538 changes: 538 additions & 0 deletions bolt/test/X86/dwarf5-empty-function-ranges.s

Large diffs are not rendered by default.

485 changes: 485 additions & 0 deletions bolt/test/X86/dwarf5-loclist-out-of-order.s

Large diffs are not rendered by default.

6 changes: 2 additions & 4 deletions bolt/test/X86/dwarf5-subprogram-single-gc-ranges.test
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,12 @@

# RUN: llvm-mc -dwarf-version=5 -filetype=obj -triple x86_64-unknown-linux %p/Inputs/dwarf5-subprogram-single-gc-ranges-main.s -o %t1.o
# RUN: %clang %cflags %t1.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections &> %t1.txt
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt >> %t1.txt
# RUN: llvm-bolt %t.exe -o %t.bolt --update-debug-sections
# RUN: llvm-dwarfdump --show-form --verbose --debug-info %t.bolt > %t1.txt
# RUN: cat %t1.txt | FileCheck --check-prefix=POSTCHECK %s

# This test checks BOLT correctly handles DW_TAG_subprogram with Ranges with single entry, when function was GCed.

# POSTCHECK: BOLT-WARNING: [internal-dwarf-error]: subprogram got GCed by the linker, DW_AT_ranges is used

# POSTCHECK: DW_TAG_subprogram
# POSTCHECK-NEXT: DW_AT_frame_base
# POSTCHECK-NEXT: DW_AT_linkage_name
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ void UnusedLocalNonTrivialVariableCheck::registerMatchers(MatchFinder *Finder) {
varDecl(isLocalVarDecl(), unless(isReferenced()),
unless(isExceptionVariable()), hasLocalStorage(), isDefinition(),
unless(hasType(isReferenceType())), unless(hasType(isTrivial())),
unless(hasAttr(attr::Kind::Unused)),
hasType(hasUnqualifiedDesugaredType(
anyOf(recordType(hasDeclaration(namedDecl(
matchesAnyListedName(IncludeTypes),
Expand Down
12 changes: 9 additions & 3 deletions clang-tools-extra/clang-tidy/modernize/UseOverrideCheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "UseOverrideCheck.h"
#include "../utils/LexerUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Lex/Lexer.h"
Expand Down Expand Up @@ -228,9 +229,14 @@ void UseOverrideCheck::check(const MatchFinder::MatchResult &Result) {
if (HasVirtual) {
for (Token Tok : Tokens) {
if (Tok.is(tok::kw_virtual)) {
Diag << FixItHint::CreateRemoval(CharSourceRange::getTokenRange(
Tok.getLocation(), Tok.getLocation()));
break;
std::optional<Token> NextToken =
utils::lexer::findNextTokenIncludingComments(
Tok.getEndLoc(), Sources, getLangOpts());
if (NextToken.has_value()) {
Diag << FixItHint::CreateRemoval(CharSourceRange::getCharRange(
Tok.getLocation(), NextToken->getLocation()));
break;
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -88,10 +88,14 @@ void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
this);

if (getLangOpts().CPlusPlus17) {
const auto IsPartOfRecordDecl = hasAncestor(recordDecl());
Finder->addMatcher(
varDecl(isInlineSpecified(),
anyOf(isInternalLinkage(StrictMode),
allOf(isConstexpr(), hasAncestor(recordDecl()))))
varDecl(
isInlineSpecified(),
anyOf(allOf(isInternalLinkage(StrictMode),
unless(allOf(hasInitializer(expr()), IsPartOfRecordDecl,
isStaticStorageClass()))),
allOf(isConstexpr(), IsPartOfRecordDecl)))
.bind("var_decl"),
this);
}
Expand Down
42 changes: 42 additions & 0 deletions clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -898,6 +898,48 @@ TEST(DiagnosticTest, ClangTidySelfContainedDiags) {
withFix(equalToFix(ExpectedDFix))))));
}

TEST(DiagnosticTest, ClangTidySelfContainedDiagsFormatting) {
Annotations Main(R"cpp(
class Interface {
public:
virtual void Reset1() = 0;
virtual void Reset2() = 0;
};
class A : public Interface {
// This will be marked by clangd to use override instead of virtual
$virtual1[[virtual ]]void $Reset1[[Reset1]]()$override1[[]];
$virtual2[[virtual ]]/**/void $Reset2[[Reset2]]()$override2[[]];
};
)cpp");
TestTU TU = TestTU::withCode(Main.code());
TU.ClangTidyProvider =
addTidyChecks("cppcoreguidelines-explicit-virtual-functions,");
clangd::Fix const ExpectedFix1{
"prefer using 'override' or (rarely) 'final' "
"instead of 'virtual'",
{TextEdit{Main.range("override1"), " override"},
TextEdit{Main.range("virtual1"), ""}},
{}};
clangd::Fix const ExpectedFix2{
"prefer using 'override' or (rarely) 'final' "
"instead of 'virtual'",
{TextEdit{Main.range("override2"), " override"},
TextEdit{Main.range("virtual2"), ""}},
{}};
// Note that in the Fix we expect the "virtual" keyword and the following
// whitespace to be deleted
EXPECT_THAT(TU.build().getDiagnostics(),
ifTidyChecks(UnorderedElementsAre(
AllOf(Diag(Main.range("Reset1"),
"prefer using 'override' or (rarely) 'final' "
"instead of 'virtual'"),
withFix(equalToFix(ExpectedFix1))),
AllOf(Diag(Main.range("Reset2"),
"prefer using 'override' or (rarely) 'final' "
"instead of 'virtual'"),
withFix(equalToFix(ExpectedFix2))))));
}

TEST(DiagnosticsTest, Preprocessor) {
// This looks like a preamble, but there's an #else in the middle!
// Check that:
Expand Down
12 changes: 12 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ Changes in existing checks
<clang-tidy/checks/bugprone/too-small-loop-variable>` check by incorporating
better support for ``const`` loop boundaries.

- Improved :doc:`bugprone-unused-local-non-trivial-variable
<clang-tidy/checks/bugprone/unused-local-non-trivial-variable>` check by
ignoring local variable with ``[maybe_unused]`` attribute.

- Cleaned up :doc:`cppcoreguidelines-prefer-member-initializer
<clang-tidy/checks/cppcoreguidelines/prefer-member-initializer>`
by removing enforcement of rule `C.48
Expand Down Expand Up @@ -160,6 +164,14 @@ Changes in existing checks
`AllowStringArrays` option, enabling the exclusion of array types with deduced
length initialized from string literals.

- Improved :doc:`modernize-use-override
<clang-tidy/checks/modernize/use-override>` check to also remove any trailing
whitespace when deleting the ``virtual`` keyword.

- Improved :doc:`readability-redundant-inline-specifier
<clang-tidy/checks/readability/redundant-inline-specifier>` check to properly
emit warnings for static data member with an in-class initializer.

Removed checks
^^^^^^^^^^^^^^

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ The following types of variables are excluded from this check:
* exception variables in catch clauses
* static or thread local
* structured bindings
* variables with ``[[maybe_unused]]`` attribute

This check can be configured to warn on all non-trivial variables by setting
`IncludeTypes` to `.*`, and excluding specific types using `ExcludeTypes`.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ T qux(T Generic) {
// CHECK-MESSAGES: :[[@LINE-1]]:22: warning: unused local variable 'TemplateType' of type 'async::Future<T>' [bugprone-unused-local-non-trivial-variable]
a::Future<T> AliasTemplateType;
// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: unused local variable 'AliasTemplateType' of type 'a::Future<T>' (aka 'Future<type-parameter-0-0>') [bugprone-unused-local-non-trivial-variable]
[[maybe_unused]] async::Future<Units> MaybeUnused;
return Generic;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ struct Base {
virtual void f() = 0;
virtual void f2() const = 0;
virtual void g() = 0;
virtual void g2() = 0;

virtual void j() const;
virtual MustUseResultObject k();
Expand Down Expand Up @@ -126,6 +127,10 @@ struct SimpleCases : public Base {
virtual void t() throw();
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: prefer using
// CHECK-FIXES: {{^}} void t() throw() override;

virtual /* */ void g2();
// CHECK-MESSAGES: :[[@LINE-1]]:33: warning: prefer using 'override' or (rarely) 'final' instead of 'virtual'
// CHECK-FIXES: {{^}} /* */ void g2() override;
};

// CHECK-MESSAGES-NOT: warning:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,17 @@ INLINE_MACRO()

#define INLINE_KW inline
INLINE_KW void fn10() { }

namespace {
class A
{
public:
static inline float test = 3.0F;
static inline double test2 = 3.0;
static inline int test3 = 3;

static inline float test4;
// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:10: warning: variable 'test4' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
// CHECK-FIXES-STRICT: static float test4;
};
}
221 changes: 113 additions & 108 deletions clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1531,114 +1531,8 @@ the configuration (without a prefix: ``Auto``).

.. _AlwaysBreakAfterReturnType:

**AlwaysBreakAfterReturnType** (``ReturnTypeBreakingStyle``) :versionbadge:`clang-format 3.8` :ref:`¶ <AlwaysBreakAfterReturnType>`
The function declaration return type breaking style to use.

Possible values:

* ``RTBS_None`` (in configuration: ``None``)
This is **deprecated**. See ``Automatic`` below.

* ``RTBS_Automatic`` (in configuration: ``Automatic``)
Break after return type based on ``PenaltyReturnTypeOnItsOwnLine``.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int f() { return 1; }
int
LongName::AnotherLongName();

* ``RTBS_ExceptShortType`` (in configuration: ``ExceptShortType``)
Same as ``Automatic`` above, except that there is no break after short
return types.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int f() { return 1; }
int LongName::
AnotherLongName();

* ``RTBS_All`` (in configuration: ``All``)
Always break after the return type.

.. code-block:: c++

class A {
int
f() {
return 0;
};
};
int
f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
Always break after the return types of top-level functions.

.. code-block:: c++

class A {
int f() { return 0; };
};
int
f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
Always break after the return type of function definitions.

.. code-block:: c++

class A {
int
f() {
return 0;
};
};
int f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
Always break after the return type of top-level definitions.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();


**AlwaysBreakAfterReturnType** (``deprecated``) :versionbadge:`clang-format 3.8` :ref:`¶ <AlwaysBreakAfterReturnType>`
This option is renamed to ``BreakAfterReturnType``.

.. _AlwaysBreakBeforeMultilineStrings:

Expand Down Expand Up @@ -2219,6 +2113,117 @@ the configuration (without a prefix: ``Auto``).
@Mock
DataLoad loader;
.. _BreakAfterReturnType:

**BreakAfterReturnType** (``ReturnTypeBreakingStyle``) :versionbadge:`clang-format 19` :ref:`¶ <BreakAfterReturnType>`
The function declaration return type breaking style to use.

Possible values:

* ``RTBS_None`` (in configuration: ``None``)
This is **deprecated**. See ``Automatic`` below.

* ``RTBS_Automatic`` (in configuration: ``Automatic``)
Break after return type based on ``PenaltyReturnTypeOnItsOwnLine``.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int f() { return 1; }
int
LongName::AnotherLongName();

* ``RTBS_ExceptShortType`` (in configuration: ``ExceptShortType``)
Same as ``Automatic`` above, except that there is no break after short
return types.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int f() { return 1; }
int LongName::
AnotherLongName();

* ``RTBS_All`` (in configuration: ``All``)
Always break after the return type.

.. code-block:: c++

class A {
int
f() {
return 0;
};
};
int
f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_TopLevel`` (in configuration: ``TopLevel``)
Always break after the return types of top-level functions.

.. code-block:: c++

class A {
int f() { return 0; };
};
int
f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_AllDefinitions`` (in configuration: ``AllDefinitions``)
Always break after the return type of function definitions.

.. code-block:: c++

class A {
int
f() {
return 0;
};
};
int f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();

* ``RTBS_TopLevelDefinitions`` (in configuration: ``TopLevelDefinitions``)
Always break after the return type of top-level definitions.

.. code-block:: c++

class A {
int f() { return 0; };
};
int f();
int
f() {
return 1;
}
int
LongName::AnotherLongName();



.. _BreakArrays:

**BreakArrays** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ <BreakArrays>`
Expand Down
33 changes: 33 additions & 0 deletions clang/docs/LanguageExtensions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,39 @@ Query for this feature with ``__has_builtin(__builtin_readcyclecounter)``. Note
that even if present, its use may depend on run-time privilege or other OS
controlled state.
``__builtin_readsteadycounter``
-------------------------------
``__builtin_readsteadycounter`` is used to access the fixed frequency counter
register (or a similar steady-rate clock) on those targets that support it.
The function is similar to ``__builtin_readcyclecounter`` above except that the
frequency is fixed, making it suitable for measuring elapsed time.
**Syntax**:
.. code-block:: c++
__builtin_readsteadycounter()
**Example of Use**:
.. code-block:: c++
unsigned long long t0 = __builtin_readsteadycounter();
do_something();
unsigned long long t1 = __builtin_readsteadycounter();
unsigned long long secs_to_do_something = (t1 - t0) / tick_rate;
**Description**:
The ``__builtin_readsteadycounter()`` builtin returns the frequency counter value.
When not supported by the target, the return value is always zero. This builtin
takes no arguments and produces an unsigned long long result. The builtin does
not guarantee any particular frequency, only that it is stable. Knowledge of the
counter's true frequency will need to be provided by the user.
Query for this feature with ``__has_builtin(__builtin_readsteadycounter)``.
``__builtin_dump_struct``
-------------------------
Expand Down
25 changes: 25 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,12 @@ Clang Frontend Potentially Breaking Changes
``ArrayRef<TemplateArgument>`` reduces AST memory usage by 0.4% when compiling clang, and is
expected to show similar improvements on other workloads.

- The ``-Wgnu-binary-literal`` diagnostic group no longer controls any
diagnostics. Binary literals are no longer a GNU extension, they're now a C23
extension which is controlled via ``-pedantic`` or ``-Wc23-extensions``. Use
of ``-Wno-gnu-binary-literal`` will no longer silence this pedantic warning,
which may break existing uses with ``-Werror``.

Target OS macros extension
^^^^^^^^^^^^^^^^^^^^^^^^^^
A new Clang extension (see :ref:`here <target_os_detail>`) is enabled for
Expand Down Expand Up @@ -113,10 +119,15 @@ C Language Changes

C23 Feature Support
^^^^^^^^^^^^^^^^^^^
- No longer diagnose use of binary literals as an extension in C23 mode. Fixes
`#72017 <https://github.com/llvm/llvm-project/issues/72017>`_.

Non-comprehensive list of changes in this release
-------------------------------------------------

- Added ``__builtin_readsteadycounter`` for reading fixed frequency hardware
counters.

New Compiler Flags
------------------

Expand Down Expand Up @@ -156,6 +167,8 @@ Improvements to Clang's diagnostics
- The ``-Wshorten-64-to-32`` diagnostic is now grouped under ``-Wimplicit-int-conversion`` instead
of ``-Wconversion``. Fixes `#69444 <https://github.com/llvm/llvm-project/issues/69444>`_.

- Clang now diagnoses friend declarations with an ``enum`` elaborated-type-specifier in language modes after C++98.

Improvements to Clang's time-trace
----------------------------------

Expand Down Expand Up @@ -228,6 +241,8 @@ Bug Fixes to C++ Support
or non-constant more accurately. Previously, only a subset of the initializer
elements were considered, misclassifying some initializers as constant. Fixes
some of (`#80510 <https://github.com/llvm/llvm-project/issues/80510>`).
- Clang now ignores top-level cv-qualifiers on function parameters in template partial orderings.
(`#75404 <https://github.com/llvm/llvm-project/issues/75404>`_)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand All @@ -253,6 +268,8 @@ X86 Support
Arm and AArch64 Support
^^^^^^^^^^^^^^^^^^^^^^^

- Fixed the incorrect definition of the __ARM_ARCH macro for architectures greater than or equal to v8.1.

Android Support
^^^^^^^^^^^^^^^

Expand Down Expand Up @@ -288,6 +305,12 @@ DWARF Support in Clang
Floating Point Support in Clang
-------------------------------

Fixed Point Support in Clang
----------------------------

- Support fixed point precision macros according to ``7.18a.3`` of
`ISO/IEC TR 18037:2008 <https://standards.iso.org/ittf/PubliclyAvailableStandards/c051126_ISO_IEC_TR_18037_2008.zip>`_.

AST Matchers
------------

Expand All @@ -296,6 +319,8 @@ clang-format

- ``AlwaysBreakTemplateDeclarations`` is deprecated and renamed to
``BreakTemplateDeclarations``.
- ``AlwaysBreakAfterReturnType`` is deprecated and renamed to
``BreakAfterReturnType``.

libclang
--------
Expand Down
6 changes: 5 additions & 1 deletion clang/include/clang-c/Index.h
Original file line number Diff line number Diff line change
Expand Up @@ -2145,7 +2145,11 @@ enum CXCursorKind {
*/
CXCursor_OMPScopeDirective = 306,

CXCursor_LastStmt = CXCursor_OMPScopeDirective,
/** OpenACC Compute Construct.
*/
CXCursor_OpenACCComputeConstruct = 320,

CXCursor_LastStmt = CXCursor_OpenACCComputeConstruct,

/**
* Cursor that represents the translation unit itself.
Expand Down
22 changes: 22 additions & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
Expand Down Expand Up @@ -505,6 +506,9 @@ template <typename Derived> class RecursiveASTVisitor {
bool VisitOMPClauseWithPostUpdate(OMPClauseWithPostUpdate *Node);

bool PostVisitStmt(Stmt *S);
bool TraverseOpenACCConstructStmt(OpenACCConstructStmt *S);
bool
TraverseOpenACCAssociatedStmtConstruct(OpenACCAssociatedStmtConstruct *S);
};

template <typename Derived>
Expand Down Expand Up @@ -3910,6 +3914,24 @@ bool RecursiveASTVisitor<Derived>::VisitOMPXBareClause(OMPXBareClause *C) {
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOpenACCConstructStmt(
OpenACCConstructStmt *) {
// TODO OpenACC: When we implement clauses, ensure we traverse them here.
return true;
}

template <typename Derived>
bool RecursiveASTVisitor<Derived>::TraverseOpenACCAssociatedStmtConstruct(
OpenACCAssociatedStmtConstruct *S) {
TRY_TO(TraverseOpenACCConstructStmt(S));
TRY_TO(TraverseStmt(S->getAssociatedStmt()));
return true;
}

DEF_TRAVERSE_STMT(OpenACCComputeConstruct,
{ TRY_TO(TraverseOpenACCAssociatedStmtConstruct(S)); })

// FIXME: look at the following tricky-seeming exprs to see if we
// need to recurse on anything. These are ones that have methods
// returning decls or qualtypes or nestednamespecifier -- though I'm
Expand Down
142 changes: 142 additions & 0 deletions clang/include/clang/AST/StmtOpenACC.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
//===- StmtOpenACC.h - Classes for OpenACC directives ----------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
/// \file
/// This file defines OpenACC AST classes for statement-level contructs.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_AST_STMTOPENACC_H
#define LLVM_CLANG_AST_STMTOPENACC_H

#include "clang/AST/Stmt.h"
#include "clang/Basic/OpenACCKinds.h"
#include "clang/Basic/SourceLocation.h"

namespace clang {
/// This is the base class for an OpenACC statement-level construct, other
/// construct types are expected to inherit from this.
class OpenACCConstructStmt : public Stmt {
friend class ASTStmtWriter;
friend class ASTStmtReader;
/// The directive kind. Each implementation of this interface should handle
/// specific kinds.
OpenACCDirectiveKind Kind = OpenACCDirectiveKind::Invalid;
/// The location of the directive statement, from the '#' to the last token of
/// the directive.
SourceRange Range;

// TODO OPENACC: Clauses should probably be collected in this class.

protected:
OpenACCConstructStmt(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start, SourceLocation End)
: Stmt(SC), Kind(K), Range(Start, End) {}

public:
OpenACCDirectiveKind getDirectiveKind() const { return Kind; }

static bool classof(const Stmt *S) {
return S->getStmtClass() >= firstOpenACCConstructStmtConstant &&
S->getStmtClass() <= lastOpenACCConstructStmtConstant;
}

SourceLocation getBeginLoc() const { return Range.getBegin(); }
SourceLocation getEndLoc() const { return Range.getEnd(); }

child_range children() {
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
return const_cast<OpenACCConstructStmt *>(this)->children();
}
};

/// This is a base class for any OpenACC statement-level constructs that have an
/// associated statement. This class is not intended to be instantiated, but is
/// a convenient place to hold the associated statement.
class OpenACCAssociatedStmtConstruct : public OpenACCConstructStmt {
friend class ASTStmtWriter;
friend class ASTStmtReader;
template <typename Derived> friend class RecursiveASTVisitor;
Stmt *AssociatedStmt = nullptr;

protected:
OpenACCAssociatedStmtConstruct(StmtClass SC, OpenACCDirectiveKind K,
SourceLocation Start, SourceLocation End)
: OpenACCConstructStmt(SC, K, Start, End) {}

void setAssociatedStmt(Stmt *S) { AssociatedStmt = S; }
Stmt *getAssociatedStmt() { return AssociatedStmt; }
const Stmt *getAssociatedStmt() const {
return const_cast<OpenACCAssociatedStmtConstruct *>(this)
->getAssociatedStmt();
}

public:
child_range children() {
if (getAssociatedStmt())
return child_range(&AssociatedStmt, &AssociatedStmt + 1);
return child_range(child_iterator(), child_iterator());
}

const_child_range children() const {
return const_cast<OpenACCAssociatedStmtConstruct *>(this)->children();
}
};
/// This class represents a compute construct, representing a 'Kind' of
/// `parallel', 'serial', or 'kernel'. These constructs are associated with a
/// 'structured block', defined as:
///
/// in C or C++, an executable statement, possibly compound, with a single
/// entry at the top and a single exit at the bottom
///
/// At the moment there is no real motivation to have a different AST node for
/// those three, as they are semantically identical, and have only minor
/// differences in the permitted list of clauses, which can be differentiated by
/// the 'Kind'.
class OpenACCComputeConstruct : public OpenACCAssociatedStmtConstruct {
friend class ASTStmtWriter;
friend class ASTStmtReader;
friend class ASTContext;
OpenACCComputeConstruct()
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass,
OpenACCDirectiveKind::Invalid,
SourceLocation{}, SourceLocation{}) {}

OpenACCComputeConstruct(OpenACCDirectiveKind K, SourceLocation Start,
SourceLocation End)
: OpenACCAssociatedStmtConstruct(OpenACCComputeConstructClass, K, Start,
End) {
assert((K == OpenACCDirectiveKind::Parallel ||
K == OpenACCDirectiveKind::Serial ||
K == OpenACCDirectiveKind::Kernels) &&
"Only parallel, serial, and kernels constructs should be "
"represented by this type");
}

void setStructuredBlock(Stmt *S) { setAssociatedStmt(S); }

public:
static bool classof(const Stmt *T) {
return T->getStmtClass() == OpenACCComputeConstructClass;
}

static OpenACCComputeConstruct *CreateEmpty(const ASTContext &C, EmptyShell);
static OpenACCComputeConstruct *Create(const ASTContext &C,
OpenACCDirectiveKind K,
SourceLocation BeginLoc,
SourceLocation EndLoc);

Stmt *getStructuredBlock() { return getAssociatedStmt(); }
const Stmt *getStructuredBlock() const {
return const_cast<OpenACCComputeConstruct *>(this)->getStructuredBlock();
}
};
} // namespace clang
#endif // LLVM_CLANG_AST_STMTOPENACC_H
3 changes: 2 additions & 1 deletion clang/include/clang/AST/StmtVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,14 @@
#ifndef LLVM_CLANG_AST_STMTVISITOR_H
#define LLVM_CLANG_AST_STMTVISITOR_H

#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprCXX.h"
#include "clang/AST/ExprConcepts.h"
#include "clang/AST/ExprObjC.h"
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/Stmt.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/Basic/LLVM.h"
#include "llvm/ADT/STLExtras.h"
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/TextNodeDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,7 @@ class TextNodeDumper
void
VisitLifetimeExtendedTemporaryDecl(const LifetimeExtendedTemporaryDecl *D);
void VisitHLSLBufferDecl(const HLSLBufferDecl *D);
void VisitOpenACCConstructStmt(const OpenACCConstructStmt *S);
};

} // namespace clang
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ FIXABLE_GADGET(UPCAddressofArraySubscript) // '&DRE[any]' in an Unspecified Poin
FIXABLE_GADGET(UPCStandalonePointer)
FIXABLE_GADGET(UPCPreIncrement) // '++Ptr' in an Unspecified Pointer Context
FIXABLE_GADGET(UUCAddAssign) // 'Ptr += n' in an Unspecified Untyped Context
FIXABLE_GADGET(PointerAssignment)
FIXABLE_GADGET(PtrToPtrAssignment)
FIXABLE_GADGET(CArrayToPtrAssignment)
FIXABLE_GADGET(PointerInit)

#undef FIXABLE_GADGET
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ class DataflowAnalysisContext {
/// to add to a `RecordStorageLocation` of a given type.
/// Typically, this is called from the constructor of a `DataflowAnalysis`
///
/// The field types returned by the callback may not have reference type.
///
/// To maintain the invariant that all `RecordStorageLocation`s of a given
/// type have the same fields:
/// * The callback must always return the same result for a given type
Expand Down Expand Up @@ -205,8 +207,17 @@ class DataflowAnalysisContext {
/// type.
llvm::StringMap<QualType> getSyntheticFields(QualType Type) {
assert(Type->isRecordType());
if (SyntheticFieldCallback)
return SyntheticFieldCallback(Type);
if (SyntheticFieldCallback) {
llvm::StringMap<QualType> Result = SyntheticFieldCallback(Type);
// Synthetic fields are not allowed to have reference type.
assert([&Result] {
for (const auto &Entry : Result)
if (Entry.getValue()->isReferenceType())
return false;
return true;
}());
return Result;
}
return {};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,14 @@ class Environment {
llvm::DenseSet<QualType> &Visited,
int Depth, int &CreatedValuesCount);

/// Initializes the fields (including synthetic fields) of `Loc` with values,
/// unless values of the field type are not supported or we hit one of the
/// limits at which we stop producing values (controlled by `Visited`,
/// `Depth`, and `CreatedValuesCount`).
void initializeFieldsWithValues(RecordStorageLocation &Loc,
llvm::DenseSet<QualType> &Visited, int Depth,
int &CreatedValuesCount);

/// Shared implementation of `createObject()` overloads.
/// `D` and `InitExpr` may be null.
StorageLocation &createObjectInternal(const ValueDecl *D, QualType Ty,
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -2891,6 +2891,13 @@ def Suppress : DeclOrStmtAttr {
let Spellings = [CXX11<"gsl", "suppress">, Clang<"suppress">];
let Args = [VariadicStringArgument<"DiagnosticIdentifiers">];
let Accessors = [Accessor<"isGSL", [CXX11<"gsl", "suppress">]>];
// There's no fundamental reason why we can't simply accept all Decls
// but let's make a short list so that to avoid supporting something weird
// by accident. We can always expand the list later.
let Subjects = SubjectList<[
Stmt, Var, Field, ObjCProperty, Function, ObjCMethod, Record, ObjCInterface,
ObjCImplementation, Namespace, Empty
], ErrorDiag, "variables, functions, structs, interfaces, and namespaces">;
let Documentation = [SuppressDocs];
}

Expand Down
23 changes: 23 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -5321,6 +5321,29 @@ Putting the attribute on a compound statement suppresses all warnings in scope:
}
}

The attribute can also be placed on entire declarations of functions, classes,
variables, member variables, and so on, to suppress warnings related
to the declarations themselves. When used this way, the attribute additionally
suppresses all warnings in the lexical scope of the declaration:

.. code-block:: c++

class [[clang::suppress]] C {
int foo() {
int *x = nullptr;
...
return *x; // warnings suppressed in the entire class scope
}

int bar();
};

int C::bar() {
int *x = nullptr;
...
return *x; // warning NOT suppressed! - not lexically nested in 'class C{}'
}

Some static analysis warnings are accompanied by one or more notes, and the
line of code against which the warning is emitted isn't necessarily the best
for suppression purposes. In such cases the tools are allowed to implement
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,12 @@ def ReadCycleCounter : Builtin {
let Prototype = "unsigned long long int()";
}

def ReadSteadyCounter : Builtin {
let Spellings = ["__builtin_readsteadycounter"];
let Attributes = [NoThrow];
let Prototype = "unsigned long long int()";
}

def Trap : Builtin {
let Spellings = ["__builtin_trap"];
let Attributes = [NoThrow, NoReturn];
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticDriverKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -804,4 +804,7 @@ def warn_android_unversioned_fallback : Warning<

def err_drv_triple_version_invalid : Error<
"version '%0' in target triple '%1' is invalid">;

def err_drv_installapi_unsupported : Error<
"InstallAPI is not supported for '%0'">;
}
11 changes: 6 additions & 5 deletions clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,8 @@ def DeprecatedModuleDotMap : DiagGroup<"deprecated-module-dot-map">;
def FrameworkHdrAtImport : DiagGroup<"atimport-in-framework-header">;
def CXX14BinaryLiteral : DiagGroup<"c++14-binary-literal">;
def CXXPre14CompatBinaryLiteral : DiagGroup<"c++98-c++11-compat-binary-literal">;
def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;
def BinaryLiteral : DiagGroup<"binary-literal", [CXX14BinaryLiteral,
CXXPre14CompatBinaryLiteral,
GNUBinaryLiteral]>;
CXXPre14CompatBinaryLiteral]>;
def GNUCompoundLiteralInitializer : DiagGroup<"gnu-compound-literal-initializer">;
def SingleBitBitFieldConstantConversion :
DiagGroup<"single-bit-bitfield-constant-conversion">;
Expand Down Expand Up @@ -1176,10 +1174,13 @@ def C23 : DiagGroup<"c23-extensions">;

def : DiagGroup<"c2x-extensions", [C23]>;

// Previously supported warning group which is no longer pertinent as binary
// literals are a C++14 and C23 extension now instead of a GNU extension.
def GNUBinaryLiteral : DiagGroup<"gnu-binary-literal">;

// A warning group for warnings about GCC extensions.
def GNU : DiagGroup<"gnu", [GNUAlignofExpression, GNUAnonymousStruct,
GNUAutoType,
GNUBinaryLiteral, GNUCaseRange,
GNUAutoType, GNUBinaryLiteral, GNUCaseRange,
GNUComplexInteger, GNUCompoundLiteralInitializer,
GNUConditionalOmittedOperand, GNUDesignator,
GNUEmptyStruct,
Expand Down
5 changes: 4 additions & 1 deletion clang/include/clang/Basic/DiagnosticLexKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,10 @@ def warn_cxx17_hex_literal : Warning<
"C++ standards before C++17">,
InGroup<CXXPre17CompatPedantic>, DefaultIgnore;
def ext_binary_literal : Extension<
"binary integer literals are a GNU extension">, InGroup<GNUBinaryLiteral>;
"binary integer literals are a C23 extension">, InGroup<C23>;
def warn_c23_compat_binary_literal : Warning<
"binary integer literals are incompatible with C standards before C23">,
InGroup<CPre23Compat>, DefaultIgnore;
def ext_binary_literal_cxx14 : Extension<
"binary integer literals are a C++14 extension">, InGroup<CXX14BinaryLiteral>;
def warn_cxx11_compat_binary_literal : Warning<
Expand Down
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1637,10 +1637,10 @@ def err_inline_namespace_std : Error<
def err_unexpected_friend : Error<
"friends can only be classes or functions">;
def ext_enum_friend : ExtWarn<
"befriending enumeration type %0 is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_enum_friend : Warning<
"befriending enumeration type %0 is incompatible with C++98">,
InGroup<CXX98Compat>, DefaultIgnore;
"elaborated enum specifier cannot be declared as a friend">,
InGroup<DiagGroup<"friend-enum">>;
def note_enum_friend : Note<
"remove 'enum%select{| struct| class}0' to befriend an enum">;
def ext_nonclass_type_friend : ExtWarn<
"non-class friend type %0 is a C++11 extension">, InGroup<CXX11>;
def warn_cxx98_compat_nonclass_type_friend : Warning<
Expand Down
4 changes: 2 additions & 2 deletions clang/include/clang/Basic/FileManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -283,15 +283,15 @@ class FileManager : public RefCountedBase<FileManager> {
bool RequiresNullTerminator = true);
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFile(StringRef Filename, bool isVolatile = false,
bool RequiresNullTerminator = true) {
bool RequiresNullTerminator = true) const {
return getBufferForFileImpl(Filename, /*FileSize=*/-1, isVolatile,
RequiresNullTerminator);
}

private:
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBufferForFileImpl(StringRef Filename, int64_t FileSize, bool isVolatile,
bool RequiresNullTerminator);
bool RequiresNullTerminator) const;

public:
/// Get the 'stat' information for the given \p Path.
Expand Down
104 changes: 48 additions & 56 deletions clang/include/clang/Basic/IdentifierTable.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,28 +84,28 @@ using IdentifierLocPair = std::pair<IdentifierInfo *, SourceLocation>;
/// of a pointer to one of these classes.
enum { IdentifierInfoAlignment = 8 };

static constexpr int ObjCOrBuiltinIDBits = 16;
static constexpr int InterestingIdentifierBits = 16;

/// The "layout" of ObjCOrBuiltinID is:
/// The "layout" of InterestingIdentifier is:
/// - ObjCKeywordKind enumerators
/// - InterestingIdentifierKind enumerators
/// - NotableIdentifierKind enumerators
/// - Builtin::ID enumerators
/// - NonSpecialIdentifier
enum class ObjCKeywordOrInterestingOrBuiltin {
/// - NotInterestingIdentifier
enum class InterestingIdentifier {
#define OBJC_AT_KEYWORD(X) objc_##X,
#include "clang/Basic/TokenKinds.def"
NUM_OBJC_KEYWORDS,

#define INTERESTING_IDENTIFIER(X) X,
#define NOTABLE_IDENTIFIER(X) X,
#include "clang/Basic/TokenKinds.def"
NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS,
NUM_OBJC_KEYWORDS_AND_NOTABLE_IDENTIFIERS,

NotBuiltin,
#define BUILTIN(ID, TYPE, ATTRS) BI##ID,
#include "clang/Basic/Builtins.inc"
FirstTSBuiltin,

NonSpecialIdentifier = 65534
NotInterestingIdentifier = 65534
};

/// One of these records is kept for each identifier that
Expand All @@ -121,8 +121,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
LLVM_PREFERRED_TYPE(tok::TokenKind)
unsigned TokenID : 9;

LLVM_PREFERRED_TYPE(ObjCKeywordOrInterestingOrBuiltin)
unsigned ObjCOrBuiltinID : ObjCOrBuiltinIDBits;
LLVM_PREFERRED_TYPE(InterestingIdentifier)
unsigned InterestingIdentifierID : InterestingIdentifierBits;

// True if there is a #define for this.
LLVM_PREFERRED_TYPE(bool)
Expand Down Expand Up @@ -205,8 +205,8 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {

IdentifierInfo()
: TokenID(tok::identifier),
ObjCOrBuiltinID(llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier)),
InterestingIdentifierID(llvm::to_underlying(
InterestingIdentifier::NotInterestingIdentifier)),
HasMacro(false), HadMacro(false), IsExtension(false),
IsFutureCompatKeyword(false), IsPoisoned(false),
IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false),
Expand Down Expand Up @@ -341,71 +341,63 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo {
///
/// For example, 'class' will return tok::objc_class if ObjC is enabled.
tok::ObjCKeywordKind getObjCKeywordID() const {
assert(0 == llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::objc_not_keyword));
auto Value =
static_cast<ObjCKeywordOrInterestingOrBuiltin>(ObjCOrBuiltinID);
if (Value < ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS)
return static_cast<tok::ObjCKeywordKind>(ObjCOrBuiltinID);
assert(0 == llvm::to_underlying(InterestingIdentifier::objc_not_keyword));
auto Value = static_cast<InterestingIdentifier>(InterestingIdentifierID);
if (Value < InterestingIdentifier::NUM_OBJC_KEYWORDS)
return static_cast<tok::ObjCKeywordKind>(InterestingIdentifierID);
return tok::objc_not_keyword;
}
void setObjCKeywordID(tok::ObjCKeywordKind ID) {
assert(0 == llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::objc_not_keyword));
ObjCOrBuiltinID = ID;
assert(0 == llvm::to_underlying(InterestingIdentifier::objc_not_keyword));
InterestingIdentifierID = ID;
assert(getObjCKeywordID() == ID && "ID too large for field!");
}

/// Return a value indicating whether this is a builtin function.
unsigned getBuiltinID() const {
auto Value =
static_cast<ObjCKeywordOrInterestingOrBuiltin>(ObjCOrBuiltinID);
if (Value > ObjCKeywordOrInterestingOrBuiltin::
NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS &&
Value != ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier) {
auto Value = static_cast<InterestingIdentifier>(InterestingIdentifierID);
if (Value >
InterestingIdentifier::NUM_OBJC_KEYWORDS_AND_NOTABLE_IDENTIFIERS &&
Value != InterestingIdentifier::NotInterestingIdentifier) {
auto FirstBuiltin =
llvm::to_underlying(ObjCKeywordOrInterestingOrBuiltin::NotBuiltin);
return static_cast<Builtin::ID>(ObjCOrBuiltinID - FirstBuiltin);
llvm::to_underlying(InterestingIdentifier::NotBuiltin);
return static_cast<Builtin::ID>(InterestingIdentifierID - FirstBuiltin);
}
return Builtin::ID::NotBuiltin;
}
void setBuiltinID(unsigned ID) {
assert(ID != Builtin::ID::NotBuiltin);
auto FirstBuiltin =
llvm::to_underlying(ObjCKeywordOrInterestingOrBuiltin::NotBuiltin);
ObjCOrBuiltinID = ID + FirstBuiltin;
auto FirstBuiltin = llvm::to_underlying(InterestingIdentifier::NotBuiltin);
InterestingIdentifierID = ID + FirstBuiltin;
assert(getBuiltinID() == ID && "ID too large for field!");
}
void clearBuiltinID() {
ObjCOrBuiltinID = llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier);
}

tok::InterestingIdentifierKind getInterestingIdentifierID() const {
auto Value =
static_cast<ObjCKeywordOrInterestingOrBuiltin>(ObjCOrBuiltinID);
if (Value > ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS &&
Value < ObjCKeywordOrInterestingOrBuiltin::
NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS) {
auto FirstInterestingIdentifier =
1 + llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS);
return static_cast<tok::InterestingIdentifierKind>(
ObjCOrBuiltinID - FirstInterestingIdentifier);
InterestingIdentifierID =
llvm::to_underlying(InterestingIdentifier::NotInterestingIdentifier);
}

tok::NotableIdentifierKind getNotableIdentifierID() const {
auto Value = static_cast<InterestingIdentifier>(InterestingIdentifierID);
if (Value > InterestingIdentifier::NUM_OBJC_KEYWORDS &&
Value <
InterestingIdentifier::NUM_OBJC_KEYWORDS_AND_NOTABLE_IDENTIFIERS) {
auto FirstNotableIdentifier =
1 + llvm::to_underlying(InterestingIdentifier::NUM_OBJC_KEYWORDS);
return static_cast<tok::NotableIdentifierKind>(InterestingIdentifierID -
FirstNotableIdentifier);
}
return tok::not_interesting;
return tok::not_notable;
}
void setInterestingIdentifierID(unsigned ID) {
assert(ID != tok::not_interesting);
auto FirstInterestingIdentifier =
1 + llvm::to_underlying(
ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS);
ObjCOrBuiltinID = ID + FirstInterestingIdentifier;
assert(getInterestingIdentifierID() == ID && "ID too large for field!");
void setNotableIdentifierID(unsigned ID) {
assert(ID != tok::not_notable);
auto FirstNotableIdentifier =
1 + llvm::to_underlying(InterestingIdentifier::NUM_OBJC_KEYWORDS);
InterestingIdentifierID = ID + FirstNotableIdentifier;
assert(getNotableIdentifierID() == ID && "ID too large for field!");
}

unsigned getObjCOrBuiltinID() const { return ObjCOrBuiltinID; }
void setObjCOrBuiltinID(unsigned ID) { ObjCOrBuiltinID = ID; }
unsigned getObjCOrBuiltinID() const { return InterestingIdentifierID; }
void setObjCOrBuiltinID(unsigned ID) { InterestingIdentifierID = ID; }

/// get/setExtension - Initialize information about whether or not this
/// language token is an extension. This controls extension warnings, and is
Expand Down
31 changes: 27 additions & 4 deletions clang/include/clang/Basic/OpenACCKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

#include "clang/Basic/Diagnostic.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"

namespace clang {
// Represents the Construct/Directive kind of a pragma directive. Note the
Expand Down Expand Up @@ -65,8 +66,9 @@ enum class OpenACCDirectiveKind {
Invalid,
};

inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
OpenACCDirectiveKind K) {
template <typename StreamTy>
inline StreamTy &PrintOpenACCDirectiveKind(StreamTy &Out,
OpenACCDirectiveKind K) {
switch (K) {
case OpenACCDirectiveKind::Parallel:
return Out << "parallel";
Expand Down Expand Up @@ -134,6 +136,16 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
llvm_unreachable("Uncovered directive kind");
}

inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
OpenACCDirectiveKind K) {
return PrintOpenACCDirectiveKind(Out, K);
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
OpenACCDirectiveKind K) {
return PrintOpenACCDirectiveKind(Out, K);
}

enum class OpenACCAtomicKind {
Read,
Write,
Expand Down Expand Up @@ -253,8 +265,8 @@ enum class OpenACCClauseKind {
Invalid,
};

inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
OpenACCClauseKind K) {
template <typename StreamTy>
inline StreamTy &PrintOpenACCClauseKind(StreamTy &Out, OpenACCClauseKind K) {
switch (K) {
case OpenACCClauseKind::Finalize:
return Out << "finalize";
Expand Down Expand Up @@ -387,6 +399,17 @@ inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
}
llvm_unreachable("Uncovered clause kind");
}

inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
OpenACCClauseKind K) {
return PrintOpenACCClauseKind(Out, K);
}

inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
OpenACCClauseKind K) {
return PrintOpenACCClauseKind(Out, K);
}

enum class OpenACCDefaultClauseKind {
/// 'none' option.
None,
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/StmtNodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -296,3 +296,9 @@ def OMPTargetTeamsGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPTargetParallelGenericLoopDirective : StmtNode<OMPLoopDirective>;
def OMPErrorDirective : StmtNode<OMPExecutableDirective>;

// OpenACC Constructs.
def OpenACCConstructStmt : StmtNode<Stmt, /*abstract=*/1>;
def OpenACCAssociatedStmtConstruct
: StmtNode<OpenACCConstructStmt, /*abstract=*/1>;
def OpenACCComputeConstruct : StmtNode<OpenACCAssociatedStmtConstruct>;
22 changes: 11 additions & 11 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,8 @@
#ifndef PRAGMA_ANNOTATION
#define PRAGMA_ANNOTATION(X) ANNOTATION(X)
#endif
#ifndef INTERESTING_IDENTIFIER
#define INTERESTING_IDENTIFIER(X)
#ifndef NOTABLE_IDENTIFIER
#define NOTABLE_IDENTIFIER(X)
#endif

//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -808,15 +808,15 @@ OBJC_AT_KEYWORD(import)
OBJC_AT_KEYWORD(available)

//===----------------------------------------------------------------------===//
// Interesting identifiers.
// Notable identifiers.
//===----------------------------------------------------------------------===//
INTERESTING_IDENTIFIER(not_interesting)
INTERESTING_IDENTIFIER(FILE)
INTERESTING_IDENTIFIER(jmp_buf)
INTERESTING_IDENTIFIER(sigjmp_buf)
INTERESTING_IDENTIFIER(ucontext_t)
INTERESTING_IDENTIFIER(float_t)
INTERESTING_IDENTIFIER(double_t)
NOTABLE_IDENTIFIER(not_notable)
NOTABLE_IDENTIFIER(FILE)
NOTABLE_IDENTIFIER(jmp_buf)
NOTABLE_IDENTIFIER(sigjmp_buf)
NOTABLE_IDENTIFIER(ucontext_t)
NOTABLE_IDENTIFIER(float_t)
NOTABLE_IDENTIFIER(double_t)

// TODO: What to do about context-sensitive keywords like:
// bycopy/byref/in/inout/oneway/out?
Expand Down Expand Up @@ -1011,4 +1011,4 @@ ANNOTATION(repl_input_end)
#undef TOK
#undef C99_KEYWORD
#undef C23_KEYWORD
#undef INTERESTING_IDENTIFIER
#undef NOTABLE_IDENTIFIER
8 changes: 4 additions & 4 deletions clang/include/clang/Basic/TokenKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,12 +44,12 @@ enum ObjCKeywordKind {
NUM_OBJC_KEYWORDS
};

/// Provides a namespace for interesting identifers such as float_t and
/// Provides a namespace for notable identifers such as float_t and
/// double_t.
enum InterestingIdentifierKind {
#define INTERESTING_IDENTIFIER(X) X,
enum NotableIdentifierKind {
#define NOTABLE_IDENTIFIER(X) X,
#include "clang/Basic/TokenKinds.def"
NUM_INTERESTING_IDENTIFIERS
NUM_NOTABLE_IDENTIFIERS
};

/// Defines the possible values of an on-off-switch (C99 6.10.6p2).
Expand Down
12 changes: 12 additions & 0 deletions clang/include/clang/Driver/Action.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ class Action {
PreprocessJobClass,
PrecompileJobClass,
ExtractAPIJobClass,
InstallAPIJobClass,
AnalyzeJobClass,
MigrateJobClass,
CompileJobClass,
Expand Down Expand Up @@ -448,6 +449,17 @@ class ExtractAPIJobAction : public JobAction {
void addHeaderInput(Action *Input) { getInputs().push_back(Input); }
};

class InstallAPIJobAction : public JobAction {
void anchor() override;

public:
InstallAPIJobAction(Action *Input, types::ID OutputType);

static bool classof(const Action *A) {
return A->getKind() == InstallAPIJobClass;
}
};

class AnalyzeJobAction : public JobAction {
void anchor() override;

Expand Down
24 changes: 16 additions & 8 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,8 @@ class AnalyzerOpts<string base>
: KeyPathAndMacro<"AnalyzerOpts->", base, "ANALYZER_"> {}
class MigratorOpts<string base>
: KeyPathAndMacro<"MigratorOpts.", base, "MIGRATOR_"> {}
class InstallAPIOpts<string base>
: KeyPathAndMacro<"InstallAPIOpts.", base, "INSTALLAPI_"> {}

// A boolean option which is opt-in in CC1. The positive option exists in CC1 and
// Args.hasArg(OPT_ffoo) can be used to check that the flag is enabled.
Expand Down Expand Up @@ -1114,7 +1116,8 @@ def config_user_dir_EQ : Joined<["--"], "config-user-dir=">,
def coverage : Flag<["-", "--"], "coverage">, Group<Link_Group>,
Visibility<[ClangOption, CLOption]>;
def cpp_precomp : Flag<["-"], "cpp-precomp">, Group<clang_ignored_f_Group>;
def current__version : JoinedOrSeparate<["-"], "current_version">;
def current__version : JoinedOrSeparate<["-"], "current_version">,
Visibility<[ClangOption, CC1Option]>;
def cxx_isystem : JoinedOrSeparate<["-"], "cxx-isystem">, Group<clang_i_Group>,
HelpText<"Add directory to the C++ SYSTEM include search path">,
Visibility<[ClangOption, CC1Option]>,
Expand Down Expand Up @@ -1529,6 +1532,9 @@ def static_libsan : Flag<["-"], "static-libsan">,
HelpText<"Statically link the sanitizer runtime (Not supported for ASan, TSan or UBSan on darwin)">;
def : Flag<["-"], "shared-libasan">, Alias<shared_libsan>;
def fasm : Flag<["-"], "fasm">, Group<f_Group>;
def installapi : Flag<["-"], "installapi">,
Visibility<[ClangOption, CC1Option]>, Group<Action_Group>,
HelpText<"Create a text-based stub file by scanning header files">;

defm assume_unique_vtables : BoolFOption<"assume-unique-vtables",
CodeGenOpts<"AssumeUniqueVTables">, DefaultTrue,
Expand Down Expand Up @@ -3198,10 +3204,10 @@ def fno_experimental_isel : Flag<["-"], "fno-experimental-isel">, Group<f_clang_
def fveclib : Joined<["-"], "fveclib=">, Group<f_Group>,
Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Use the given vector functions library">,
Values<"Accelerate,libmvec,MASSV,SVML,SLEEF,Darwin_libsystem_m,ArmPL,none">,
Values<"Accelerate,libmvec,MASSV,SVML,SLEEF,Darwin_libsystem_m,ArmPL,AMDLIBM,none">,
NormalizedValuesScope<"llvm::driver::VectorLibrary">,
NormalizedValues<["Accelerate", "LIBMVEC", "MASSV", "SVML", "SLEEF",
"Darwin_libsystem_m", "ArmPL", "NoLibrary"]>,
"Darwin_libsystem_m", "ArmPL", "AMDLIBM", "NoLibrary"]>,
MarshallingInfoEnum<CodeGenOpts<"VecLib">, "NoLibrary">;
def fno_lax_vector_conversions : Flag<["-"], "fno-lax-vector-conversions">, Group<f_Group>,
Alias<flax_vector_conversions_EQ>, AliasArgs<["none"]>;
Expand Down Expand Up @@ -4291,7 +4297,9 @@ def verify_pch : Flag<["-"], "verify-pch">, Group<Action_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Load and verify that a pre-compiled header file is not stale">;
def init : Separate<["-"], "init">;
def install__name : Separate<["-"], "install_name">;
def install__name : Separate<["-"], "install_name">,
Visibility<[ClangOption, CC1Option]>,
MarshallingInfoString<InstallAPIOpts<"InstallName">>;
def iprefix : JoinedOrSeparate<["-"], "iprefix">, Group<clang_i_Group>,
Visibility<[ClangOption, CC1Option]>,
HelpText<"Set the -iwithprefix/-iwithprefixbefore prefix">, MetaVarName<"<dir>">;
Expand Down Expand Up @@ -4414,7 +4422,7 @@ def mwatchsimulator_version_min_EQ : Joined<["-"], "mwatchsimulator-version-min=
def march_EQ : Joined<["-"], "march=">, Group<m_Group>,
Flags<[TargetSpecific]>, Visibility<[ClangOption, CLOption, DXCOption, FlangOption]>,
HelpText<"For a list of available architectures for the target use '-mcpu=help'">;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>;
def masm_EQ : Joined<["-"], "masm=">, Group<m_Group>, Visibility<[ClangOption, FlangOption]>;
def inline_asm_EQ : Joined<["-"], "inline-asm=">, Group<m_Group>,
Visibility<[ClangOption, CC1Option]>,
Values<"att,intel">,
Expand Down Expand Up @@ -5339,7 +5347,7 @@ def print_rocm_search_dirs : Flag<["-", "--"], "print-rocm-search-dirs">,
HelpText<"Print the paths used for finding ROCm installation">,
Visibility<[ClangOption, CLOption]>;
def print_runtime_dir : Flag<["-", "--"], "print-runtime-dir">,
HelpText<"Print the directory pathname containing clangs runtime libraries">,
HelpText<"Print the directory pathname containing Clang's runtime libraries">,
Visibility<[ClangOption, CLOption]>;
def print_diagnostic_options : Flag<["-", "--"], "print-diagnostic-options">,
HelpText<"Print all of Clang's warning options">,
Expand Down Expand Up @@ -8466,8 +8474,8 @@ def _SLASH_ZW : CLJoined<"ZW">;
// clang-dxc Options
//===----------------------------------------------------------------------===//

def dxc_Group : OptionGroup<"<clang-dxc options>">, Visibility<[DXCOption]>,
HelpText<"dxc compatibility options">;
def dxc_Group : OptionGroup<"clang-dxc options">, Visibility<[DXCOption]>,
HelpText<"dxc compatibility options.">;
class DXCFlag<string name> : Option<["/", "-"], name, KIND_FLAG>,
Group<dxc_Group>, Visibility<[DXCOption]>;
class DXCJoinedOrSeparate<string name> : Option<["/", "-"], name,
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Driver/Types.def
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ TYPE("lto-bc", LTO_BC, INVALID, "o", phases
TYPE("ast", AST, INVALID, "ast", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("ifs", IFS, INVALID, "ifs", phases::IfsMerge)
TYPE("ifs-cpp", IFS_CPP, INVALID, "ifs", phases::Compile, phases::IfsMerge)
TYPE("tbd", TextAPI, INVALID, "tbd", phases::Precompile)
TYPE("pcm", ModuleFile, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("header-unit", HeaderUnit, INVALID, "pcm", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
TYPE("plist", Plist, INVALID, "plist", phases::Compile, phases::Backend, phases::Assemble, phases::Link)
Expand Down
11 changes: 8 additions & 3 deletions clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -1010,9 +1010,10 @@ struct FormatStyle {
/// \version 3.7
DefinitionReturnTypeBreakingStyle AlwaysBreakAfterDefinitionReturnType;

/// The function declaration return type breaking style to use.
/// This option is renamed to ``BreakAfterReturnType``.
/// \version 3.8
ReturnTypeBreakingStyle AlwaysBreakAfterReturnType;
/// @deprecated
// ReturnTypeBreakingStyle AlwaysBreakAfterReturnType;

/// If ``true``, always break before multiline string literals.
///
Expand Down Expand Up @@ -1576,6 +1577,10 @@ struct FormatStyle {
/// \version 16
AttributeBreakingStyle BreakAfterAttributes;

/// The function declaration return type breaking style to use.
/// \version 19
ReturnTypeBreakingStyle BreakAfterReturnType;

/// If ``true``, clang-format will always break after a Json array ``[``
/// otherwise it will scan until the closing ``]`` to determine if it should
/// add newlines between elements (prettier compatible).
Expand Down Expand Up @@ -4819,7 +4824,6 @@ struct FormatStyle {
R.AllowShortIfStatementsOnASingleLine &&
AllowShortLambdasOnASingleLine == R.AllowShortLambdasOnASingleLine &&
AllowShortLoopsOnASingleLine == R.AllowShortLoopsOnASingleLine &&
AlwaysBreakAfterReturnType == R.AlwaysBreakAfterReturnType &&
AlwaysBreakBeforeMultilineStrings ==
R.AlwaysBreakBeforeMultilineStrings &&
AttributeMacros == R.AttributeMacros &&
Expand All @@ -4830,6 +4834,7 @@ struct FormatStyle {
BreakAdjacentStringLiterals == R.BreakAdjacentStringLiterals &&
BreakAfterAttributes == R.BreakAfterAttributes &&
BreakAfterJavaFieldAnnotations == R.BreakAfterJavaFieldAnnotations &&
BreakAfterReturnType == R.BreakAfterReturnType &&
BreakArrays == R.BreakArrays &&
BreakBeforeBinaryOperators == R.BreakBeforeBinaryOperators &&
BreakBeforeBraces == R.BreakBeforeBraces &&
Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Frontend/CompilerInstance.h
Original file line number Diff line number Diff line change
Expand Up @@ -294,6 +294,13 @@ class CompilerInstance : public ModuleLoader {
return Invocation->getFrontendOpts();
}

InstallAPIOptions &getInstallAPIOpts() {
return Invocation->getInstallAPIOpts();
}
const InstallAPIOptions &getInstallAPIOpts() const {
return Invocation->getInstallAPIOpts();
}

HeaderSearchOptions &getHeaderSearchOpts() {
return Invocation->getHeaderSearchOpts();
}
Expand Down
9 changes: 8 additions & 1 deletion clang/include/clang/Frontend/CompilerInvocation.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@
#include "clang/Basic/LangStandard.h"
#include "clang/Frontend/DependencyOutputOptions.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/Frontend/InstallAPIOptions.h"
#include "clang/Frontend/MigratorOptions.h"
#include "clang/Frontend/PreprocessorOutputOptions.h"
#include "clang/StaticAnalyzer/Core/AnalyzerOptions.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include <memory>
#include <string>

Expand Down Expand Up @@ -111,6 +112,9 @@ class CompilerInvocationBase {
/// Options controlling preprocessed output.
std::shared_ptr<PreprocessorOutputOptions> PreprocessorOutputOpts;

/// Options controlling InstallAPI operations and output.
std::shared_ptr<InstallAPIOptions> InstallAPIOpts;

/// Dummy tag type whose instance can be passed into the constructor to
/// prevent creation of the reference-counted option objects.
struct EmptyConstructor {};
Expand Down Expand Up @@ -145,6 +149,7 @@ class CompilerInvocationBase {
const PreprocessorOutputOptions &getPreprocessorOutputOpts() const {
return *PreprocessorOutputOpts;
}
const InstallAPIOptions &getInstallAPIOpts() const { return *InstallAPIOpts; }
/// @}

/// Command line generation.
Expand Down Expand Up @@ -237,6 +242,7 @@ class CompilerInvocation : public CompilerInvocationBase {
using CompilerInvocationBase::getFrontendOpts;
using CompilerInvocationBase::getDependencyOutputOpts;
using CompilerInvocationBase::getPreprocessorOutputOpts;
using CompilerInvocationBase::getInstallAPIOpts;
/// @}

/// Mutable getters.
Expand All @@ -258,6 +264,7 @@ class CompilerInvocation : public CompilerInvocationBase {
PreprocessorOutputOptions &getPreprocessorOutputOpts() {
return *PreprocessorOutputOpts;
}
InstallAPIOptions &getInstallAPIOpts() { return *InstallAPIOpts; }
/// @}

/// Base class internals.
Expand Down
10 changes: 10 additions & 0 deletions clang/include/clang/Frontend/FrontendActions.h
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,16 @@ class GenerateModuleAction : public ASTFrontendAction {
bool shouldEraseOutputFiles() override;
};

class InstallAPIAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;

public:
static std::unique_ptr<llvm::raw_pwrite_stream>
CreateOutputFile(CompilerInstance &CI, StringRef InFile);
};

class GenerateInterfaceStubsAction : public ASTFrontendAction {
protected:
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Frontend/FrontendOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,9 @@ enum ActionKind {
/// Only execute frontend initialization.
InitOnly,

// Create TextAPI stub.
InstallAPI,

/// Dump information about a module file.
ModuleFileInfo,

Expand Down
28 changes: 28 additions & 0 deletions clang/include/clang/Frontend/InstallAPIOptions.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//===--- InstallAPIOptions.h ------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_FRONTEND_INSTALLAPIOPTIONS_H
#define LLVM_CLANG_FRONTEND_INSTALLAPIOPTIONS_H

#include "llvm/TextAPI/PackedVersion.h"

namespace clang {

/// InstallAPIOptions - Options for controlling InstallAPI verification and
/// TextAPI output.
class InstallAPIOptions {
public:
/// The install name which is apart of the library's ID.
std::string InstallName;

/// The current version which is apart of the library's ID.
llvm::MachO::PackedVersion CurrentVersion;
};
} // namespace clang

#endif
65 changes: 65 additions & 0 deletions clang/include/clang/InstallAPI/Context.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//===- InstallAPI/Context.h -------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// Top level types for interacting with the generic clang driver and frontend
// for InstallAPI operations.
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INSTALLAPI_CONTEXT_H
#define LLVM_CLANG_INSTALLAPI_CONTEXT_H

#include "clang/AST/ASTConsumer.h"
#include "clang/Basic/Diagnostic.h"
#include "llvm/ADT/IntrusiveRefCntPtr.h"
#include "llvm/TextAPI/InterfaceFile.h"
#include "llvm/TextAPI/RecordVisitor.h"
#include "llvm/TextAPI/RecordsSlice.h"

namespace clang {
namespace installapi {

/// Struct used for generating validating InstallAPI.
/// The attributes captured represent all necessary information
/// to generate TextAPI output.
struct InstallAPIContext {

/// Library attributes that are typically passed as linker inputs.
llvm::MachO::RecordsSlice::BinaryAttrs BA;

/// Active target triple to parse.
llvm::Triple TargetTriple{};

/// Output stream to write TextAPI file to.
std::unique_ptr<llvm::raw_pwrite_stream> OS = nullptr;

/// DiagnosticsEngine to report errors.
llvm::IntrusiveRefCntPtr<DiagnosticsEngine> Diags = nullptr;

/// File Path of output location.
StringRef OutputLoc{};

/// What encoding to write output as.
llvm::MachO::FileType FT = llvm::MachO::FileType::TBD_V5;
};

class InstallAPIConsumer : public ASTConsumer {
public:
InstallAPIConsumer(InstallAPIContext InstallAPICtx)
: Ctx(std::move(InstallAPICtx)) {}

void HandleTranslationUnit(ASTContext &ASTContext) override;

private:
InstallAPIContext Ctx;
};

} // namespace installapi
} // namespace clang

#endif // LLVM_CLANG_INSTALLAPI_CONTEXT_H
13 changes: 6 additions & 7 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,10 +346,7 @@ class DeclSpec {
// FIXME: Attributes should be included here.
};

enum FriendSpecified : bool {
No,
Yes,
};
enum FriendSpecified : bool { No, Yes };

private:
// storage-class-specifier
Expand Down Expand Up @@ -400,7 +397,7 @@ class DeclSpec {

// friend-specifier
LLVM_PREFERRED_TYPE(bool)
unsigned Friend_specified : 1;
unsigned FriendSpecifiedFirst : 1;

// constexpr-specifier
LLVM_PREFERRED_TYPE(ConstexprSpecKind)
Expand Down Expand Up @@ -491,7 +488,7 @@ class DeclSpec {
TypeSpecPipe(false), TypeSpecSat(false), ConstrainedAuto(false),
TypeQualifiers(TQ_unspecified), FS_inline_specified(false),
FS_forceinline_specified(false), FS_virtual_specified(false),
FS_noreturn_specified(false), Friend_specified(false),
FS_noreturn_specified(false), FriendSpecifiedFirst(false),
ConstexprSpecifier(
static_cast<unsigned>(ConstexprSpecKind::Unspecified)),
Attrs(attrFactory), writtenBS(), ObjCQualifiers(nullptr) {}
Expand Down Expand Up @@ -818,9 +815,11 @@ class DeclSpec {
const char *&PrevSpec, unsigned &DiagID);

FriendSpecified isFriendSpecified() const {
return static_cast<FriendSpecified>(Friend_specified);
return static_cast<FriendSpecified>(FriendLoc.isValid());
}

bool isFriendSpecifiedFirst() const { return FriendSpecifiedFirst; }

SourceLocation getFriendSpecLoc() const { return FriendLoc; }

bool isModulePrivateSpecified() const { return ModulePrivateLoc.isValid(); }
Expand Down
3 changes: 0 additions & 3 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8039,9 +8039,6 @@ class Sema final {
SourceLocation RParenLoc, bool Failed);
void DiagnoseStaticAssertDetails(const Expr *E);

FriendDecl *CheckFriendTypeDecl(SourceLocation LocStart,
SourceLocation FriendLoc,
TypeSourceInfo *TSInfo);
Decl *ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
MultiTemplateParamsArg TemplateParams);
NamedDecl *ActOnFriendFunctionDecl(Scope *S, Declarator &D,
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Serialization/ASTBitCodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -2018,6 +2018,9 @@ enum StmtCode {

// SYCLUniqueStableNameExpr
EXPR_SYCL_UNIQUE_STABLE_NAME,

// OpenACC Constructs
STMT_OPENACC_COMPUTE_CONSTRUCT,
};

/// The kinds of designators that can occur in a
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/ASTStructuralEquivalence.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/NestedNameSpecifier.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/TemplateBase.h"
#include "clang/AST/TemplateName.h"
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ add_clang_library(clangAST
StmtCXX.cpp
StmtIterator.cpp
StmtObjC.cpp
StmtOpenACC.cpp
StmtOpenMP.cpp
StmtPrinter.cpp
StmtProfile.cpp
Expand Down
122 changes: 113 additions & 9 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,9 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitNull(classifyPrim(CE->getType()), CE);

case CK_PointerToIntegral: {
// TODO: Discard handling.
if (DiscardResult)
return this->discard(SubExpr);

if (!this->visit(SubExpr))
return false;

Expand Down Expand Up @@ -1827,8 +1829,19 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
return false;
}

if (!this->emitCall(Func, E))
return false;
if (Func->isVariadic()) {
uint32_t VarArgSize = 0;
unsigned NumParams = Func->getNumWrittenParams();
for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I) {
VarArgSize +=
align(primSize(classify(E->getArg(I)->getType()).value_or(PT_Ptr)));
}
if (!this->emitCallVar(Func, VarArgSize, E))
return false;
} else {
if (!this->emitCall(Func, 0, E))
return false;
}

// Immediately call the destructor if we have to.
if (DiscardResult) {
Expand Down Expand Up @@ -1861,7 +1874,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXConstructExpr(
return false;
}

if (!this->emitCall(Func, E))
if (!this->emitCall(Func, 0, E))
return false;
}
return true;
Expand Down Expand Up @@ -2047,7 +2060,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXInheritedCtorInitExpr(
Offset += align(primSize(PT));
}

return this->emitCall(F, E);
return this->emitCall(F, 0, E);
}

template <class Emitter>
Expand All @@ -2057,6 +2070,79 @@ bool ByteCodeExprGen<Emitter>::VisitExpressionTraitExpr(
return this->emitConstBool(E->getValue(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitCXXUuidofExpr(const CXXUuidofExpr *E) {
if (DiscardResult)
return true;
assert(!Initializing);

std::optional<unsigned> GlobalIndex = P.getOrCreateGlobal(E->getGuidDecl());
if (!GlobalIndex)
return false;
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
return false;

const Record *R = this->getRecord(E->getType());
assert(R);

const APValue &V = E->getGuidDecl()->getAsAPValue();
if (V.getKind() == APValue::None)
return true;

assert(V.isStruct());
assert(V.getStructNumBases() == 0);
// FIXME: This could be useful in visitAPValue, too.
for (unsigned I = 0, N = V.getStructNumFields(); I != N; ++I) {
const APValue &F = V.getStructField(I);
const Record::Field *RF = R->getField(I);

if (F.isInt()) {
PrimType T = classifyPrim(RF->Decl->getType());
if (!this->visitAPValue(F, T, E))
return false;
if (!this->emitInitField(T, RF->Offset, E))
return false;
} else if (F.isArray()) {
assert(RF->Desc->isPrimitiveArray());
const auto *ArrType = RF->Decl->getType()->getAsArrayTypeUnsafe();
PrimType ElemT = classifyPrim(ArrType->getElementType());
assert(ArrType);

if (!this->emitDupPtr(E))
return false;
if (!this->emitGetPtrField(RF->Offset, E))
return false;

for (unsigned A = 0, AN = F.getArraySize(); A != AN; ++A) {
if (!this->visitAPValue(F.getArrayInitializedElt(A), ElemT, E))
return false;
if (!this->emitInitElem(ElemT, A, E))
return false;
}

if (!this->emitPopPtr(E))
return false;
} else {
assert(false && "I don't think this should be possible");
}
}

return this->emitInitPtr(E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitRequiresExpr(const RequiresExpr *E) {
assert(classifyPrim(E->getType()) == PT_Bool);
return this->emitConstBool(E->isSatisfied(), E);
}

template <class Emitter>
bool ByteCodeExprGen<Emitter>::VisitConceptSpecializationExpr(
const ConceptSpecializationExpr *E) {
assert(classifyPrim(E->getType()) == PT_Bool);
return this->emitConstBool(E->isSatisfied(), E);
}

template <class Emitter> bool ByteCodeExprGen<Emitter>::discard(const Expr *E) {
if (E->containsErrors())
return false;
Expand Down Expand Up @@ -2771,20 +2857,38 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
// and if the function has RVO, we already have the pointer on the stack to
// write the result into.
if (IsVirtual && !HasQualifier) {
if (!this->emitCallVirt(Func, E))
uint32_t VarArgSize = 0;
unsigned NumParams = Func->getNumWrittenParams();
for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I)
VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));

if (!this->emitCallVirt(Func, VarArgSize, E))
return false;
} else if (Func->isVariadic()) {
uint32_t VarArgSize = 0;
unsigned NumParams = Func->getNumWrittenParams();
for (unsigned I = NumParams, N = E->getNumArgs(); I != N; ++I)
VarArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));
if (!this->emitCallVar(Func, VarArgSize, E))
return false;
} else {
if (!this->emitCall(Func, E))
if (!this->emitCall(Func, 0, E))
return false;
}
} else {
// Indirect call. Visit the callee, which will leave a FunctionPointer on
// the stack. Cleanup of the returned value if necessary will be done after
// the function call completed.

// Sum the size of all args from the call expr.
uint32_t ArgSize = 0;
for (unsigned I = 0, N = E->getNumArgs(); I != N; ++I)
ArgSize += align(primSize(classify(E->getArg(I)).value_or(PT_Ptr)));

if (!this->visit(E->getCallee()))
return false;

if (!this->emitCallPtr(E))
if (!this->emitCallPtr(ArgSize, E))
return false;
}

Expand Down Expand Up @@ -3311,7 +3415,7 @@ bool ByteCodeExprGen<Emitter>::emitRecordDestruction(const Descriptor *Desc) {
assert(DtorFunc->getNumParams() == 1);
if (!this->emitDupPtr(SourceInfo{}))
return false;
if (!this->emitCall(DtorFunc, SourceInfo{}))
if (!this->emitCall(DtorFunc, 0, SourceInfo{}))
return false;
}
}
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/AST/Interp/ByteCodeExprGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@ class ByteCodeExprGen : public ConstStmtVisitor<ByteCodeExprGen<Emitter>, bool>,
bool VisitObjCBoolLiteralExpr(const ObjCBoolLiteralExpr *E);
bool VisitCXXInheritedCtorInitExpr(const CXXInheritedCtorInitExpr *E);
bool VisitExpressionTraitExpr(const ExpressionTraitExpr *E);
bool VisitCXXUuidofExpr(const CXXUuidofExpr *E);
bool VisitRequiresExpr(const RequiresExpr *E);
bool VisitConceptSpecializationExpr(const ConceptSpecializationExpr *E);

protected:
bool visitExpr(const Expr *E) override;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/ByteCodeStmtGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody(
return false;
}

if (!this->emitCall(Func, LambdaCallOp))
if (!this->emitCall(Func, 0, LambdaCallOp))
return false;

this->emitCleanup();
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,8 @@ bool Context::Run(State &Parent, const Function *Func, APValue &Result) {

{
InterpState State(Parent, *P, Stk, *this);
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, {});
State.Current = new InterpFrame(State, Func, /*Caller=*/nullptr, CodePtr(),
Func->getArgSize());
if (Interpret(State, Result)) {
assert(Stk.empty());
return true;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ EvalEmitter::EvalEmitter(Context &Ctx, Program &P, State &Parent,
: Ctx(Ctx), P(P), S(Parent, P, Stk, Ctx, this), EvalResult(&Ctx) {
// Create a dummy frame for the interpreter which does not have locals.
S.Current =
new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr());
new InterpFrame(S, /*Func=*/nullptr, /*Caller=*/nullptr, CodePtr(), 0);
}

EvalEmitter::~EvalEmitter() {
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/AST/Interp/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,16 @@ class Function final {

unsigned getNumParams() const { return ParamTypes.size(); }

/// Returns the number of parameter this function takes when it's called,
/// i.e excluding the instance pointer and the RVO pointer.
unsigned getNumWrittenParams() const {
assert(getNumParams() >= (hasThisPointer() + hasRVO()));
return getNumParams() - hasThisPointer() - hasRVO();
}
unsigned getWrittenArgSize() const {
return ArgSize - (align(primSize(PT_Ptr)) * (hasThisPointer() + hasRVO()));
}

unsigned getParamOffset(unsigned ParamIndex) const {
return ParamOffsets[ParamIndex];
}
Expand Down
25 changes: 18 additions & 7 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,16 +169,27 @@ void cleanupAfterFunctionCall(InterpState &S, CodePtr OpPC) {
// CallExpr we're look for is at the return PC of the current function, i.e.
// in the caller.
// This code path should be executed very rarely.
const auto *CE =
cast<CallExpr>(S.Current->Caller->getExpr(S.Current->getRetPC()));
unsigned FixedParams = CurFunc->getNumParams();
int32_t ArgsToPop = CE->getNumArgs() - FixedParams;
assert(ArgsToPop >= 0);
for (int32_t I = ArgsToPop - 1; I >= 0; --I) {
const Expr *A = CE->getArg(FixedParams + I);
unsigned NumVarArgs;
const Expr *const *Args = nullptr;
unsigned NumArgs = 0;
const Expr *CallSite = S.Current->Caller->getExpr(S.Current->getRetPC());
if (const auto *CE = dyn_cast<CallExpr>(CallSite)) {
Args = CE->getArgs();
NumArgs = CE->getNumArgs();
} else if (const auto *CE = dyn_cast<CXXConstructExpr>(CallSite)) {
Args = CE->getArgs();
NumArgs = CE->getNumArgs();
} else
assert(false && "Can't get arguments from that expression type");

assert(NumArgs >= CurFunc->getNumWrittenParams());
NumVarArgs = NumArgs - CurFunc->getNumWrittenParams();
for (unsigned I = 0; I != NumVarArgs; ++I) {
const Expr *A = Args[NumArgs - 1 - I];
popArg(S, A);
}
}

// And in any case, remove the fixed parameters (the non-variadic ones)
// at the end.
S.Current->popArgs();
Expand Down
79 changes: 66 additions & 13 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1915,10 +1915,60 @@ inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
return false;
}

inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
size_t ThisOffset =
Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

// If the current function is a lambda static invoker and
// the function we're about to call is a lambda call operator,
// skip the CheckInvoke, since the ThisPtr is a null pointer
// anyway.
if (!(S.Current->getFunction() &&
S.Current->getFunction()->isLambdaStaticInvoker() &&
Func->isLambdaCallOperator())) {
if (!CheckInvoke(S, OpPC, ThisPtr))
return false;
}

if (S.checkingPotentialConstantExpression())
return false;
}

if (!CheckCallable(S, OpPC, Func))
return false;

if (!CheckCallDepth(S, OpPC))
return false;

auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

APValue CallResult;
// Note that we cannot assert(CallResult.hasValue()) here since
// Ret() above only sets the APValue if the curent frame doesn't
// have a caller set.
if (Interpret(S, CallResult)) {
NewFrame.release(); // Frame was delete'd already.
assert(S.Current == FrameBefore);
return true;
}

// Interpreting the function failed somehow. Reset to
// previous state.
S.Current = FrameBefore;
return false;

return false;
}
inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);

const Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

Expand All @@ -1943,7 +1993,7 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
if (!CheckCallDepth(S, OpPC))
return false;

auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC);
auto NewFrame = std::make_unique<InterpFrame>(S, Func, OpPC, VarArgSize);
InterpFrame *FrameBefore = S.Current;
S.Current = NewFrame.get();

Expand All @@ -1963,11 +2013,12 @@ inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func) {
return false;
}

inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
assert(Func->hasThisPointer());
assert(Func->isVirtual());
size_t ThisOffset =
Func->getArgSize() - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
size_t ArgSize = Func->getArgSize() + VarArgSize;
size_t ThisOffset = ArgSize - (Func->hasRVO() ? primSize(PT_Ptr) : 0);
Pointer &ThisPtr = S.Stk.peek<Pointer>(ThisOffset);

const CXXRecordDecl *DynamicDecl =
Expand Down Expand Up @@ -1998,7 +2049,7 @@ inline bool CallVirt(InterpState &S, CodePtr OpPC, const Function *Func) {
}
}

return Call(S, OpPC, Func);
return Call(S, OpPC, Func, VarArgSize);
}

inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
Expand All @@ -2016,17 +2067,19 @@ inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
return false;
}

inline bool CallPtr(InterpState &S, CodePtr OpPC) {
inline bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize) {
const FunctionPointer &FuncPtr = S.Stk.pop<FunctionPointer>();

const Function *F = FuncPtr.getFunction();
if (!F || !F->isConstexpr())
return false;
assert(F);

assert(ArgSize >= F->getWrittenArgSize());
uint32_t VarArgSize = ArgSize - F->getWrittenArgSize();

if (F->isVirtual())
return CallVirt(S, OpPC, F);
return CallVirt(S, OpPC, F, VarArgSize);

return Call(S, OpPC, F);
return Call(S, OpPC, F, VarArgSize);
}

inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
Expand Down
17 changes: 12 additions & 5 deletions clang/lib/AST/Interp/InterpFrame.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ using namespace clang;
using namespace clang::interp;

InterpFrame::InterpFrame(InterpState &S, const Function *Func,
InterpFrame *Caller, CodePtr RetPC)
InterpFrame *Caller, CodePtr RetPC, unsigned ArgSize)
: Caller(Caller), S(S), Depth(Caller ? Caller->Depth + 1 : 0), Func(Func),
RetPC(RetPC), ArgSize(Func ? Func->getArgSize() : 0),
Args(static_cast<char *>(S.Stk.top())), FrameOffset(S.Stk.size()) {
RetPC(RetPC), ArgSize(ArgSize), Args(static_cast<char *>(S.Stk.top())),
FrameOffset(S.Stk.size()) {
if (!Func)
return;

Expand All @@ -43,8 +43,9 @@ InterpFrame::InterpFrame(InterpState &S, const Function *Func,
}
}

InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC)
: InterpFrame(S, Func, S.Current, RetPC) {
InterpFrame::InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
unsigned VarArgSize)
: InterpFrame(S, Func, S.Current, RetPC, Func->getArgSize() + VarArgSize) {
// As per our calling convention, the this pointer is
// part of the ArgSize.
// If the function has RVO, the RVO pointer is first.
Expand Down Expand Up @@ -228,10 +229,16 @@ SourceInfo InterpFrame::getSource(CodePtr PC) const {
}

const Expr *InterpFrame::getExpr(CodePtr PC) const {
if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
return Caller->getExpr(RetPC);

return S.getExpr(Func, PC);
}

SourceLocation InterpFrame::getLocation(CodePtr PC) const {
if (Func && (!Func->hasBody() || Func->getDecl()->isImplicit()) && Caller)
return Caller->getLocation(RetPC);

return S.getLocation(Func, PC);
}

Expand Down
5 changes: 3 additions & 2 deletions clang/lib/AST/Interp/InterpFrame.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,14 @@ class InterpFrame final : public Frame {

/// Creates a new frame for a method call.
InterpFrame(InterpState &S, const Function *Func, InterpFrame *Caller,
CodePtr RetPC);
CodePtr RetPC, unsigned ArgSize);

/// Creates a new frame with the values that make sense.
/// I.e., the caller is the current frame of S,
/// the This() pointer is the current Pointer on the top of S's stack,
/// and the RVO pointer is before that.
InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC);
InterpFrame(InterpState &S, const Function *Func, CodePtr RetPC,
unsigned VarArgSize = 0);

/// Destroys the frame, killing all live pointers to stack slots.
~InterpFrame();
Expand Down
11 changes: 8 additions & 3 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ def NoRet : Opcode {}


def Call : Opcode {
let Args = [ArgFunction];
let Args = [ArgFunction, ArgUint32];
let Types = [];
}

def CallVirt : Opcode {
let Args = [ArgFunction];
let Args = [ArgFunction, ArgUint32];
let Types = [];
}

Expand All @@ -206,7 +206,12 @@ def CallBI : Opcode {
}

def CallPtr : Opcode {
let Args = [];
let Args = [ArgUint32];
let Types = [];
}

def CallVar : Opcode {
let Args = [ArgFunction, ArgUint32];
let Types = [];
}

Expand Down
6 changes: 1 addition & 5 deletions clang/lib/AST/Interp/Pointer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -232,11 +232,7 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {

// Primitive values.
if (std::optional<PrimType> T = Ctx.classify(Ty)) {
if (T == PT_Ptr || T == PT_FnPtr) {
R = Ptr.toAPValue();
} else {
TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue());
}
TYPE_SWITCH(*T, R = Ptr.deref<T>().toAPValue());
return true;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ std::optional<unsigned> Program::createGlobal(const ValueDecl *VD,
if (const auto *Var = dyn_cast<VarDecl>(VD)) {
IsStatic = Context::shouldBeGloballyIndexed(VD);
IsExtern = !Var->getAnyInitializer();
} else if (isa<UnnamedGlobalConstantDecl>(VD)) {
} else if (isa<UnnamedGlobalConstantDecl, MSGuidDecl>(VD)) {
IsStatic = true;
IsExtern = false;
} else {
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ class Program final {
std::optional<unsigned> getOrCreateDummy(const ValueDecl *VD);

/// Creates a global and returns its index.
std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *E);
std::optional<unsigned> createGlobal(const ValueDecl *VD, const Expr *Init);

/// Creates a global from a lifetime-extended temporary.
std::optional<unsigned> createGlobal(const Expr *E);
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ SourceRange SourceInfo::getRange() const {
}

const Expr *SourceInfo::asExpr() const {
if (auto *S = Source.dyn_cast<const Stmt *>())
if (const auto *S = Source.dyn_cast<const Stmt *>())
return dyn_cast<Expr>(S);
return nullptr;
}
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Stmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "clang/AST/ExprOpenMP.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtObjC.h"
#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/Type.h"
#include "clang/Basic/CharInfo.h"
Expand Down
33 changes: 33 additions & 0 deletions clang/lib/AST/StmtOpenACC.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//===--- StmtOpenACC.cpp - Classes for OpenACC Constructs -----------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file implements the subclesses of Stmt class declared in StmtOpenACC.h
//
//===----------------------------------------------------------------------===//

#include "clang/AST/StmtOpenACC.h"
#include "clang/AST/ASTContext.h"
using namespace clang;

OpenACCComputeConstruct *
OpenACCComputeConstruct::CreateEmpty(const ASTContext &C, EmptyShell) {
void *Mem = C.Allocate(sizeof(OpenACCComputeConstruct),
alignof(OpenACCComputeConstruct));
auto *Inst = new (Mem) OpenACCComputeConstruct;
return Inst;
}

OpenACCComputeConstruct *
OpenACCComputeConstruct::Create(const ASTContext &C, OpenACCDirectiveKind K,
SourceLocation BeginLoc,
SourceLocation EndLoc) {
void *Mem = C.Allocate(sizeof(OpenACCComputeConstruct),
alignof(OpenACCComputeConstruct));
auto *Inst = new (Mem) OpenACCComputeConstruct(K, BeginLoc, EndLoc);
return Inst;
}
9 changes: 9 additions & 0 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1137,6 +1137,15 @@ void StmtPrinter::VisitOMPTargetParallelGenericLoopDirective(
PrintOMPExecutableDirective(Node);
}

//===----------------------------------------------------------------------===//
// OpenACC construct printing methods
//===----------------------------------------------------------------------===//
void StmtPrinter::VisitOpenACCComputeConstruct(OpenACCComputeConstruct *S) {
Indent() << "#pragma acc " << S->getDirectiveKind();
// TODO OpenACC: Print Clauses.
PrintStmt(S->getStructuredBlock());
}

//===----------------------------------------------------------------------===//
// Expr printing methods.
//===----------------------------------------------------------------------===//
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/AST/StmtProfile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2441,6 +2441,13 @@ void StmtProfiler::VisitTemplateArgument(const TemplateArgument &Arg) {
}
}

void StmtProfiler::VisitOpenACCComputeConstruct(
const OpenACCComputeConstruct *S) {
// VisitStmt handles children, so the AssociatedStmt is handled.
VisitStmt(S);
// TODO OpenACC: Visit Clauses.
}

void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
bool Canonical, bool ProfileLambdaExpr) const {
StmtProfilerWithPointers Profiler(ID, Context, Canonical, ProfileLambdaExpr);
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/AST/TextNodeDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2668,3 +2668,8 @@ void TextNodeDumper::VisitHLSLBufferDecl(const HLSLBufferDecl *D) {
OS << " tbuffer";
dumpName(D);
}

void TextNodeDumper::VisitOpenACCConstructStmt(const OpenACCConstructStmt *S) {
OS << " " << S->getDirectiveKind();
// TODO OpenACC: Dump clauses as well.
}
74 changes: 47 additions & 27 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -887,34 +887,10 @@ Value *Environment::createValueUnlessSelfReferential(

if (Type->isRecordType()) {
CreatedValuesCount++;
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;
for (const FieldDecl *Field : DACtx->getModeledFields(Type)) {
assert(Field != nullptr);
auto &Loc = cast<RecordStorageLocation>(createStorageLocation(Type));
initializeFieldsWithValues(Loc, Visited, Depth, CreatedValuesCount);

QualType FieldType = Field->getType();

FieldLocs.insert(
{Field, &createLocAndMaybeValue(FieldType, Visited, Depth + 1,
CreatedValuesCount)});
}

RecordStorageLocation::SyntheticFieldMap SyntheticFieldLocs;
for (const auto &Entry : DACtx->getSyntheticFields(Type)) {
SyntheticFieldLocs.insert(
{Entry.getKey(),
&createLocAndMaybeValue(Entry.getValue(), Visited, Depth + 1,
CreatedValuesCount)});
}

RecordStorageLocation &Loc = DACtx->createRecordStorageLocation(
Type, std::move(FieldLocs), std::move(SyntheticFieldLocs));
RecordValue &RecordVal = create<RecordValue>(Loc);

// As we already have a storage location for the `RecordValue`, we can and
// should associate them in the environment.
setValue(Loc, RecordVal);

return &RecordVal;
return &refreshRecordValue(Loc, *this);
}

return nullptr;
Expand Down Expand Up @@ -943,6 +919,50 @@ Environment::createLocAndMaybeValue(QualType Ty,
return Loc;
}

void Environment::initializeFieldsWithValues(RecordStorageLocation &Loc,
llvm::DenseSet<QualType> &Visited,
int Depth,
int &CreatedValuesCount) {
auto initField = [&](QualType FieldType, StorageLocation &FieldLoc) {
if (FieldType->isRecordType()) {
auto &FieldRecordLoc = cast<RecordStorageLocation>(FieldLoc);
setValue(FieldRecordLoc, create<RecordValue>(FieldRecordLoc));
initializeFieldsWithValues(FieldRecordLoc, Visited, Depth + 1,
CreatedValuesCount);
} else {
if (!Visited.insert(FieldType.getCanonicalType()).second)
return;
if (Value *Val = createValueUnlessSelfReferential(
FieldType, Visited, Depth + 1, CreatedValuesCount))
setValue(FieldLoc, *Val);
Visited.erase(FieldType.getCanonicalType());
}
};

for (const auto &[Field, FieldLoc] : Loc.children()) {
assert(Field != nullptr);
QualType FieldType = Field->getType();

if (FieldType->isReferenceType()) {
Loc.setChild(*Field,
&createLocAndMaybeValue(FieldType, Visited, Depth + 1,
CreatedValuesCount));
} else {
assert(FieldLoc != nullptr);
initField(FieldType, *FieldLoc);
}
}
for (const auto &[FieldName, FieldLoc] : Loc.synthetic_fields()) {
assert(FieldLoc != nullptr);
QualType FieldType = FieldLoc->getType();

// Synthetic fields cannot have reference type, so we don't need to deal
// with this case.
assert(!FieldType->isReferenceType());
initField(FieldType, Loc.getSyntheticField(FieldName));
}
}

StorageLocation &Environment::createObjectInternal(const ValueDecl *D,
QualType Ty,
const Expr *InitExpr) {
Expand Down
14 changes: 13 additions & 1 deletion clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -535,7 +535,19 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
return;

copyRecord(*LocSrc, *LocDst, Env);
Env.setStorageLocation(*S, *LocDst);

// If the expr is a glvalue, we can reasonably assume the operator is
// returning T& and thus we can assign it `LocDst`.
if (S->isGLValue()) {
Env.setStorageLocation(*S, *LocDst);
} else if (S->getType()->isRecordType()) {
// Make sure that we have a `RecordValue` for this expression so that
// `Environment::getResultObjectLocation()` is able to return a location
// for it.
if (Env.getValue(*S) == nullptr)
refreshRecordValue(*S, Env);
}

return;
}

Expand Down
Loading