10 changes: 10 additions & 0 deletions clang-tools-extra/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,10 @@ The improvements are...
Improvements to clang-tidy
--------------------------

- Improved :program:`run-clang-tidy.py` script. Added argument `-source-filter`
to filter source files from the compilation database, via a RegEx. In a
similar fashion to what `-header-filter` does for header files.

New checks
^^^^^^^^^^

Expand Down Expand Up @@ -179,6 +183,12 @@ Changes in existing checks
<clang-tidy/checks/modernize/use-override>` check to also remove any trailing
whitespace when deleting the ``virtual`` keyword.

- Improved :doc:`performance-unnecessary-copy-initialization
<clang-tidy/checks/performance/unnecessary-copy-initialization>` check by
detecting more cases of constant access. In particular, pointers can be
analyzed, se the check now handles the common patterns
`const auto e = (*vector_ptr)[i]` and `const auto e = vector_ptr->at(i);`.

- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check to provide
valid fix suggestions for ``static_cast`` without a preceding space and
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ struct Container {
ConstIterator<T> end() const;
void nonConstMethod();
bool constMethod() const;

const T& at(int) const;
T& at(int);

};

using ExpensiveToCopyContainerAlias = Container<ExpensiveToCopyType>;
Expand Down Expand Up @@ -225,25 +229,25 @@ void PositiveOperatorCallConstValueParamAlias(const ExpensiveToCopyContainerAlia
VarCopyConstructed.constMethod();
}

void PositiveOperatorCallConstValueParam(const Container<ExpensiveToCopyType>* C) {
void PositiveOperatorCallConstPtrParam(const Container<ExpensiveToCopyType>* C) {
const auto AutoAssigned = (*C)[42];
// TODO-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
// TODO-FIXES: const auto& AutoAssigned = (*C)[42];
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoAssigned'
// CHECK-FIXES: const auto& AutoAssigned = (*C)[42];
AutoAssigned.constMethod();

const auto AutoCopyConstructed((*C)[42]);
// TODO-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
// TODO-FIXES: const auto& AutoCopyConstructed((*C)[42]);
// CHECK-MESSAGES: [[@LINE-1]]:14: warning: the const qualified variable 'AutoCopyConstructed'
// CHECK-FIXES: const auto& AutoCopyConstructed((*C)[42]);
AutoCopyConstructed.constMethod();

const ExpensiveToCopyType VarAssigned = C->operator[](42);
// TODO-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
// TODO-FIXES: const ExpensiveToCopyType& VarAssigned = C->operator[](42);
const ExpensiveToCopyType VarAssigned = C->at(42);
// CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarAssigned'
// CHECK-FIXES: const ExpensiveToCopyType& VarAssigned = C->at(42);
VarAssigned.constMethod();

const ExpensiveToCopyType VarCopyConstructed(C->operator[](42));
// TODO-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
// TODO-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->operator[](42));
const ExpensiveToCopyType VarCopyConstructed(C->at(42));
// CHECK-MESSAGES: [[@LINE-1]]:29: warning: the const qualified variable 'VarCopyConstructed'
// CHECK-FIXES: const ExpensiveToCopyType& VarCopyConstructed(C->at(42));
VarCopyConstructed.constMethod();
}

Expand Down Expand Up @@ -876,3 +880,4 @@ void negativeNonConstMemberExpr() {
mutate(&Copy.Member);
}
}

274 changes: 168 additions & 106 deletions clang-tools-extra/unittests/clang-tidy/DeclRefExprUtilsTest.cpp

Large diffs are not rendered by default.

143 changes: 142 additions & 1 deletion clang/docs/ClangFormatStyleOptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -955,6 +955,146 @@ the configuration (without a prefix: ``Auto``).
}


.. _AlignConsecutiveTableGenCondOperatorColons:

**AlignConsecutiveTableGenCondOperatorColons** (``AlignConsecutiveStyle``) :versionbadge:`clang-format 19` :ref:`¶ <AlignConsecutiveTableGenCondOperatorColons>`
Style of aligning consecutive TableGen cond operator colons.
Align the colons of cases inside !cond operators.

.. code-block:: c++

!cond(!eq(size, 1) : 1,
!eq(size, 16): 1,
true : 0)

Nested configuration flags:

Alignment options.

They can also be read as a whole for compatibility. The choices are:
- None
- Consecutive
- AcrossEmptyLines
- AcrossComments
- AcrossEmptyLinesAndComments

For example, to align across empty lines and not across comments, either
of these work.

.. code-block:: c++

AlignConsecutiveMacros: AcrossEmptyLines

AlignConsecutiveMacros:
Enabled: true
AcrossEmptyLines: true
AcrossComments: false

* ``bool Enabled`` Whether aligning is enabled.

.. code-block:: c++

#define SHORT_NAME 42
#define LONGER_NAME 0x007f
#define EVEN_LONGER_NAME (2)
#define foo(x) (x * x)
#define bar(y, z) (y + z)

int a = 1;
int somelongname = 2;
double c = 3;

int aaaa : 1;
int b : 12;
int ccc : 8;

int aaaa = 12;
float b = 23;
std::string ccc;

* ``bool AcrossEmptyLines`` Whether to align across empty lines.

.. code-block:: c++

true:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

false:
int a = 1;
int somelongname = 2;
double c = 3;

int d = 3;

* ``bool AcrossComments`` Whether to align across comments.

.. code-block:: c++

true:
int d = 3;
/* A comment. */
double e = 4;
false:
int d = 3;
/* A comment. */
double e = 4;
* ``bool AlignCompound`` Only for ``AlignConsecutiveAssignments``. Whether compound assignments
like ``+=`` are aligned along with ``=``.

.. code-block:: c++

true:
a &= 2;
bbb = 2;

false:
a &= 2;
bbb = 2;

* ``bool AlignFunctionPointers`` Only for ``AlignConsecutiveDeclarations``. Whether function pointers are
aligned.

.. code-block:: c++

true:
unsigned i;
int &r;
int *p;
int (*f)();
false:
unsigned i;
int &r;
int *p;
int (*f)();
* ``bool PadOperators`` Only for ``AlignConsecutiveAssignments``. Whether short assignment
operators are left-padded to the same length as long ones in order to
put all assignment operators to the right of the left hand side.

.. code-block:: c++

true:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;

false:
a >>= 2;
bbb = 2;

a = 2;
bbb >>= 2;


.. _AlignEscapedNewlines:

**AlignEscapedNewlines** (``EscapedNewlineAlignmentStyle``) :versionbadge:`clang-format 5` :ref:`¶ <AlignEscapedNewlines>`
Expand Down Expand Up @@ -4844,7 +4984,8 @@ the configuration (without a prefix: ``Auto``).
.. _RemoveSemicolon:

**RemoveSemicolon** (``Boolean``) :versionbadge:`clang-format 16` :ref:`¶ <RemoveSemicolon>`
Remove semicolons after the closing brace of a non-empty function.
Remove semicolons after the closing braces of functions and
constructors/destructors.

.. warning::

Expand Down
4 changes: 2 additions & 2 deletions clang/docs/HLSL/ExpectedDifferences.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ behavior between Clang and DXC. Some examples include:
fma(X, Y, Z); // DXC: Fails to resolve no known conversion from float to double.
// Clang: Resolves to fma(double,double,double).
#endif

double D = dot(A, B); // DXC: Resolves to dot(double3, double3), fails DXIL Validation.
// FXC: Expands to compute double dot product with fmul/fadd
// Clang: Resolves to dot(float3, float3), emits conversion warnings.
Expand All @@ -102,7 +102,7 @@ behavior between Clang and DXC. Some examples include:

.. note::

In Clang, a conscious decision was made to exclude the ``dot(vector<double,N>, vector<double,N>)``
In Clang, a conscious decision was made to exclude the ``dot(vector<double,N>, vector<double,N>)``
overload and allow overload resolution to resolve the
``vector<float,N>`` overload. This approach provides ``-Wconversion``
diagnostic notifying the user of the conversion rather than silently altering
Expand Down
2 changes: 2 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,8 @@ Bug Fixes to C++ Support
a requires-clause lie at the same depth as those of the surrounding lambda. This,
in turn, results in the wrong template argument substitution during constraint checking.
(`#78524 <https://github.com/llvm/llvm-project/issues/78524>`_)
- Clang no longer instantiates the exception specification of discarded candidate function
templates when determining the primary template of an explicit specialization.

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,12 +753,9 @@ RecordStorageLocation *getImplicitObjectLocation(const CXXMemberCallExpr &MCE,
RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
const Environment &Env);

/// Returns the fields of a `RecordDecl` that are initialized by an
/// `InitListExpr`, in the order in which they appear in
/// `InitListExpr::inits()`.
/// `Init->getType()` must be a record type.
std::vector<const FieldDecl *>
getFieldsForInitListExpr(const InitListExpr *InitList);
/// Returns the fields of `RD` that are initialized by an `InitListExpr`, in the
/// order in which they appear in `InitListExpr::inits()`.
std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD);

/// Associates a new `RecordValue` with `Loc` and returns the new value.
RecordValue &refreshRecordValue(RecordStorageLocation &Loc, Environment &Env);
Expand Down
12 changes: 6 additions & 6 deletions clang/include/clang/Analysis/FlowSensitive/DataflowValues.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ class DataflowValues {
//===--------------------------------------------------------------------===//

public:
typedef typename ValueTypes::ValTy ValTy;
typedef typename ValueTypes::AnalysisDataTy AnalysisDataTy;
typedef _AnalysisDirTag AnalysisDirTag;
typedef llvm::DenseMap<ProgramPoint, ValTy> EdgeDataMapTy;
typedef llvm::DenseMap<const CFGBlock*, ValTy> BlockDataMapTy;
typedef llvm::DenseMap<const Stmt*, ValTy> StmtDataMapTy;
using ValTy = typename ValueTypes::ValTy;
using AnalysisDataTy = typename ValueTypes::AnalysisDataTy;
using AnalysisDirTag = _AnalysisDirTag;
using EdgeDataMapTy = llvm::DenseMap<ProgramPoint, ValTy>;
using BlockDataMapTy = llvm::DenseMap<const CFGBlock *, ValTy>;
using StmtDataMapTy = llvm::DenseMap<const Stmt *, ValTy>;

//===--------------------------------------------------------------------===//
// Predicates.
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 @@ -4524,6 +4524,12 @@ def HLSLCreateHandle : LangBuiltin<"HLSL_LANG"> {
let Prototype = "void*(unsigned char)";
}

def HLSLDotProduct : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_dot"];
let Attributes = [NoThrow, Const];
let Prototype = "void(...)";
}

// Builtins for XRay.
def XRayCustomEvent : Builtin {
let Spellings = ["__xray_customevent"];
Expand Down
12 changes: 10 additions & 2 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -10760,6 +10760,13 @@ def warn_imp_cast_drops_unaligned : Warning<

} // end of sema category

let CategoryName = "API Notes Issue" in {

def err_incompatible_replacement_type : Error<
"API notes replacement type %0 has a different size from original type %1">;

} // end of API Notes category

let CategoryName = "OpenMP Issue" in {
// OpenMP support.
def err_omp_expected_var_arg : Error<
Expand Down Expand Up @@ -12203,6 +12210,7 @@ def warn_acc_clause_unimplemented
def err_acc_construct_appertainment
: Error<"OpenACC construct '%0' cannot be used here; it can only "
"be used in a statement context">;
def err_acc_branch_in_out
: Error<"invalid branch %select{out of|into}0 OpenACC Compute Construct">;
def err_acc_branch_in_out_compute_construct
: Error<"invalid %select{branch|return}0 %select{out of|into}1 OpenACC "
"Compute Construct">;
} // end of sema component.
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticSerializationKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,9 @@ def err_pch_diagopt_mismatch : Error<"%0 is currently enabled, but was not in "
"the PCH file">;
def err_pch_modulecache_mismatch : Error<"PCH was compiled with module cache "
"path '%0', but the path is currently '%1'">;
def err_pch_vfsoverlay_mismatch : Error<"PCH was compiled with different VFS overlay files than are currently in use">;
def warn_pch_vfsoverlay_mismatch : Warning<
"PCH was compiled with different VFS overlay files than are currently in use">,
InGroup<DiagGroup<"pch-vfs-diff">>;
def note_pch_vfsoverlay_files : Note<"%select{PCH|current translation unit}0 has the following VFS overlays:\n%1">;
def note_pch_vfsoverlay_empty : Note<"%select{PCH|current translation unit}0 has no VFS overlays">;

Expand Down
15 changes: 14 additions & 1 deletion clang/include/clang/Format/Format.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,16 @@ struct FormatStyle {
/// \version 17
ShortCaseStatementsAlignmentStyle AlignConsecutiveShortCaseStatements;

/// Style of aligning consecutive TableGen cond operator colons.
/// Align the colons of cases inside !cond operators.
/// \code
/// !cond(!eq(size, 1) : 1,
/// !eq(size, 16): 1,
/// true : 0)
/// \endcode
/// \version 19
AlignConsecutiveStyle AlignConsecutiveTableGenCondOperatorColons;

/// Different styles for aligning escaped newlines.
enum EscapedNewlineAlignmentStyle : int8_t {
/// Don't align escaped newlines.
Expand Down Expand Up @@ -3771,7 +3781,8 @@ struct FormatStyle {
/// \version 17
RemoveParenthesesStyle RemoveParentheses;

/// Remove semicolons after the closing brace of a non-empty function.
/// Remove semicolons after the closing braces of functions and
/// constructors/destructors.
/// \warning
/// Setting this option to ``true`` could lead to incorrect code formatting
/// due to clang-format's lack of complete semantic information. As such,
Expand Down Expand Up @@ -4804,6 +4815,8 @@ struct FormatStyle {
AlignConsecutiveMacros == R.AlignConsecutiveMacros &&
AlignConsecutiveShortCaseStatements ==
R.AlignConsecutiveShortCaseStatements &&
AlignConsecutiveTableGenCondOperatorColons ==
R.AlignConsecutiveTableGenCondOperatorColons &&
AlignEscapedNewlines == R.AlignEscapedNewlines &&
AlignOperands == R.AlignOperands &&
AlignTrailingComments == R.AlignTrailingComments &&
Expand Down
13 changes: 13 additions & 0 deletions clang/include/clang/Sema/Scope.h
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,19 @@ class Scope {
return getFlags() & Scope::OpenACCComputeConstructScope;
}

bool isInOpenACCComputeConstructScope() const {
for (const Scope *S = this; S; S = S->getParent()) {
if (S->getFlags() & Scope::OpenACCComputeConstructScope)
return true;
else if (S->getFlags() &
(Scope::FnScope | Scope::ClassScope | Scope::BlockScope |
Scope::TemplateParamScope | Scope::FunctionPrototypeScope |
Scope::AtCatchScope | Scope::ObjCMethodScope))
return false;
}
return false;
}

/// Determine whether this scope is a while/do/for statement, which can have
/// continue statements embedded into it.
bool isContinueScope() const {
Expand Down
9 changes: 9 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -4883,6 +4883,12 @@ class Sema final {
bool checkCommonAttributeFeatures(const Stmt *S, const ParsedAttr &A,
bool SkipArgCountCheck = false);

/// Map any API notes provided for this declaration to attributes on the
/// declaration.
///
/// Triggered by declaration-attribute processing.
void ProcessAPINotes(Decl *D);

/// Determine if type T is a valid subject for a nonnull and similar
/// attributes. By default, we look through references (the behavior used by
/// nonnull), but if the second parameter is true, then we treat a reference
Expand Down Expand Up @@ -14057,6 +14063,7 @@ class Sema final {
bool CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
bool CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall);
bool CheckRISCVLMUL(CallExpr *TheCall, unsigned ArgNum);
bool CheckRISCVBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
CallExpr *TheCall);
Expand Down Expand Up @@ -14122,6 +14129,8 @@ class Sema final {

bool CheckPPCMMAType(QualType Type, SourceLocation TypeLoc);

bool SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res);
bool SemaBuiltinVectorToScalarMath(CallExpr *TheCall);
bool SemaBuiltinElementwiseMath(CallExpr *TheCall);
bool SemaBuiltinElementwiseTernaryMath(CallExpr *TheCall);
bool PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ enum class ScanningOptimizations {
/// Remove unused -ivfsoverlay arguments.
VFS = 4,

DSS_LAST_BITMASK_ENUM(VFS),
/// Canonicalize -D and -U options.
Macros = 8,

DSS_LAST_BITMASK_ENUM(Macros),
Default = All
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,8 @@ struct ModuleDeps {
BuildInfo;
};

using PrebuiltModuleVFSMapT = llvm::StringMap<llvm::StringSet<>>;

class ModuleDepCollector;

/// Callback that records textual includes and direct modular includes/imports
Expand Down Expand Up @@ -214,6 +216,7 @@ class ModuleDepCollector final : public DependencyCollector {
CompilerInstance &ScanInstance, DependencyConsumer &C,
DependencyActionController &Controller,
CompilerInvocation OriginalCI,
PrebuiltModuleVFSMapT PrebuiltModuleVFSMap,
ScanningOptimizations OptimizeArgs, bool EagerLoadModules,
bool IsStdModuleP1689Format);

Expand All @@ -233,6 +236,8 @@ class ModuleDepCollector final : public DependencyCollector {
DependencyConsumer &Consumer;
/// Callbacks for computing dependency information.
DependencyActionController &Controller;
/// Mapping from prebuilt AST files to their sorted list of VFS overlay files.
PrebuiltModuleVFSMapT PrebuiltModuleVFSMap;
/// Path to the main source file.
std::string MainFile;
/// Hash identifying the compilation conditions of the current TU.
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 @@ -88,6 +88,7 @@ add_clang_library(clangAST
Interp/Record.cpp
Interp/Source.cpp
Interp/State.cpp
Interp/InterpShared.cpp
ItaniumCXXABI.cpp
ItaniumMangle.cpp
JSONNodeDumper.cpp
Expand Down
156 changes: 112 additions & 44 deletions clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@
#include "Context.h"
#include "Floating.h"
#include "Function.h"
#include "InterpShared.h"
#include "PrimType.h"
#include "Program.h"
#include "clang/AST/Attr.h"

using namespace clang;
using namespace clang::interp;
Expand Down Expand Up @@ -658,19 +660,16 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;
}

// Both LHS and RHS might _not_ be of complex type, but one of them
// needs to be.
const Expr *LHS = E->getLHS();
const Expr *RHS = E->getRHS();
PrimType LHSElemT = this->classifyComplexElementType(LHS->getType());
PrimType RHSElemT = this->classifyComplexElementType(RHS->getType());

unsigned LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
unsigned RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
PrimType ResultElemT = this->classifyComplexElementType(E->getType());
unsigned ResultOffset = ~0u;
if (!this->DiscardResult)
if (!DiscardResult)
ResultOffset = this->allocateLocalPrimitive(E, PT_Ptr, true, false);

assert(LHSElemT == RHSElemT);

// Save result pointer in ResultOffset
if (!this->DiscardResult) {
if (!this->emitDupPtr(E))
Expand All @@ -680,16 +679,64 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
}

// Evaluate LHS and save value to LHSOffset.
if (!this->visit(LHS))
return false;
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
return false;
bool LHSIsComplex;
unsigned LHSOffset;
if (LHS->getType()->isAnyComplexType()) {
LHSIsComplex = true;
LHSOffset = this->allocateLocalPrimitive(LHS, PT_Ptr, true, false);
if (!this->visit(LHS))
return false;
if (!this->emitSetLocal(PT_Ptr, LHSOffset, E))
return false;
} else {
LHSIsComplex = false;
PrimType LHST = classifyPrim(LHS->getType());
LHSOffset = this->allocateLocalPrimitive(LHS, LHST, true, false);
if (!this->visit(LHS))
return false;
if (!this->emitSetLocal(LHST, LHSOffset, E))
return false;
}

// Same with RHS.
if (!this->visit(RHS))
return false;
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
return false;
bool RHSIsComplex;
unsigned RHSOffset;
if (RHS->getType()->isAnyComplexType()) {
RHSIsComplex = true;
RHSOffset = this->allocateLocalPrimitive(RHS, PT_Ptr, true, false);
if (!this->visit(RHS))
return false;
if (!this->emitSetLocal(PT_Ptr, RHSOffset, E))
return false;
} else {
RHSIsComplex = false;
PrimType RHST = classifyPrim(RHS->getType());
RHSOffset = this->allocateLocalPrimitive(RHS, RHST, true, false);
if (!this->visit(RHS))
return false;
if (!this->emitSetLocal(RHST, RHSOffset, E))
return false;
}

// For both LHS and RHS, either load the value from the complex pointer, or
// directly from the local variable. For index 1 (i.e. the imaginary part),
// just load 0 and do the operation anyway.
auto loadComplexValue = [this](bool IsComplex, unsigned ElemIndex,
unsigned Offset, const Expr *E) -> bool {
if (IsComplex) {
if (!this->emitGetLocal(PT_Ptr, Offset, E))
return false;
if (!this->emitConstUint8(ElemIndex, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;
return this->emitLoadPop(classifyComplexElementType(E->getType()), E);
}
if (ElemIndex == 0)
return this->emitGetLocal(classifyPrim(E->getType()), Offset, E);
return this->visitZeroInitializer(classifyPrim(E->getType()), E->getType(),
E);
};

// Now we can get pointers to the LHS and RHS from the offsets above.
BinaryOperatorKind Op = E->getOpcode();
Expand All @@ -700,41 +747,29 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {
return false;
}

if (!this->emitGetLocal(PT_Ptr, LHSOffset, E))
return false;
if (!this->emitConstUint8(ElemIndex, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;
if (!this->emitLoadPop(LHSElemT, E))
if (!loadComplexValue(LHSIsComplex, ElemIndex, LHSOffset, LHS))
return false;

if (!this->emitGetLocal(PT_Ptr, RHSOffset, E))
return false;
if (!this->emitConstUint8(ElemIndex, E))
return false;
if (!this->emitArrayElemPtrPopUint8(E))
return false;
if (!this->emitLoadPop(RHSElemT, E))
if (!loadComplexValue(RHSIsComplex, ElemIndex, RHSOffset, RHS))
return false;

// The actual operation.
switch (Op) {
case BO_Add:
if (LHSElemT == PT_Float) {
if (ResultElemT == PT_Float) {
if (!this->emitAddf(getRoundingMode(E), E))
return false;
} else {
if (!this->emitAdd(LHSElemT, E))
if (!this->emitAdd(ResultElemT, E))
return false;
}
break;
case BO_Sub:
if (LHSElemT == PT_Float) {
if (ResultElemT == PT_Float) {
if (!this->emitSubf(getRoundingMode(E), E))
return false;
} else {
if (!this->emitSub(LHSElemT, E))
if (!this->emitSub(ResultElemT, E))
return false;
}
break;
Expand All @@ -745,10 +780,10 @@ bool ByteCodeExprGen<Emitter>::VisitComplexBinOp(const BinaryOperator *E) {

if (!this->DiscardResult) {
// Initialize array element with the value we just computed.
if (!this->emitInitElemPop(LHSElemT, ElemIndex, E))
if (!this->emitInitElemPop(ResultElemT, ElemIndex, E))
return false;
} else {
if (!this->emitPop(LHSElemT, E))
if (!this->emitPop(ResultElemT, E))
return false;
}
}
Expand Down Expand Up @@ -1644,13 +1679,24 @@ bool ByteCodeExprGen<Emitter>::VisitCompoundLiteralExpr(

std::optional<PrimType> T = classify(E->getType());
if (E->isFileScope()) {
// Avoid creating a variable if this is a primitive RValue anyway.
if (T && !E->isLValue())
return this->delegate(Init);

if (std::optional<unsigned> GlobalIndex = P.createGlobal(E)) {
if (classify(E->getType()))
return this->visit(Init);
if (!this->emitGetPtrGlobal(*GlobalIndex, E))
return false;

if (T) {
if (!this->visit(Init))
return false;
return this->emitInitGlobal(*T, *GlobalIndex, E);
}

return this->visitInitializer(Init);
}

return false;
}

// Otherwise, use a local variable.
Expand Down Expand Up @@ -1696,6 +1742,9 @@ bool ByteCodeExprGen<Emitter>::VisitLambdaExpr(const LambdaExpr *E) {
const Expr *Init = *CaptureInitIt;
++CaptureInitIt;

if (!Init)
continue;

if (std::optional<PrimType> T = classify(Init)) {
if (!this->visit(Init))
return false;
Expand Down Expand Up @@ -2656,6 +2705,7 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
QualType ReturnType = E->getCallReturnType(Ctx.getASTContext());
std::optional<PrimType> T = classify(ReturnType);
bool HasRVO = !ReturnType->isVoidType() && !T;
const FunctionDecl *FuncDecl = E->getDirectCallee();

if (HasRVO) {
if (DiscardResult) {
Expand All @@ -2667,23 +2717,29 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
return false;
}
} else {
assert(Initializing);
// We need the result. Prepare a pointer to return or
// dup the current one.
if (!Initializing) {
if (std::optional<unsigned> LocalIndex = allocateLocal(E)) {
if (!this->emitGetPtrLocal(*LocalIndex, E))
return false;
}
}
if (!this->emitDupPtr(E))
return false;
}
}

auto Args = E->arguments();
auto Args = llvm::ArrayRef(E->getArgs(), E->getNumArgs());
// Calling a static operator will still
// pass the instance, but we don't need it.
// Discard it here.
if (isa<CXXOperatorCallExpr>(E)) {
if (const auto *MD =
dyn_cast_if_present<CXXMethodDecl>(E->getDirectCallee());
if (const auto *MD = dyn_cast_if_present<CXXMethodDecl>(FuncDecl);
MD && MD->isStatic()) {
if (!this->discard(E->getArg(0)))
return false;
Args = drop_begin(Args, 1);
Args = Args.drop_front();
}
}

Expand All @@ -2693,13 +2749,25 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
return false;
}

llvm::BitVector NonNullArgs = collectNonNullArgs(FuncDecl, Args);
// Put arguments on the stack.
unsigned ArgIndex = 0;
for (const auto *Arg : Args) {
if (!this->visit(Arg))
return false;

// If we know the callee already, check the known parametrs for nullability.
if (FuncDecl && NonNullArgs[ArgIndex]) {
PrimType ArgT = classify(Arg).value_or(PT_Ptr);
if (ArgT == PT_Ptr || ArgT == PT_FnPtr) {
if (!this->emitCheckNonNullArg(ArgT, Arg))
return false;
}
}
++ArgIndex;
}

if (const FunctionDecl *FuncDecl = E->getDirectCallee()) {
if (FuncDecl) {
const Function *Func = getFunction(FuncDecl);
if (!Func)
return false;
Expand Down Expand Up @@ -2748,7 +2816,7 @@ bool ByteCodeExprGen<Emitter>::VisitCallExpr(const CallExpr *E) {
if (!this->visit(E->getCallee()))
return false;

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

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/AST/Interp/Context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isReferenceType() || T->isPointerType())
return PT_Ptr;

if (const auto *AT = dyn_cast<AtomicType>(T))
if (const auto *AT = T->getAs<AtomicType>())
return classify(AT->getValueType());

if (const auto *DT = dyn_cast<DecltypeType>(T))
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/AST/Interp/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
#ifndef LLVM_CLANG_AST_INTERP_FUNCTION_H
#define LLVM_CLANG_AST_INTERP_FUNCTION_H

#include "Source.h"
#include "Descriptor.h"
#include "Source.h"
#include "clang/AST/ASTLambda.h"
#include "clang/AST/Attr.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/raw_ostream.h"

Expand Down Expand Up @@ -108,6 +109,8 @@ class Function final {
/// Checks if the first argument is a RVO pointer.
bool hasRVO() const { return HasRVO; }

bool hasNonNullAttr() const { return getDecl()->hasAttr<NonNullAttr>(); }

/// Range over the scope blocks.
llvm::iterator_range<llvm::SmallVector<Scope, 2>::const_iterator>
scopes() const {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/AST/Interp/FunctionPointer.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class FunctionPointer final {
FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }

const Function *getFunction() const { return Func; }
bool isZero() const { return !Func; }

APValue toAPValue() const {
if (!Func)
Expand Down
29 changes: 27 additions & 2 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
//===----------------------------------------------------------------------===//

#include "Interp.h"
#include <limits>
#include <vector>
#include "Function.h"
#include "InterpFrame.h"
#include "InterpShared.h"
#include "InterpStack.h"
#include "Opcode.h"
#include "PrimType.h"
Expand All @@ -22,6 +21,10 @@
#include "clang/AST/Expr.h"
#include "clang/AST/ExprCXX.h"
#include "llvm/ADT/APSInt.h"
#include <limits>
#include <vector>

using namespace clang;

using namespace clang;
using namespace clang::interp;
Expand Down Expand Up @@ -622,6 +625,28 @@ bool CheckDeclRef(InterpState &S, CodePtr OpPC, const DeclRefExpr *DR) {
return false;
}

bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *CE, unsigned ArgSize) {
auto Args = llvm::ArrayRef(CE->getArgs(), CE->getNumArgs());
auto NonNullArgs = collectNonNullArgs(F->getDecl(), Args);
unsigned Offset = 0;
unsigned Index = 0;
for (const Expr *Arg : Args) {
if (NonNullArgs[Index] && Arg->getType()->isPointerType()) {
const Pointer &ArgPtr = S.Stk.peek<Pointer>(ArgSize - Offset);
if (ArgPtr.isZero()) {
const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_non_null_attribute_failed);
return false;
}
}

Offset += align(primSize(S.Ctx.classify(Arg).value_or(PT_Ptr)));
++Index;
}
return true;
}

bool Interpret(InterpState &S, APValue &Result) {
// The current stack frame when we started Interpret().
// This is being used by the ops to determine wheter
Expand Down
37 changes: 34 additions & 3 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,10 @@ bool CheckThis(InterpState &S, CodePtr OpPC, const Pointer &This);
/// Checks if a method is pure virtual.
bool CheckPure(InterpState &S, CodePtr OpPC, const CXXMethodDecl *MD);

/// Checks if all the arguments annotated as 'nonnull' are in fact not null.
bool CheckNonNullArgs(InterpState &S, CodePtr OpPC, const Function *F,
const CallExpr *CE, unsigned ArgSize);

/// Sets the given integral value to the pointer, which is of
/// a std::{weak,partial,strong}_ordering type.
bool SetThreeWayComparisonField(InterpState &S, CodePtr OpPC,
Expand Down Expand Up @@ -804,7 +808,8 @@ bool CMP3(InterpState &S, CodePtr OpPC, const ComparisonCategoryInfo *CmpInfo) {
}

assert(CmpInfo);
const auto *CmpValueInfo = CmpInfo->getValueInfo(CmpResult);
const auto *CmpValueInfo =
CmpInfo->getValueInfo(CmpInfo->makeWeakResult(CmpResult));
assert(CmpValueInfo);
assert(CmpValueInfo->hasValidIntValue());
const APSInt &IntValue = CmpValueInfo->getIntValue();
Expand Down Expand Up @@ -1043,7 +1048,7 @@ bool InitGlobal(InterpState &S, CodePtr OpPC, uint32_t I) {

/// 1) Converts the value on top of the stack to an APValue
/// 2) Sets that APValue on \Temp
/// 3) Initialized global with index \I with that
/// 3) Initializes global with index \I with that
template <PrimType Name, class T = typename PrimConv<Name>::T>
bool InitGlobalTemp(InterpState &S, CodePtr OpPC, uint32_t I,
const LifetimeExtendedTemporaryDecl *Temp) {
Expand Down Expand Up @@ -1980,6 +1985,7 @@ inline bool CallVar(InterpState &S, CodePtr OpPC, const Function *Func,

return false;
}

inline bool Call(InterpState &S, CodePtr OpPC, const Function *Func,
uint32_t VarArgSize) {
if (Func->hasThisPointer()) {
Expand Down Expand Up @@ -2083,12 +2089,25 @@ inline bool CallBI(InterpState &S, CodePtr &PC, const Function *Func,
return false;
}

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

const Function *F = FuncPtr.getFunction();
if (!F) {
const Expr *E = S.Current->getExpr(OpPC);
S.FFDiag(E, diag::note_constexpr_null_callee)
<< const_cast<Expr *>(E) << E->getSourceRange();
return false;
}
assert(F);

// Check argument nullability state.
if (F->hasNonNullAttr()) {
if (!CheckNonNullArgs(S, OpPC, F, CE, ArgSize))
return false;
}

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

Expand Down Expand Up @@ -2145,6 +2164,18 @@ inline bool OffsetOf(InterpState &S, CodePtr OpPC, const OffsetOfExpr *E) {
return true;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
const T &Arg = S.Stk.peek<T>();
if (!Arg.isZero())
return true;

const SourceLocation &Loc = S.Current->getLocation(OpPC);
S.CCEDiag(Loc, diag::note_non_null_attribute_failed);

return false;
}

//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
Expand Down
288 changes: 155 additions & 133 deletions clang/lib/AST/Interp/InterpBuiltin.cpp

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions clang/lib/AST/Interp/InterpShared.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//===--- InterpShared.cpp ---------------------------------------*- 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
//
//===----------------------------------------------------------------------===//

#include "InterpShared.h"
#include "clang/AST/Attr.h"
#include "llvm/ADT/BitVector.h"

namespace clang {
namespace interp {

llvm::BitVector collectNonNullArgs(const FunctionDecl *F,
const llvm::ArrayRef<const Expr *> &Args) {
llvm::BitVector NonNullArgs;
if (!F)
return NonNullArgs;

assert(F);
NonNullArgs.resize(Args.size());

for (const auto *Attr : F->specific_attrs<NonNullAttr>()) {
if (!Attr->args_size()) {
NonNullArgs.set();
break;
} else
for (auto Idx : Attr->args()) {
unsigned ASTIdx = Idx.getASTIndex();
if (ASTIdx >= Args.size())
continue;
NonNullArgs[ASTIdx] = true;
}
}

return NonNullArgs;
}

} // namespace interp
} // namespace clang
26 changes: 26 additions & 0 deletions clang/lib/AST/Interp/InterpShared.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===--- InterpShared.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_LIB_AST_INTERP_SHARED_H
#define LLVM_CLANG_LIB_AST_INTERP_SHARED_H

#include "llvm/ADT/BitVector.h"

namespace clang {
class FunctionDecl;
class Expr;

namespace interp {

llvm::BitVector collectNonNullArgs(const FunctionDecl *F,
const llvm::ArrayRef<const Expr *> &Args);

} // namespace interp
} // namespace clang

#endif
7 changes: 6 additions & 1 deletion clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ def CallBI : Opcode {
}

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

Expand Down Expand Up @@ -706,3 +706,8 @@ def InvalidDeclRef : Opcode {
}

def ArrayDecay : Opcode;

def CheckNonNullArg : Opcode {
let Types = [PtrTypeClass];
let HasGroup = 1;
}
18 changes: 4 additions & 14 deletions clang/lib/Analysis/FlowSensitive/DataflowEnvironment.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -361,8 +361,8 @@ getFieldsGlobalsAndFuncs(const Stmt &S, FieldSet &Fields,
if (const auto *FD = dyn_cast<FieldDecl>(VD))
Fields.insert(FD);
} else if (auto *InitList = dyn_cast<InitListExpr>(&S)) {
if (InitList->getType()->isRecordType())
for (const auto *FD : getFieldsForInitListExpr(InitList))
if (RecordDecl *RD = InitList->getType()->getAsRecordDecl())
for (const auto *FD : getFieldsForInitListExpr(RD))
Fields.insert(FD);
}
}
Expand Down Expand Up @@ -1104,22 +1104,12 @@ RecordStorageLocation *getBaseObjectLocation(const MemberExpr &ME,
return Env.get<RecordStorageLocation>(*Base);
}

std::vector<const FieldDecl *>
getFieldsForInitListExpr(const InitListExpr *InitList) {
const RecordDecl *RD = InitList->getType()->getAsRecordDecl();
assert(RD != nullptr);

std::vector<const FieldDecl *> Fields;

if (InitList->getType()->isUnionType()) {
Fields.push_back(InitList->getInitializedFieldInUnion());
return Fields;
}

std::vector<FieldDecl *> getFieldsForInitListExpr(const RecordDecl *RD) {
// Unnamed bitfields are only used for padding and do not appear in
// `InitListExpr`'s inits. However, those fields do appear in `RecordDecl`'s
// field list, and we thus need to remove them before mapping inits to
// fields to avoid mapping inits to the wrongs fields.
std::vector<FieldDecl *> Fields;
llvm::copy_if(
RD->fields(), std::back_inserter(Fields),
[](const FieldDecl *Field) { return !Field->isUnnamedBitfield(); });
Expand Down
31 changes: 14 additions & 17 deletions clang/lib/Analysis/FlowSensitive/Transfer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -663,10 +663,17 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
void VisitInitListExpr(const InitListExpr *S) {
QualType Type = S->getType();

if (!Type->isRecordType()) {
// Until array initialization is implemented, we don't need to care about
// cases where `getNumInits() > 1`.
if (S->getNumInits() == 1)
if (Type->isUnionType()) {
// FIXME: Initialize unions properly.
if (auto *Val = Env.createValue(Type))
Env.setValue(*S, *Val);
return;
}

if (!Type->isStructureOrClassType()) {
// Until array initialization is implemented, we skip arrays and don't
// need to care about cases where `getNumInits() > 1`.
if (!Type->isArrayType() && S->getNumInits() == 1)
propagateValueOrStorageLocation(*S->getInit(0), *S, Env);
return;
}
Expand All @@ -681,9 +688,10 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
llvm::DenseMap<const ValueDecl *, StorageLocation *> FieldLocs;

// This only contains the direct fields for the given type.
std::vector<const FieldDecl *> FieldsForInit = getFieldsForInitListExpr(S);
std::vector<FieldDecl *> FieldsForInit =
getFieldsForInitListExpr(Type->getAsRecordDecl());

// `S->inits()` contains all the initializer expressions, including the
// `S->inits()` contains all the initializer epressions, including the
// ones for direct base classes.
auto Inits = S->inits();
size_t InitIdx = 0;
Expand Down Expand Up @@ -723,17 +731,6 @@ class TransferVisitor : public ConstStmtVisitor<TransferVisitor> {
FieldLocs.insert({Field, &Loc});
}

// In the case of a union, we don't in general have initializers for all
// of the fields. Create storage locations for the remaining fields (but
// don't associate them with values).
if (Type->isUnionType()) {
for (const FieldDecl *Field :
Env.getDataflowAnalysisContext().getModeledFields(Type)) {
if (auto [it, inserted] = FieldLocs.insert({Field, nullptr}); inserted)
it->second = &Env.createStorageLocation(Field->getType());
}
}

// Check that we satisfy the invariant that a `RecordStorageLoation`
// contains exactly the set of modeled fields for that type.
// `ModeledFields` includes fields from all the bases, but only the
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Basic/Targets/AMDGPU.h
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,10 @@ class LLVM_LIBRARY_VISIBILITY AMDGPUTargetInfo final : public TargetInfo {
// value ~0.
uint64_t getNullPointerValue(LangAS AS) const override {
// FIXME: Also should handle region.
return (AS == LangAS::opencl_local || AS == LangAS::opencl_private)
? ~0 : 0;
return (AS == LangAS::opencl_local || AS == LangAS::opencl_private ||
AS == LangAS::sycl_local || AS == LangAS::sycl_private)
? ~0
: 0;
}

void setAuxTarget(const TargetInfo *Aux) override;
Expand Down
51 changes: 51 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include "llvm/IR/IntrinsicsAMDGPU.h"
#include "llvm/IR/IntrinsicsARM.h"
#include "llvm/IR/IntrinsicsBPF.h"
#include "llvm/IR/IntrinsicsDirectX.h"
#include "llvm/IR/IntrinsicsHexagon.h"
#include "llvm/IR/IntrinsicsNVPTX.h"
#include "llvm/IR/IntrinsicsPowerPC.h"
Expand Down Expand Up @@ -5982,6 +5983,10 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
llvm_unreachable("Bad evaluation kind in EmitBuiltinExpr");
}

// EmitHLSLBuiltinExpr will check getLangOpts().HLSL
if (Value *V = EmitHLSLBuiltinExpr(BuiltinID, E))
return RValue::get(V);

if (getLangOpts().HIPStdPar && getLangOpts().CUDAIsDevice)
return EmitHipStdParUnsupportedBuiltin(this, FD);

Expand Down Expand Up @@ -17959,6 +17964,52 @@ llvm::Value *CodeGenFunction::EmitScalarOrConstFoldImmArg(unsigned ICEArguments,
return Arg;
}

Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
if (!getLangOpts().HLSL)
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_dot: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
Value *Op1 = EmitScalarExpr(E->getArg(1));
llvm::Type *T0 = Op0->getType();
llvm::Type *T1 = Op1->getType();
if (!T0->isVectorTy() && !T1->isVectorTy()) {
if (T0->isFloatingPointTy())
return Builder.CreateFMul(Op0, Op1, "dx.dot");

if (T0->isIntegerTy())
return Builder.CreateMul(Op0, Op1, "dx.dot");

// Bools should have been promoted
llvm_unreachable(
"Scalar dot product is only supported on ints and floats.");
}
// A VectorSplat should have happened
assert(T0->isVectorTy() && T1->isVectorTy() &&
"Dot product of vector and scalar is not supported.");

// A vector sext or sitofp should have happened
assert(T0->getScalarType() == T1->getScalarType() &&
"Dot product of vectors need the same element types.");

[[maybe_unused]] auto *VecTy0 =
E->getArg(0)->getType()->getAs<VectorType>();
[[maybe_unused]] auto *VecTy1 =
E->getArg(1)->getType()->getAs<VectorType>();
// A HLSLVectorTruncation should have happend
assert(VecTy0->getNumElements() == VecTy1->getNumElements() &&
"Dot product requires vectors to be of the same size.");

return Builder.CreateIntrinsic(
/*ReturnType*/ T0->getScalarType(), Intrinsic::dx_dot,
ArrayRef<Value *>{Op0, Op1}, nullptr, "dx.dot");
} break;
}
return nullptr;
}

Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
const CallExpr *E) {
llvm::AtomicOrdering AO = llvm::AtomicOrdering::SequentiallyConsistent;
Expand Down
28 changes: 14 additions & 14 deletions clang/lib/CodeGen/CGRecordLayoutBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ struct CGRecordLowering {
CGRecordLowering(CodeGenTypes &Types, const RecordDecl *D, bool Packed);
// Short helper routines.
/// Constructs a MemberInfo instance from an offset and llvm::Type *.
MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
static MemberInfo StorageInfo(CharUnits Offset, llvm::Type *Data) {
return MemberInfo(Offset, MemberInfo::Field, Data);
}

Expand All @@ -104,7 +104,7 @@ struct CGRecordLowering {
/// fields of the same formal type. We want to emit a layout with
/// these discrete storage units instead of combining them into a
/// continuous run.
bool isDiscreteBitFieldABI() {
bool isDiscreteBitFieldABI() const {
return Context.getTargetInfo().getCXXABI().isMicrosoft() ||
D->isMsStruct(Context);
}
Expand All @@ -121,60 +121,60 @@ struct CGRecordLowering {
/// other bases, which complicates layout in specific ways.
///
/// Note specifically that the ms_struct attribute doesn't change this.
bool isOverlappingVBaseABI() {
bool isOverlappingVBaseABI() const {
return !Context.getTargetInfo().getCXXABI().isMicrosoft();
}

/// Wraps llvm::Type::getIntNTy with some implicit arguments.
llvm::Type *getIntNType(uint64_t NumBits) {
llvm::Type *getIntNType(uint64_t NumBits) const {
unsigned AlignedBits = llvm::alignTo(NumBits, Context.getCharWidth());
return llvm::Type::getIntNTy(Types.getLLVMContext(), AlignedBits);
}
/// Get the LLVM type sized as one character unit.
llvm::Type *getCharType() {
llvm::Type *getCharType() const {
return llvm::Type::getIntNTy(Types.getLLVMContext(),
Context.getCharWidth());
}
/// Gets an llvm type of size NumChars and alignment 1.
llvm::Type *getByteArrayType(CharUnits NumChars) {
llvm::Type *getByteArrayType(CharUnits NumChars) const {
assert(!NumChars.isZero() && "Empty byte arrays aren't allowed.");
llvm::Type *Type = getCharType();
return NumChars == CharUnits::One() ? Type :
(llvm::Type *)llvm::ArrayType::get(Type, NumChars.getQuantity());
}
/// Gets the storage type for a field decl and handles storage
/// for itanium bitfields that are smaller than their declared type.
llvm::Type *getStorageType(const FieldDecl *FD) {
llvm::Type *getStorageType(const FieldDecl *FD) const {
llvm::Type *Type = Types.ConvertTypeForMem(FD->getType());
if (!FD->isBitField()) return Type;
if (isDiscreteBitFieldABI()) return Type;
return getIntNType(std::min(FD->getBitWidthValue(Context),
(unsigned)Context.toBits(getSize(Type))));
}
/// Gets the llvm Basesubobject type from a CXXRecordDecl.
llvm::Type *getStorageType(const CXXRecordDecl *RD) {
llvm::Type *getStorageType(const CXXRecordDecl *RD) const {
return Types.getCGRecordLayout(RD).getBaseSubobjectLLVMType();
}
CharUnits bitsToCharUnits(uint64_t BitOffset) {
CharUnits bitsToCharUnits(uint64_t BitOffset) const {
return Context.toCharUnitsFromBits(BitOffset);
}
CharUnits getSize(llvm::Type *Type) {
CharUnits getSize(llvm::Type *Type) const {
return CharUnits::fromQuantity(DataLayout.getTypeAllocSize(Type));
}
CharUnits getAlignment(llvm::Type *Type) {
CharUnits getAlignment(llvm::Type *Type) const {
return CharUnits::fromQuantity(DataLayout.getABITypeAlign(Type));
}
bool isZeroInitializable(const FieldDecl *FD) {
bool isZeroInitializable(const FieldDecl *FD) const {
return Types.isZeroInitializable(FD->getType());
}
bool isZeroInitializable(const RecordDecl *RD) {
bool isZeroInitializable(const RecordDecl *RD) const {
return Types.isZeroInitializable(RD);
}
void appendPaddingBytes(CharUnits Size) {
if (!Size.isZero())
FieldTypes.push_back(getByteArrayType(Size));
}
uint64_t getFieldBitOffset(const FieldDecl *FD) {
uint64_t getFieldBitOffset(const FieldDecl *FD) const {
return Layout.getFieldOffset(FD->getFieldIndex());
}
// Layout routines.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -4405,6 +4405,7 @@ class CodeGenFunction : public CodeGenTypeCache {
llvm::Value *EmitX86BuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitPPCBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitAMDGPUBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitHLSLBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
llvm::Value *EmitScalarOrConstFoldImmArg(unsigned ICEArguments, unsigned Idx,
const CallExpr *E);
llvm::Value *EmitSystemZBuiltinExpr(unsigned BuiltinID, const CallExpr *E);
Expand Down
27 changes: 14 additions & 13 deletions clang/lib/CodeGen/CodeGenPGO.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {
llvm::DenseMap<const Stmt *, unsigned> &CounterMap;
/// The next bitmap byte index to assign.
unsigned NextMCDCBitmapIdx;
/// The state of MC/DC Coverage in this function.
MCDC::State &MCDCState;
/// Maximum number of supported MC/DC conditions in a boolean expression.
unsigned MCDCMaxCond;
Expand Down Expand Up @@ -311,7 +312,7 @@ struct MapRegionCounters : public RecursiveASTVisitor<MapRegionCounters> {

// Otherwise, allocate the number of bytes required for the bitmap
// based on the number of conditions. Must be at least 1-byte long.
MCDCState.BitmapMap[BinOp] = NextMCDCBitmapIdx;
MCDCState.DecisionByStmt[BinOp].BitmapIdx = NextMCDCBitmapIdx;
unsigned SizeInBits = std::max<unsigned>(1L << NumCond, CHAR_BIT);
NextMCDCBitmapIdx += SizeInBits / CHAR_BIT;
}
Expand Down Expand Up @@ -1034,7 +1035,7 @@ void CodeGenPGO::emitCounterRegionMapping(const Decl *D) {

std::string CoverageMapping;
llvm::raw_string_ostream OS(CoverageMapping);
RegionCondIDMap.reset(new llvm::DenseMap<const Stmt *, int16_t>);
RegionMCDCState->BranchByStmt.clear();
CoverageMappingGen MappingGen(
*CGM.getCoverageMapping(), CGM.getContext().getSourceManager(),
CGM.getLangOpts(), RegionCounterMap.get(), RegionMCDCState.get());
Expand Down Expand Up @@ -1142,12 +1143,12 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,

S = S->IgnoreParens();

auto ExprMCDCBitmapMapIterator = RegionMCDCState->BitmapMap.find(S);
if (ExprMCDCBitmapMapIterator == RegionMCDCState->BitmapMap.end())
auto DecisionStateIter = RegionMCDCState->DecisionByStmt.find(S);
if (DecisionStateIter == RegionMCDCState->DecisionByStmt.end())
return;

// Extract the ID of the global bitmap associated with this expression.
unsigned MCDCTestVectorBitmapID = ExprMCDCBitmapMapIterator->second;
// Extract the offset of the global bitmap associated with this expression.
unsigned MCDCTestVectorBitmapOffset = DecisionStateIter->second.BitmapIdx;
auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

// Emit intrinsic responsible for updating the global bitmap corresponding to
Expand All @@ -1158,7 +1159,7 @@ void CodeGenPGO::emitMCDCTestVectorBitmapUpdate(CGBuilderTy &Builder,
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(RegionMCDCState->BitmapBytes),
Builder.getInt32(MCDCTestVectorBitmapID),
Builder.getInt32(MCDCTestVectorBitmapOffset),
MCDCCondBitmapAddr.getPointer()};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_tvbitmap_update), Args);
Expand All @@ -1171,7 +1172,7 @@ void CodeGenPGO::emitMCDCCondBitmapReset(CGBuilderTy &Builder, const Expr *S,

S = S->IgnoreParens();

if (!RegionMCDCState->BitmapMap.contains(S))
if (!RegionMCDCState->DecisionByStmt.contains(S))
return;

// Emit intrinsic that resets a dedicated temporary value on the stack to 0.
Expand All @@ -1193,13 +1194,13 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
// also make debugging a bit easier.
S = CodeGenFunction::stripCond(S);

auto ExprMCDCConditionIDMapIterator = RegionMCDCState->CondIDMap.find(S);
if (ExprMCDCConditionIDMapIterator == RegionMCDCState->CondIDMap.end())
auto BranchStateIter = RegionMCDCState->BranchByStmt.find(S);
if (BranchStateIter == RegionMCDCState->BranchByStmt.end())
return;

// Extract the ID of the condition we are setting in the bitmap.
auto CondID = ExprMCDCConditionIDMapIterator->second;
assert(CondID >= 0 && "Condition has no ID!");
const auto &Branch = BranchStateIter->second;
assert(Branch.ID >= 0 && "Condition has no ID!");

auto *I8PtrTy = llvm::PointerType::getUnqual(CGM.getLLVMContext());

Expand All @@ -1208,7 +1209,7 @@ void CodeGenPGO::emitMCDCCondBitmapUpdate(CGBuilderTy &Builder, const Expr *S,
// the resulting value is used to update the boolean expression's bitmap.
llvm::Value *Args[5] = {llvm::ConstantExpr::getBitCast(FuncNameVar, I8PtrTy),
Builder.getInt64(FunctionHash),
Builder.getInt32(CondID),
Builder.getInt32(Branch.ID),
MCDCCondBitmapAddr.getPointer(), Val};
Builder.CreateCall(
CGM.getIntrinsic(llvm::Intrinsic::instrprof_mcdc_condbitmap_update),
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/CodeGen/CodeGenPGO.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ class CodeGenPGO {
unsigned NumRegionCounters;
uint64_t FunctionHash;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionCounterMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, unsigned>> RegionMCDCBitmapMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, int16_t>> RegionCondIDMap;
std::unique_ptr<llvm::DenseMap<const Stmt *, uint64_t>> StmtCountMap;
std::unique_ptr<llvm::InstrProfRecord> ProfRecord;
std::unique_ptr<MCDC::State> RegionMCDCState;
Expand Down
63 changes: 36 additions & 27 deletions clang/lib/CodeGen/CoverageMappingGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,6 @@ struct MCDCCoverageBuilder {

llvm::SmallVector<mcdc::ConditionIDs> DecisionStack;
MCDC::State &MCDCState;
llvm::DenseMap<const Stmt *, mcdc::ConditionID> &CondIDs;
mcdc::ConditionID NextID = 0;
bool NotMapped = false;

Expand All @@ -699,8 +698,8 @@ struct MCDCCoverageBuilder {

public:
MCDCCoverageBuilder(CodeGenModule &CGM, MCDC::State &MCDCState)
: CGM(CGM), DecisionStack(1, DecisionStackSentinel), MCDCState(MCDCState),
CondIDs(MCDCState.CondIDMap) {}
: CGM(CGM), DecisionStack(1, DecisionStackSentinel),
MCDCState(MCDCState) {}

/// Return whether the build of the control flow map is at the top-level
/// (root) of a logical operator nest in a boolean expression prior to the
Expand All @@ -714,16 +713,16 @@ struct MCDCCoverageBuilder {

/// Set the given condition's ID.
void setCondID(const Expr *Cond, mcdc::ConditionID ID) {
CondIDs[CodeGenFunction::stripCond(Cond)] = ID;
MCDCState.BranchByStmt[CodeGenFunction::stripCond(Cond)].ID = ID;
}

/// Return the ID of a given condition.
mcdc::ConditionID getCondID(const Expr *Cond) const {
auto I = CondIDs.find(CodeGenFunction::stripCond(Cond));
if (I == CondIDs.end())
auto I = MCDCState.BranchByStmt.find(CodeGenFunction::stripCond(Cond));
if (I == MCDCState.BranchByStmt.end())
return -1;
else
return I->second;
return I->second.ID;
}

/// Return the LHS Decision ([0,0] if not set).
Expand All @@ -738,7 +737,7 @@ struct MCDCCoverageBuilder {

// If binary expression is disqualified, don't do mapping.
if (!isBuilding() &&
!MCDCState.BitmapMap.contains(CodeGenFunction::stripCond(E)))
!MCDCState.DecisionByStmt.contains(CodeGenFunction::stripCond(E)))
NotMapped = true;

// Don't go any further if we don't need to map condition IDs.
Expand All @@ -750,7 +749,7 @@ struct MCDCCoverageBuilder {
// If the operator itself has an assigned ID, this means it represents a
// larger subtree. In this case, assign that ID to its LHS node. Its RHS
// will receive a new ID below. Otherwise, assign ID+1 to LHS.
if (CondIDs.contains(CodeGenFunction::stripCond(E)))
if (MCDCState.BranchByStmt.contains(CodeGenFunction::stripCond(E)))
setCondID(E->getLHS(), getCondID(E));
else
setCondID(E->getLHS(), NextID++);
Expand Down Expand Up @@ -853,8 +852,6 @@ struct CounterCoverageMappingBuilder
return Counter::getCounter(CounterMap[S]);
}

unsigned getRegionBitmap(const Stmt *S) { return MCDCState.BitmapMap[S]; }

/// Push a region onto the stack.
///
/// Returns the index on the stack where the region was pushed. This can be
Expand Down Expand Up @@ -887,12 +884,11 @@ struct CounterCoverageMappingBuilder
return RegionStack.size() - 1;
}

size_t pushRegion(unsigned BitmapIdx, uint16_t Conditions,
size_t pushRegion(const mcdc::DecisionParameters &DecisionParams,
std::optional<SourceLocation> StartLoc = std::nullopt,
std::optional<SourceLocation> EndLoc = std::nullopt) {

RegionStack.emplace_back(mcdc::DecisionParameters{BitmapIdx, Conditions},
StartLoc, EndLoc);
RegionStack.emplace_back(DecisionParams, StartLoc, EndLoc);

return RegionStack.size() - 1;
}
Expand Down Expand Up @@ -1058,8 +1054,9 @@ struct CounterCoverageMappingBuilder
/// Create a Decision Region with a BitmapIdx and number of Conditions. This
/// type of region "contains" branch regions, one for each of the conditions.
/// The visualization tool will group everything together.
void createDecisionRegion(const Expr *C, unsigned BitmapIdx, unsigned Conds) {
popRegions(pushRegion(BitmapIdx, Conds, getStart(C), getEnd(C)));
void createDecisionRegion(const Expr *C,
const mcdc::DecisionParameters &DecisionParams) {
popRegions(pushRegion(DecisionParams, getStart(C), getEnd(C)));
}

/// Create a Branch Region around a SwitchCase for code coverage
Expand Down Expand Up @@ -1311,7 +1308,7 @@ struct CounterCoverageMappingBuilder
return;
assert(SpellingRegion(SM, NewStartLoc, EndLoc).isInSourceOrder());
handleFileExit(NewStartLoc);
size_t Index = pushRegion({}, NewStartLoc, EndLoc);
size_t Index = pushRegion(Counter{}, NewStartLoc, EndLoc);
getRegion().setSkipped(true);
handleFileExit(EndLoc);
popRegions(Index);
Expand Down Expand Up @@ -1961,6 +1958,20 @@ struct CounterCoverageMappingBuilder
subtractCounters(ParentCount, TrueCount));
}

void createDecision(const BinaryOperator *E) {
unsigned NumConds = MCDCBuilder.getTotalConditionsAndReset(E);
if (NumConds == 0)
return;

auto DecisionParams = mcdc::DecisionParameters{
MCDCState.DecisionByStmt[E].BitmapIdx,
NumConds,
};

// Create MCDC Decision Region.
createDecisionRegion(E, DecisionParams);
}

void VisitBinLAnd(const BinaryOperator *E) {
bool IsRootNode = MCDCBuilder.isIdle();

Expand All @@ -1981,11 +1992,6 @@ struct CounterCoverageMappingBuilder
// Track RHS True/False Decision.
const auto DecisionRHS = MCDCBuilder.back();

// Create MCDC Decision Region if at top-level (root).
unsigned NumConds = 0;
if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
createDecisionRegion(E, getRegionBitmap(E), NumConds);

// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);

Expand All @@ -2002,6 +2008,10 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), RHSTrueCnt,
subtractCounters(RHSExecCnt, RHSTrueCnt), DecisionRHS);

// Create MCDC Decision Region if at top-level (root).
if (IsRootNode)
createDecision(E);
}

// Determine whether the right side of OR operation need to be visited.
Expand Down Expand Up @@ -2034,11 +2044,6 @@ struct CounterCoverageMappingBuilder
// Track RHS True/False Decision.
const auto DecisionRHS = MCDCBuilder.back();

// Create MCDC Decision Region if at top-level (root).
unsigned NumConds = 0;
if (IsRootNode && (NumConds = MCDCBuilder.getTotalConditionsAndReset(E)))
createDecisionRegion(E, getRegionBitmap(E), NumConds);

// Extract the RHS's Execution Counter.
Counter RHSExecCnt = getRegionCounter(E);

Expand All @@ -2059,6 +2064,10 @@ struct CounterCoverageMappingBuilder
// Create Branch Region around RHS condition.
createBranchRegion(E->getRHS(), subtractCounters(RHSExecCnt, RHSFalseCnt),
RHSFalseCnt, DecisionRHS);

// Create MCDC Decision Region if at top-level (root).
if (IsRootNode)
createDecision(E);
}

void VisitLambdaExpr(const LambdaExpr *LE) {
Expand Down
14 changes: 12 additions & 2 deletions clang/lib/CodeGen/MCDCState.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,18 @@ using namespace llvm::coverage::mcdc;
/// Per-Function MC/DC state
struct State {
unsigned BitmapBytes = 0;
llvm::DenseMap<const Stmt *, unsigned> BitmapMap;
llvm::DenseMap<const Stmt *, ConditionID> CondIDMap;

struct Decision {
unsigned BitmapIdx;
};

llvm::DenseMap<const Stmt *, Decision> DecisionByStmt;

struct Branch {
ConditionID ID;
};

llvm::DenseMap<const Stmt *, Branch> BranchByStmt;
};

} // namespace clang::CodeGen::MCDC
Expand Down
18 changes: 18 additions & 0 deletions clang/lib/CodeGen/Targets/NVPTX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
CodeGen::CodeGenModule &M) const override;
bool shouldEmitStaticExternCAliases() const override;

llvm::Constant *getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *T,
QualType QT) const override;

llvm::Type *getCUDADeviceBuiltinSurfaceDeviceType() const override {
// On the device side, surface reference is represented as an object handle
// in 64-bit integer.
Expand Down Expand Up @@ -285,6 +289,20 @@ void NVPTXTargetCodeGenInfo::addNVVMMetadata(llvm::GlobalValue *GV,
bool NVPTXTargetCodeGenInfo::shouldEmitStaticExternCAliases() const {
return false;
}

llvm::Constant *
NVPTXTargetCodeGenInfo::getNullPointer(const CodeGen::CodeGenModule &CGM,
llvm::PointerType *PT,
QualType QT) const {
auto &Ctx = CGM.getContext();
if (PT->getAddressSpace() != Ctx.getTargetAddressSpace(LangAS::opencl_local))
return llvm::ConstantPointerNull::get(PT);

auto NPT = llvm::PointerType::get(
PT->getContext(), Ctx.getTargetAddressSpace(LangAS::opencl_generic));
return llvm::ConstantExpr::getAddrSpaceCast(
llvm::ConstantPointerNull::get(NPT), PT);
}
}

void CodeGenModule::handleCUDALaunchBoundsAttr(llvm::Function *F,
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Driver/ToolChain.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,12 @@ static void getAArch64MultilibFlags(const Driver &D,
for (const auto &Ext : AArch64::Extensions)
if (FeatureSet.contains(Ext.NegFeature))
MArch.push_back(("no" + Ext.Name).str());
MArch.insert(MArch.begin(), ("-march=" + Triple.getArchName()).str());
StringRef ArchName;
for (const auto &ArchInfo : AArch64::ArchInfos)
if (FeatureSet.contains(ArchInfo->ArchFeature))
ArchName = ArchInfo->Name;
assert(!ArchName.empty() && "at least one architecture should be found");
MArch.insert(MArch.begin(), ("-march=" + ArchName).str());
Result.push_back(llvm::join(MArch, "+"));
}

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/AMDGPU.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,7 @@ void amdgpu::Linker::ConstructJob(Compilation &C, const JobAction &JA,

addLinkerCompressDebugSectionsOption(getToolChain(), Args, CmdArgs);
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);
AddLinkerInputs(getToolChain(), Inputs, Args, CmdArgs, JA);
if (C.getDriver().isUsingLTO())
addLTOOptions(getToolChain(), Args, CmdArgs, Output, Inputs[0],
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1111,8 +1111,8 @@ void Clang::AddPreprocessingOptions(Compilation &C, const JobAction &JA,
C.getActiveOffloadKinds() == Action::OFK_None) {
SmallString<128> P(llvm::sys::path::parent_path(D.InstalledDir));
llvm::sys::path::append(P, "include");
llvm::sys::path::append(P, "gpu-none-llvm");
CmdArgs.push_back("-c-isystem");
llvm::sys::path::append(P, getToolChain().getTripleString());
CmdArgs.push_back("-internal-isystem");
CmdArgs.push_back(Args.MakeArgString(P));
} else if (C.getActiveOffloadKinds() == Action::OFK_OpenMP) {
// TODO: CUDA / HIP include their own headers for some common functions
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Driver/ToolChains/Cuda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -609,6 +609,10 @@ void NVPTX::Linker::ConstructJob(Compilation &C, const JobAction &JA,
// Add paths specified in LIBRARY_PATH environment variable as -L options.
addDirectoryList(Args, CmdArgs, "-L", "LIBRARY_PATH");

// Add standard library search paths passed on the command line.
Args.AddAllArgs(CmdArgs, options::OPT_L);
getToolChain().AddFilePathLibArgs(Args, CmdArgs);

// Add paths for the default clang library path.
SmallString<256> DefaultLibPath =
llvm::sys::path::parent_path(TC.getDriver().Dir);
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Format/Format.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -915,6 +915,8 @@ template <> struct MappingTraits<FormatStyle> {
IO.mapOptional("AlignConsecutiveMacros", Style.AlignConsecutiveMacros);
IO.mapOptional("AlignConsecutiveShortCaseStatements",
Style.AlignConsecutiveShortCaseStatements);
IO.mapOptional("AlignConsecutiveTableGenCondOperatorColons",
Style.AlignConsecutiveTableGenCondOperatorColons);
IO.mapOptional("AlignEscapedNewlines", Style.AlignEscapedNewlines);
IO.mapOptional("AlignOperands", Style.AlignOperands);
IO.mapOptional("AlignTrailingComments", Style.AlignTrailingComments);
Expand Down Expand Up @@ -1420,6 +1422,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.AlignConsecutiveDeclarations = {};
LLVMStyle.AlignConsecutiveMacros = {};
LLVMStyle.AlignConsecutiveShortCaseStatements = {};
LLVMStyle.AlignConsecutiveTableGenCondOperatorColons = {};
LLVMStyle.AlignEscapedNewlines = FormatStyle::ENAS_Right;
LLVMStyle.AlignOperands = FormatStyle::OAS_Align;
LLVMStyle.AlignTrailingComments = {};
Expand Down Expand Up @@ -1591,7 +1594,7 @@ FormatStyle getLLVMStyle(FormatStyle::LanguageKind Language) {
LLVMStyle.PenaltyBreakScopeResolution = 500;
LLVMStyle.PenaltyBreakString = 1000;
LLVMStyle.PenaltyBreakTemplateDeclaration = prec::Relational;
LLVMStyle.PenaltyExcessCharacter = 1000000;
LLVMStyle.PenaltyExcessCharacter = 1'000'000;
LLVMStyle.PenaltyIndentedWhitespace = 0;
LLVMStyle.PenaltyReturnTypeOnItsOwnLine = 60;

Expand Down Expand Up @@ -1914,9 +1917,12 @@ FormatStyle getClangFormatStyle() {
FormatStyle Style = getLLVMStyle();
Style.InsertBraces = true;
Style.InsertNewlineAtEOF = true;
Style.IntegerLiteralSeparator.Decimal = 3;
Style.IntegerLiteralSeparator.DecimalMinDigits = 5;
Style.LineEnding = FormatStyle::LE_LF;
Style.RemoveBracesLLVM = true;
Style.RemoveParentheses = FormatStyle::RPS_ReturnStatement;
Style.RemoveSemicolon = true;
return Style;
}

Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Format/FormatToken.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ unsigned CommaSeparatedList::formatAfterToken(LineState &State,
// bin-packed. Add a severe penalty to this so that column layouts are
// preferred if possible.
if (!Format)
return 10000;
return 10'000;

// Format the entire list.
unsigned Penalty = 0;
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Format/UnwrappedLineFormatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1221,7 +1221,7 @@ class OptimizingLineFormatter : public LineFormatter {
// While not empty, take first element and follow edges.
while (!Queue.empty()) {
// Quit if we still haven't found a solution by now.
if (Count > 25000000)
if (Count > 25'000'000)
return 0;

Penalty = Queue.top().first.first;
Expand All @@ -1235,7 +1235,7 @@ class OptimizingLineFormatter : public LineFormatter {

// Cut off the analysis of certain solutions if the analysis gets too
// complex. See description of IgnoreStackForComparison.
if (Count > 50000)
if (Count > 50'000)
Node->State.IgnoreStackForComparison = true;

if (!Seen.insert(&Node->State).second) {
Expand Down
18 changes: 15 additions & 3 deletions clang/lib/Format/WhitespaceManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@ const tooling::Replacements &WhitespaceManager::generateReplacements() {
alignConsecutiveDeclarations();
alignConsecutiveBitFields();
alignConsecutiveAssignments();
if (Style.isTableGen())
alignConsecutiveTableGenCondOperatorColons();
alignChainedConditionals();
alignTrailingComments();
alignEscapedNewlines();
Expand Down Expand Up @@ -849,7 +851,12 @@ void WhitespaceManager::alignConsecutiveAssignments() {
}

void WhitespaceManager::alignConsecutiveBitFields() {
if (!Style.AlignConsecutiveBitFields.Enabled)
alignConsecutiveColons(Style.AlignConsecutiveBitFields, TT_BitFieldColon);
}

void WhitespaceManager::alignConsecutiveColons(
const FormatStyle::AlignConsecutiveStyle &AlignStyle, TokenType Type) {
if (!AlignStyle.Enabled)
return;

AlignTokens(
Expand All @@ -863,9 +870,9 @@ void WhitespaceManager::alignConsecutiveBitFields() {
if (&C != &Changes.back() && (&C + 1)->NewlinesBefore > 0)
return false;

return C.Tok->is(TT_BitFieldColon);
return C.Tok->is(Type);
},
Changes, /*StartAt=*/0, Style.AlignConsecutiveBitFields);
Changes, /*StartAt=*/0, AlignStyle);
}

void WhitespaceManager::alignConsecutiveShortCaseStatements() {
Expand Down Expand Up @@ -972,6 +979,11 @@ void WhitespaceManager::alignConsecutiveShortCaseStatements() {
Changes);
}

void WhitespaceManager::alignConsecutiveTableGenCondOperatorColons() {
alignConsecutiveColons(Style.AlignConsecutiveTableGenCondOperatorColons,
TT_TableGenCondOperatorColon);
}

void WhitespaceManager::alignConsecutiveDeclarations() {
if (!Style.AlignConsecutiveDeclarations.Enabled)
return;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Format/WhitespaceManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,11 @@ class WhitespaceManager {
/// Align consecutive bitfields over all \c Changes.
void alignConsecutiveBitFields();

/// Align consecutive colon. For bitfields, TableGen DAGArgs and defintions.
void
alignConsecutiveColons(const FormatStyle::AlignConsecutiveStyle &AlignStyle,
TokenType Type);

/// Align consecutive declarations over all \c Changes.
void alignConsecutiveDeclarations();

Expand All @@ -235,6 +240,9 @@ class WhitespaceManager {
/// Align consecutive short case statements over all \c Changes.
void alignConsecutiveShortCaseStatements();

/// Align consecutive TableGen cond operator colon over all \c Changes.
void alignConsecutiveTableGenCondOperatorColons();

/// Align trailing comments over all \c Changes.
void alignTrailingComments();

Expand Down
98 changes: 98 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,104 @@ double3 cos(double3);
_HLSL_BUILTIN_ALIAS(__builtin_elementwise_cos)
double4 cos(double4);

//===----------------------------------------------------------------------===//
// dot product builtins
//===----------------------------------------------------------------------===//

/// \fn K dot(T X, T Y)
/// \brief Return the dot product (a scalar value) of \a X and \a Y.
/// \param X The X input value.
/// \param Y The Y input value.

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half, half);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half2, half2);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half3, half3);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
half dot(half4, half4);

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t, int16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t2, int16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t3, int16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int16_t dot(int16_t4, int16_t4);

_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t, uint16_t);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t2, uint16_t2);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t3, uint16_t3);
_HLSL_AVAILABILITY(shadermodel, 6.2)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint16_t dot(uint16_t4, uint16_t4);
#endif

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float, float);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float2, float2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float3, float3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
float dot(float4, float4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
double dot(double, double);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int, int);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int2, int2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int3, int3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int dot(int4, int4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint, uint);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint2, uint2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint3, uint3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint dot(uint4, uint4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t, int64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t2, int64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t3, int64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
int64_t dot(int64_t4, int64_t4);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t, uint64_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t2, uint64_t2);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t3, uint64_t3);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_dot)
uint64_t dot(uint64_t4, uint64_t4);

//===----------------------------------------------------------------------===//
// floor builtins
//===----------------------------------------------------------------------===//
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Sema/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ add_clang_library(clangSema
Sema.cpp
SemaAccess.cpp
SemaAttr.cpp
SemaAPINotes.cpp
SemaAvailability.cpp
SemaCXXScopeSpec.cpp
SemaCast.cpp
Expand Down
988 changes: 988 additions & 0 deletions clang/lib/Sema/SemaAPINotes.cpp

Large diffs are not rendered by default.

103 changes: 95 additions & 8 deletions clang/lib/Sema/SemaChecking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2120,10 +2120,11 @@ bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID,
// not a valid type, emit an error message and return true. Otherwise return
// false.
static bool checkMathBuiltinElementType(Sema &S, SourceLocation Loc,
QualType Ty) {
if (!Ty->getAs<VectorType>() && !ConstantMatrixType::isValidElementType(Ty)) {
QualType ArgTy, int ArgIndex) {
if (!ArgTy->getAs<VectorType>() &&
!ConstantMatrixType::isValidElementType(ArgTy)) {
return S.Diag(Loc, diag::err_builtin_invalid_arg_type)
<< 1 << /* vector, integer or float ty*/ 0 << Ty;
<< ArgIndex << /* vector, integer or float ty*/ 0 << ArgTy;
}

return false;
Expand Down Expand Up @@ -2961,6 +2962,9 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
}
}

if (getLangOpts().HLSL && CheckHLSLBuiltinFunctionCall(BuiltinID, TheCall))
return ExprError();

// Since the target specific builtins for each arch overlap, only check those
// of the arch we are compiling for.
if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) {
Expand Down Expand Up @@ -5161,6 +5165,70 @@ bool Sema::CheckPPCMMAType(QualType Type, SourceLocation TypeLoc) {
return false;
}

// Helper function for CheckHLSLBuiltinFunctionCall
bool CheckVectorElementCallArgs(Sema *S, CallExpr *TheCall) {
assert(TheCall->getNumArgs() > 1);
ExprResult A = TheCall->getArg(0);
ExprResult B = TheCall->getArg(1);
QualType ArgTyA = A.get()->getType();
QualType ArgTyB = B.get()->getType();
auto *VecTyA = ArgTyA->getAs<VectorType>();
auto *VecTyB = ArgTyB->getAs<VectorType>();
SourceLocation BuiltinLoc = TheCall->getBeginLoc();
if (VecTyA == nullptr && VecTyB == nullptr)
return false;

if (VecTyA && VecTyB) {
bool retValue = false;
if (VecTyA->getElementType() != VecTyB->getElementType()) {
// Note: type promotion is intended to be handeled via the intrinsics
// and not the builtin itself.
S->Diag(TheCall->getBeginLoc(), diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< SourceRange(A.get()->getBeginLoc(), B.get()->getEndLoc());
retValue = true;
}
if (VecTyA->getNumElements() != VecTyB->getNumElements()) {
// if we get here a HLSLVectorTruncation is needed.
S->Diag(BuiltinLoc, diag::err_vec_builtin_incompatible_vector)
<< TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
retValue = true;
}

if (retValue)
TheCall->setType(VecTyA->getElementType());

return retValue;
}

// Note: if we get here one of the args is a scalar which
// requires a VectorSplat on Arg0 or Arg1
S->Diag(BuiltinLoc, diag::err_vec_builtin_non_vector)
<< TheCall->getDirectCallee()
<< SourceRange(TheCall->getArg(0)->getBeginLoc(),
TheCall->getArg(1)->getEndLoc());
return true;
}

// Note: returning true in this case results in CheckBuiltinFunctionCall
// returning an ExprError
bool Sema::CheckHLSLBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_dot: {
if (checkArgCount(*this, TheCall, 2))
return true;
if (CheckVectorElementCallArgs(this, TheCall))
return true;
if (SemaBuiltinVectorToScalarMath(TheCall))
return true;
break;
}
}
return false;
}

bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID,
CallExpr *TheCall) {
// position of memory order and scope arguments in the builtin
Expand Down Expand Up @@ -19594,23 +19662,43 @@ bool Sema::PrepareBuiltinElementwiseMathOneArgCall(CallExpr *TheCall) {
TheCall->setArg(0, A.get());
QualType TyA = A.get()->getType();

if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA))
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
return true;

TheCall->setType(TyA);
return false;
}

bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) {
QualType Res;
if (SemaBuiltinVectorMath(TheCall, Res))
return true;
TheCall->setType(Res);
return false;
}

bool Sema::SemaBuiltinVectorToScalarMath(CallExpr *TheCall) {
QualType Res;
if (SemaBuiltinVectorMath(TheCall, Res))
return true;

if (auto *VecTy0 = Res->getAs<VectorType>())
TheCall->setType(VecTy0->getElementType());
else
TheCall->setType(Res);

return false;
}

bool Sema::SemaBuiltinVectorMath(CallExpr *TheCall, QualType &Res) {
if (checkArgCount(*this, TheCall, 2))
return true;

ExprResult A = TheCall->getArg(0);
ExprResult B = TheCall->getArg(1);
// Do standard promotions between the two arguments, returning their common
// type.
QualType Res =
UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison);
Res = UsualArithmeticConversions(A, B, TheCall->getExprLoc(), ACK_Comparison);
if (A.isInvalid() || B.isInvalid())
return true;

Expand All @@ -19622,12 +19710,11 @@ bool Sema::SemaBuiltinElementwiseMath(CallExpr *TheCall) {
diag::err_typecheck_call_different_arg_types)
<< TyA << TyB;

if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA))
if (checkMathBuiltinElementType(*this, A.get()->getBeginLoc(), TyA, 1))
return true;

TheCall->setArg(0, A.get());
TheCall->setArg(1, B.get());
TheCall->setType(Res);
return false;
}

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16424,6 +16424,7 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
D = TD->getTemplatedDecl();
ProcessDeclAttributeList(S, D, Attrs);
ProcessAPINotes(D);

if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
if (Method->isStatic())
Expand Down Expand Up @@ -19683,6 +19684,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
CDecl->setIvarRBraceLoc(RBrac);
}
}
ProcessAPINotes(Record);
}

/// Determine whether the given integral value is representable within
Expand Down Expand Up @@ -19997,6 +19999,7 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
// Process attributes.
ProcessDeclAttributeList(S, New, Attrs);
AddPragmaAttributes(S, New);
ProcessAPINotes(New);

// Register this decl in the current scope stack.
New->setAccess(TheEnumDecl->getAccess());
Expand Down Expand Up @@ -20195,6 +20198,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
QualType EnumType = Context.getTypeDeclType(Enum);

ProcessDeclAttributeList(S, Enum, Attrs);
ProcessAPINotes(Enum);

if (Enum->isDependentType()) {
for (unsigned i = 0, e = Elements.size(); i != e; ++i) {
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10146,6 +10146,9 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) {

// Apply additional attributes specified by '#pragma clang attribute'.
AddPragmaAttributes(S, D);

// Look for API notes that map to attributes.
ProcessAPINotes(D);
}

/// Is the given declaration allowed to use a forbidden type?
Expand Down
6 changes: 5 additions & 1 deletion clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11724,6 +11724,7 @@ Decl *Sema::ActOnStartNamespaceDef(Scope *NamespcScope,

ProcessDeclAttributeList(DeclRegionScope, Namespc, AttrList);
AddPragmaAttributes(DeclRegionScope, Namespc);
ProcessAPINotes(Namespc);

// FIXME: Should we be merging attributes?
if (const VisibilityAttr *Attr = Namespc->getAttr<VisibilityAttr>())
Expand Down Expand Up @@ -12270,8 +12271,10 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
Diag(IdentLoc, diag::err_expected_namespace_name) << SS.getRange();
}

if (UDir)
if (UDir) {
ProcessDeclAttributeList(S, UDir, AttrList);
ProcessAPINotes(UDir);
}

return UDir;
}
Expand Down Expand Up @@ -13563,6 +13566,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,

ProcessDeclAttributeList(S, NewTD, AttrList);
AddPragmaAttributes(S, NewTD);
ProcessAPINotes(NewTD);

CheckTypedefForVariablyModifiedType(S, NewTD);
Invalid |= NewTD->isInvalidDecl();
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1072,6 +1072,7 @@ ObjCInterfaceDecl *Sema::ActOnStartClassInterface(

ProcessDeclAttributeList(TUScope, IDecl, AttrList);
AddPragmaAttributes(TUScope, IDecl);
ProcessAPINotes(IDecl);

// Merge attributes from previous declarations.
if (PrevIDecl)
Expand Down Expand Up @@ -1273,6 +1274,7 @@ ObjCProtocolDecl *Sema::ActOnStartProtocolInterface(

ProcessDeclAttributeList(TUScope, PDecl, AttrList);
AddPragmaAttributes(TUScope, PDecl);
ProcessAPINotes(PDecl);

// Merge attributes from previous declarations.
if (PrevDecl)
Expand Down Expand Up @@ -4807,6 +4809,7 @@ Decl *Sema::ActOnMethodDeclaration(
// Apply the attributes to the parameter.
ProcessDeclAttributeList(TUScope, Param, ArgInfo[i].ArgAttrs);
AddPragmaAttributes(TUScope, Param);
ProcessAPINotes(Param);

if (Param->hasAttr<BlocksAttr>()) {
Diag(Param->getLocation(), diag::err_block_on_nonlocal);
Expand Down Expand Up @@ -4837,6 +4840,7 @@ Decl *Sema::ActOnMethodDeclaration(

ProcessDeclAttributeList(TUScope, ObjCMethod, AttrList);
AddPragmaAttributes(TUScope, ObjCMethod);
ProcessAPINotes(ObjCMethod);

// Add the method now.
const ObjCMethodDecl *PrevMethod = nullptr;
Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/SemaObjCProperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2509,6 +2509,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
GetterMethod->addAttr(SectionAttr::CreateImplicit(
Context, SA->getName(), Loc, SectionAttr::GNU_section));

ProcessAPINotes(GetterMethod);

if (getLangOpts().ObjCAutoRefCount)
CheckARCMethodDecl(GetterMethod);
} else
Expand Down Expand Up @@ -2578,6 +2580,9 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
if (const SectionAttr *SA = property->getAttr<SectionAttr>())
SetterMethod->addAttr(SectionAttr::CreateImplicit(
Context, SA->getName(), Loc, SectionAttr::GNU_section));

ProcessAPINotes(SetterMethod);

// It's possible for the user to have set a very odd custom
// setter selector that causes it to have a method family.
if (getLangOpts().ObjCAutoRefCount)
Expand Down
16 changes: 12 additions & 4 deletions clang/lib/Sema/SemaStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3361,8 +3361,9 @@ Sema::ActOnContinueStmt(SourceLocation ContinueLoc, Scope *CurScope) {
// of a compute construct counts as 'branching out of' the compute construct,
// so diagnose here.
if (S->isOpenACCComputeConstructScope())
return StmtError(Diag(ContinueLoc, diag::err_acc_branch_in_out)
<< /*out of */ 0);
return StmtError(
Diag(ContinueLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*out of */ 0);

CheckJumpOutOfSEHFinally(*this, ContinueLoc, *S);

Expand Down Expand Up @@ -3390,8 +3391,9 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
if (S->isOpenACCComputeConstructScope() ||
(S->isLoopScope() && S->getParent() &&
S->getParent()->isOpenACCComputeConstructScope()))
return StmtError(Diag(BreakLoc, diag::err_acc_branch_in_out)
<< /*out of */ 0);
return StmtError(
Diag(BreakLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*branch*/ 0 << /*out of */ 0);

CheckJumpOutOfSEHFinally(*this, BreakLoc, *S);

Expand Down Expand Up @@ -3947,6 +3949,12 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
RetValExp, nullptr, /*RecoverUncorrectedTypos=*/true);
if (RetVal.isInvalid())
return StmtError();

if (getCurScope()->isInOpenACCComputeConstructScope())
return StmtError(
Diag(ReturnLoc, diag::err_acc_branch_in_out_compute_construct)
<< /*return*/ 1 << /*out of */ 0);

StmtResult R =
BuildReturnStmt(ReturnLoc, RetVal.get(), /*AllowRecovery=*/true);
if (R.isInvalid() || ExprEvalContexts.back().isDiscardedStatementContext())
Expand Down
41 changes: 41 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2158,6 +2158,7 @@ DeclResult Sema::CheckClassTemplate(
NewClass->startDefinition();

ProcessDeclAttributeList(S, NewClass, Attr);
ProcessAPINotes(NewClass);

if (PrevClassTemplate)
mergeDeclAttributes(NewClass, PrevClassTemplate->getTemplatedDecl());
Expand Down Expand Up @@ -9112,6 +9113,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization(
}

ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);

// Add alignment attributes if necessary; these attributes are checked when
// the ASTContext lays out the structure.
Expand Down Expand Up @@ -9707,6 +9709,40 @@ bool Sema::CheckFunctionTemplateSpecialization(
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);

// C++23 [except.spec]p13:
// An exception specification is considered to be needed when:
// - [...]
// - the exception specification is compared to that of another declaration
// (e.g., an explicit specialization or an overriding virtual function);
// - [...]
//
// The exception specification of a defaulted function is evaluated as
// described above only when needed; similarly, the noexcept-specifier of a
// specialization of a function template or member function of a class
// template is instantiated only when needed.
//
// The standard doesn't specify what the "comparison with another declaration"
// entails, nor the exact circumstances in which it occurs. Moreover, it does
// not state which properties of an explicit specialization must match the
// primary template.
//
// We assume that an explicit specialization must correspond with (per
// [basic.scope.scope]p4) and declare the same entity as (per [basic.link]p8)
// the declaration produced by substitution into the function template.
//
// Since the determination whether two function declarations correspond does
// not consider exception specification, we only need to instantiate it once
// we determine the primary template when comparing types per
// [basic.link]p11.1.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
// If the function has a dependent exception specification, resolve it after
// we have selected the primary template so we can check whether it matches.
if (getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(FD->getLocation(), SpecializationFPT))
return true;

FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
Expand Down Expand Up @@ -10346,6 +10382,7 @@ DeclResult Sema::ActOnExplicitInstantiation(

bool PreviouslyDLLExported = Specialization->hasAttr<DLLExportAttr>();
ProcessDeclAttributeList(S, Specialization, Attr);
ProcessAPINotes(Specialization);

// Add the explicit instantiation into its lexical context. However,
// since explicit instantiations are never found by name lookup, we
Expand Down Expand Up @@ -10756,6 +10793,9 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
Prev->setTemplateSpecializationKind(TSK, D.getIdentifierLoc());
// Merge attributes.
ProcessDeclAttributeList(S, Prev, D.getDeclSpec().getAttributes());
if (PrevTemplate)
ProcessAPINotes(Prev);

if (TSK == TSK_ExplicitInstantiationDefinition)
InstantiateVariableDefinition(D.getIdentifierLoc(), Prev);
}
Expand Down Expand Up @@ -10931,6 +10971,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
}

ProcessDeclAttributeList(S, Specialization, D.getDeclSpec().getAttributes());
ProcessAPINotes(Specialization);

// In MSVC mode, dllimported explicit instantiation definitions are treated as
// instantiation declarations.
Expand Down
14 changes: 6 additions & 8 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4632,11 +4632,9 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
Info.getLocation()))
return TemplateDeductionResult::MiscellaneousDeductionFailure;

// If the function has a dependent exception specification, resolve it now,
// so we can check that the exception specification matches.
auto *SpecializationFPT =
Specialization->getType()->castAs<FunctionProtoType>();
if (getLangOpts().CPlusPlus17 &&
if (IsAddressOfFunction && getLangOpts().CPlusPlus17 &&
isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) &&
!ResolveExceptionSpec(Info.getLocation(), SpecializationFPT))
return TemplateDeductionResult::MiscellaneousDeductionFailure;
Expand All @@ -4662,11 +4660,11 @@ TemplateDeductionResult Sema::DeduceTemplateArguments(
// specialization with respect to arguments of compatible pointer to function
// types, template argument deduction fails.
if (!ArgFunctionType.isNull()) {
if (IsAddressOfFunction
? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameType(SpecializationType, ArgFunctionType)) {
if (IsAddressOfFunction ? !isSameOrCompatibleFunctionType(
Context.getCanonicalType(SpecializationType),
Context.getCanonicalType(ArgFunctionType))
: !Context.hasSameFunctionTypeIgnoringExceptionSpec(
SpecializationType, ArgFunctionType)) {
Info.FirstArg = TemplateArgument(SpecializationType);
Info.SecondArg = TemplateArgument(ArgFunctionType);
return TemplateDeductionResult::NonDeducedMismatch;
Expand Down
Loading