9 changes: 6 additions & 3 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,8 @@ C++2c Feature Support
- Added the ``__builtin_is_within_lifetime`` builtin, which supports
`P2641R4 Checking if a union alternative is active <https://wg21.link/p2641r4>`_

- Implemented `P3176R1 The Oxford variadic comma <https://wg21.link/P3176R1>`_

C++23 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Removed the restriction to literal types in constexpr functions in C++23 mode.
Expand Down Expand Up @@ -402,6 +404,7 @@ Non-comprehensive list of changes in this release
- ``__builtin_reduce_and`` function can now be used in constant expressions.
- ``__builtin_reduce_or`` and ``__builtin_reduce_xor`` functions can now be used in constant expressions.
- ``__builtin_elementwise_popcount`` function can now be used in constant expressions.
- ``__builtin_elementwise_bitreverse`` function can now be used in constant expressions.

New Compiler Flags
------------------
Expand Down Expand Up @@ -624,9 +627,6 @@ Improvements to Clang's diagnostics

- Fixed a false negative ``-Wunused-private-field`` diagnostic when a defaulted comparison operator is defined out of class (#GH116961).

- Clang now supports using alias templates in deduction guides, aligning with the C++ standard,
which treats alias templates as synonyms for their underlying types (#GH54909).

- Clang now diagnoses dangling references for C++20's parenthesized aggregate initialization (#101957).

Improvements to Clang's time-trace
Expand Down Expand Up @@ -763,6 +763,9 @@ Bug Fixes to C++ Support
- Fixed a bug where bounds of partially expanded pack indexing expressions were checked too early. (#GH116105)
- Fixed an assertion failure caused by using ``consteval`` in condition in consumed analyses. (#GH117385)
- Fix a crash caused by incorrect argument position in merging deduced template arguments. (#GH113659)
- Fixed an assertion failure caused by mangled names with invalid identifiers. (#GH112205)
- Fixed an incorrect lambda scope of generic lambdas that caused Clang to crash when computing potential lambda
captures at the end of a full expression. (#GH115931)

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
Expand Down
8 changes: 7 additions & 1 deletion clang/include/clang/Basic/Builtins.td
Original file line number Diff line number Diff line change
Expand Up @@ -1270,7 +1270,7 @@ def ElementwiseATan2 : Builtin {

def ElementwiseBitreverse : Builtin {
let Spellings = ["__builtin_elementwise_bitreverse"];
let Attributes = [NoThrow, Const, CustomTypeChecking];
let Attributes = [NoThrow, Const, CustomTypeChecking, Constexpr];
let Prototype = "void(...)";
}

Expand Down Expand Up @@ -4738,6 +4738,12 @@ def GetDeviceSideMangledName : LangBuiltin<"CUDA_LANG"> {
}

// HLSL
def HLSLResourceGetPointer : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_resource_getpointer"];
let Attributes = [NoThrow];
let Prototype = "void(...)";
}

def HLSLAll : LangBuiltin<"HLSL_LANG"> {
let Spellings = ["__builtin_hlsl_all"];
let Attributes = [NoThrow, Const];
Expand Down
2 changes: 2 additions & 0 deletions clang/include/clang/Basic/BuiltinsAMDGPU.def
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,8 @@ TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr4_b64_v2i32, "V2iV2i*3", "nc", "gfx950
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr6_b96_v3i32, "V3iV3i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr8_b64_v2i32, "V2iV2i*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4i16, "V4sV4s*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4f16, "V4hV4h*3", "nc", "gfx950-insts")
TARGET_BUILTIN(__builtin_amdgcn_ds_read_tr16_b64_v4bf16, "V4yV4y*3", "nc", "gfx950-insts")

TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_i8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
TARGET_BUILTIN(__builtin_amdgcn_ashr_pk_u8_i32, "UsUiUiUi", "nc", "ashr-pk-insts")
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticGroups.td
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,7 @@ def DeprecatedWritableStr : DiagGroup<"deprecated-writable-strings",
[CXX11CompatDeprecatedWritableStr]>;
def DeprecatedPragma : DiagGroup<"deprecated-pragma">;
def DeprecatedType : DiagGroup<"deprecated-type">;
def DeprecatedMissingCommaVariadicParam : DiagGroup<"deprecated-missing-comma-variadic-parameter">;
// FIXME: Why is DeprecatedImplementations not in this group?
def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedArrayCompare,
Expand All @@ -235,7 +236,8 @@ def Deprecated : DiagGroup<"deprecated", [DeprecatedAnonEnumEnumConversion,
DeprecatedType,
DeprecatedVolatile,
DeprecatedWritableStr,
DeprecatedRedundantConstexprStaticDef
DeprecatedRedundantConstexprStaticDef,
DeprecatedMissingCommaVariadicParam
]>,
DiagCategory<"Deprecations">;

Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,9 @@ def err_function_scope_depth_exceeded : Error<
"function scope depth exceeded maximum of %0">, DefaultFatal;
def err_missing_comma_before_ellipsis : Error<
"C requires a comma prior to the ellipsis in a variadic function type">;
def warn_deprecated_missing_comma_before_ellipsis : Warning<
"declaration of a variadic function without a comma before '...' is deprecated">,
InGroup<DeprecatedMissingCommaVariadicParam>;
def err_unexpected_typedef_ident : Error<
"unexpected type name %0: expected identifier">;
def warn_cxx98_compat_decltype : Warning<
Expand Down
10 changes: 5 additions & 5 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -12733,19 +12733,19 @@ def err_acc_size_expr_value
"OpenACC 'tile' clause size expression must be %select{an asterisk "
"or a constant expression|positive integer value, evaluated to %1}0">;
def err_acc_invalid_in_loop
: Error<"%select{OpenACC '%2' construct|while loop|do loop}0 cannot appear "
"in intervening code of a 'loop' with a '%1' clause">;
: Error<"%select{OpenACC '%3' construct|while loop|do loop}0 cannot appear "
"in intervening code of a '%1' with a '%2' clause">;
def note_acc_active_clause_here
: Note<"active '%0' clause defined here">;
def err_acc_clause_multiple_loops
: Error<"more than one for-loop in a loop associated with OpenACC 'loop' "
"construct with a '%select{collapse|tile}0' clause">;
: Error<"more than one for-loop in a loop associated with OpenACC '%0' "
"construct with a '%1' clause">;
def err_acc_insufficient_loops
: Error<"'%0' clause specifies a loop count greater than the number "
"of available loops">;
def err_acc_intervening_code
: Error<"inner loops must be tightly nested inside a '%0' clause on "
"a 'loop' construct">;
"a '%1' construct">;
def err_acc_gang_multiple_elt
: Error<"OpenACC 'gang' clause may have at most one %select{unnamed or "
"'num'|'dim'|'static'}0 argument">;
Expand Down
28 changes: 14 additions & 14 deletions clang/include/clang/Basic/arm_sve.td
Original file line number Diff line number Diff line change
Expand Up @@ -762,14 +762,14 @@ def SVCMPLS_WIDE_N : SInst<"svcmple_wide[_n_{d}]", "PPdj", "UcUsUi", MergeNone,
////////////////////////////////////////////////////////////////////////////////
// While comparisons

def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S32 : SInst<"svwhilele_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELE_S64 : SInst<"svwhilele_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilele", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U32 : SInst<"svwhilelt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELO_U64 : SInst<"svwhilelt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilelo", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U32 : SInst<"svwhilele_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELS_U64 : SInst<"svwhilele_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilels", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S32 : SInst<"svwhilelt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILELT_S64 : SInst<"svwhilelt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilelt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;

////////////////////////////////////////////////////////////////////////////////
// Counting bit
Expand Down Expand Up @@ -1365,10 +1365,10 @@ def SVWHILEGE_S32 : SInst<"svwhilege_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNon
def SVWHILEGE_S64 : SInst<"svwhilege_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilege", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S32 : SInst<"svwhilegt_{d}[_{1}]", "Pkk", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEGT_S64 : SInst<"svwhilegt_{d}[_{1}]", "Pll", "PcPsPiPl", MergeNone, "aarch64_sve_whilegt", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PUcPUsPUiPUl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U32 : SInst<"svwhilegt_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHI_U64 : SInst<"svwhilegt_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehi", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U32 : SInst<"svwhilege_{d}[_{1}]", "Pmm", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
def SVWHILEHS_U64 : SInst<"svwhilege_{d}[_{1}]", "Pnn", "PcPsPiPl", MergeNone, "aarch64_sve_whilehs", [IsOverloadWhileOrMultiVecCvt, VerifyRuntimeMode]>;
}

let SVETargetGuard = "sve2p1", SMETargetGuard = "sme2" in {
Expand Down Expand Up @@ -2326,7 +2326,7 @@ let SVETargetGuard = "sve2p1,bf16", SMETargetGuard = "sme2p1,bf16" in {
// Multi-vector convert to/from floating-point.
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_F16_X2 : SInst<"svcvt_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvt_x2", [IsStreaming],[]>;
def SVCVT_BF16_X2 : SInst<"svcvt_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvt_x2", [IsOverloadNone, IsStreaming],[]>;

def SVCVT_F32_U32_X2 : SInst<"svcvt_{d}[_u32_x2]", "2.d2.u", "f", MergeNone, "aarch64_sve_ucvtf_x2", [IsStreaming, IsOverloadWhileOrMultiVecCvt], []>;
Expand All @@ -2348,7 +2348,7 @@ let SVETargetGuard = InvalidMode, SMETargetGuard = "sme-f16f16" in {
// Multi-vector floating-point convert from single-precision to interleaved half-precision/BFloat16
//
let SVETargetGuard = InvalidMode, SMETargetGuard = "sme2" in {
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "e2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_F16_X2 : SInst<"svcvtn_f16[_f32_x2]", "h2", "f", MergeNone, "aarch64_sve_fcvtn_x2", [IsStreaming],[]>;
def SVCVTN_BF16_X2 : SInst<"svcvtn_bf16[_f32_x2]", "$2", "f", MergeNone, "aarch64_sve_bfcvtn_x2", [IsOverloadNone, IsStreaming],[]>;
}

Expand Down
4 changes: 4 additions & 0 deletions clang/include/clang/Driver/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -5092,6 +5092,10 @@ def matomics : Flag<["-"], "matomics">, Group<m_wasm_Features_Group>;
def mno_atomics : Flag<["-"], "mno-atomics">, Group<m_wasm_Features_Group>;
def mbulk_memory : Flag<["-"], "mbulk-memory">, Group<m_wasm_Features_Group>;
def mno_bulk_memory : Flag<["-"], "mno-bulk-memory">, Group<m_wasm_Features_Group>;
def mbulk_memory_opt : Flag<["-"], "mbulk-memory-opt">, Group<m_wasm_Features_Group>;
def mno_bulk_memory_opt : Flag<["-"], "mno-bulk-memory-opt">, Group<m_wasm_Features_Group>;
def mcall_indirect_overlong : Flag<["-"], "mcall-indirect-overlong">, Group<m_wasm_Features_Group>;
def mno_call_indirect_overlong : Flag<["-"], "mno-call-indirect-overlong">, Group<m_wasm_Features_Group>;
def mexception_handing : Flag<["-"], "mexception-handling">, Group<m_wasm_Features_Group>;
def mno_exception_handing : Flag<["-"], "mno-exception-handling">, Group<m_wasm_Features_Group>;
def mextended_const : Flag<["-"], "mextended-const">, Group<m_wasm_Features_Group>;
Expand Down
8 changes: 8 additions & 0 deletions clang/include/clang/Sema/SemaOpenACC.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the value of 'N' is too large for the
/// current number of 'for' loops.
bool CollapseDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} CollapseInfo;

/// The 'tile' clause requires a bit of additional checking as well, so like
Expand All @@ -103,6 +107,10 @@ class SemaOpenACC : public SemaBase {
/// which allows us to diagnose if the number of arguments is too large for
/// the current number of 'for' loops.
bool TileDepthSatisfied = true;

/// Records the kind of the directive that this clause is attached to, which
/// allows us to use it in diagnostics.
OpenACCDirectiveKind DirectiveKind = OpenACCDirectiveKind::Invalid;
} TileInfo;

/// A list of the active reduction clauses, which allows us to check that all
Expand Down
32 changes: 6 additions & 26 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -429,47 +429,27 @@ class BranchNodeBuilder: public NodeBuilder {
const CFGBlock *DstT;
const CFGBlock *DstF;

bool InFeasibleTrue;
bool InFeasibleFalse;

void anchor() override;

public:
BranchNodeBuilder(ExplodedNode *SrcNode, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcNode, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcNode, DstSet, C), DstT(DT), DstF(DF) {
// The branch node builder does not generate autotransitions.
// If there are no successors it means that both branches are infeasible.
takeNodes(SrcNode);
}

BranchNodeBuilder(const ExplodedNodeSet &SrcSet, ExplodedNodeSet &DstSet,
const NodeBuilderContext &C,
const CFGBlock *dstT, const CFGBlock *dstF)
: NodeBuilder(SrcSet, DstSet, C), DstT(dstT), DstF(dstF),
InFeasibleTrue(!DstT), InFeasibleFalse(!DstF) {
const NodeBuilderContext &C, const CFGBlock *DT,
const CFGBlock *DF)
: NodeBuilder(SrcSet, DstSet, C), DstT(DT), DstF(DF) {
takeNodes(SrcSet);
}

ExplodedNode *generateNode(ProgramStateRef State, bool branch,
ExplodedNode *Pred);

const CFGBlock *getTargetBlock(bool branch) const {
return branch ? DstT : DstF;
}

void markInfeasible(bool branch) {
if (branch)
InFeasibleTrue = true;
else
InFeasibleFalse = true;
}

bool isFeasible(bool branch) {
return branch ? !InFeasibleTrue : !InFeasibleFalse;
}
};

class IndirectGotoNodeBuilder {
Expand Down
16 changes: 14 additions & 2 deletions clang/lib/AST/ASTImporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6093,8 +6093,7 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
Decl::IDNS_TagFriend))
continue;

Decl *Found = FoundDecl;
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(Found);
auto *FoundTemplate = dyn_cast<ClassTemplateDecl>(FoundDecl);
if (FoundTemplate) {
if (!hasSameVisibilityContextAndLinkage(FoundTemplate, D))
continue;
Expand All @@ -6118,6 +6117,19 @@ ExpectedDecl ASTNodeImporter::VisitClassTemplateDecl(ClassTemplateDecl *D) {
// see ASTTests test ImportExistingFriendClassTemplateDef.
continue;
}
// When importing a friend, it is possible that multiple declarations
// with same name can co-exist in specific cases (if a template contains
// a friend template and has a specialization). For this case the
// declarations should match, except that the "template depth" is
// different. No linking of previous declaration is needed in this case.
// FIXME: This condition may need refinement.
if (D->getFriendObjectKind() != Decl::FOK_None &&
FoundTemplate->getFriendObjectKind() != Decl::FOK_None &&
D->getFriendObjectKind() != FoundTemplate->getFriendObjectKind() &&
IsStructuralMatch(D, FoundTemplate, /*Complain=*/false,
/*IgnoreTemplateParmDepth=*/true))
continue;

ConflictingDecls.push_back(FoundDecl);
}
}
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,8 @@ bool Compiler<Emitter>::VisitCastExpr(const CastExpr *CE) {

QualType SubExprTy = SubExpr->getType();
std::optional<PrimType> FromT = classify(SubExprTy);
// Casts from integer to vectors in C.
if (FromT && CE->getType()->isVectorType())
// Casts from integer/vector to vector.
if (CE->getType()->isVectorType())
return this->emitBuiltinBitCast(CE);

std::optional<PrimType> ToT = classify(CE->getType());
Expand Down Expand Up @@ -6502,7 +6502,7 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
// we later assume it to be one (i.e. a PT_Ptr). However,
// we call this function for other utility methods where
// a bitcast might be useful, so convert it to a PT_Ptr in that case.
if (SubExpr->isGLValue()) {
if (SubExpr->isGLValue() || FromType->isVectorType()) {
if (!this->visit(SubExpr))
return false;
} else if (std::optional<PrimType> FromT = classify(SubExpr)) {
Expand All @@ -6514,6 +6514,8 @@ bool Compiler<Emitter>::emitBuiltinBitCast(const CastExpr *E) {
return false;
if (!this->emitGetPtrLocal(TempOffset, E))
return false;
} else {
return false;
}

if (!ToT || ToT == PT_Ptr) {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/ByteCode/Integral.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,9 @@ template <unsigned Bits, bool Signed> class Integral final {
APSInt toAPSInt() const {
return APSInt(APInt(Bits, static_cast<uint64_t>(V), Signed), !Signed);
}
APSInt toAPSInt(unsigned BitWidth) const { return APSInt(toAPInt(BitWidth)); }
APSInt toAPSInt(unsigned BitWidth) const {
return APSInt(toAPInt(BitWidth), !Signed);
}
APInt toAPInt(unsigned BitWidth) const {
if constexpr (Signed)
return APInt(Bits, static_cast<uint64_t>(V), Signed)
Expand Down
164 changes: 145 additions & 19 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,8 @@ template <typename T>
static void pushInteger(InterpState &S, T Val, QualType QT) {
if constexpr (std::is_same_v<T, APInt>)
pushInteger(S, APSInt(Val, !std::is_signed_v<T>), QT);
else if constexpr (std::is_same_v<T, APSInt>)
pushInteger(S, Val, QT);
else
pushInteger(S,
APSInt(APInt(sizeof(T) * 8, static_cast<uint64_t>(Val),
Expand Down Expand Up @@ -220,11 +222,25 @@ static bool interp__builtin_strcmp(InterpState &S, CodePtr OpPC,
return true;
}

static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
unsigned ID) {
auto Loc = S.Current->getSource(OpPC);
if (S.getLangOpts().CPlusPlus11)
S.CCEDiag(Loc, diag::note_constexpr_invalid_function)
<< /*isConstexpr=*/0 << /*isConstructor=*/0
<< ("'" + S.getASTContext().BuiltinInfo.getName(ID) + "'").str();
else
S.CCEDiag(Loc, diag::note_invalid_subexpr_in_const_expr);
}
static bool interp__builtin_strlen(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const CallExpr *Call) {
const Function *Func, const CallExpr *Call) {
unsigned ID = Func->getBuiltinID();
const Pointer &StrPtr = getParam<Pointer>(Frame, 0);

if (ID == Builtin::BIstrlen)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

if (!CheckArray(S, OpPC, StrPtr))
return false;

Expand Down Expand Up @@ -1695,32 +1711,124 @@ static bool interp__builtin_vector_reduce(InterpState &S, CodePtr OpPC,
assert(Arg.getFieldDesc()->isPrimitiveArray());

unsigned ID = Func->getBuiltinID();
if (ID == Builtin::BI__builtin_reduce_add) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH(ElemT, {
T Sum = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Sum.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
if (T::add(Sum, Elem, BitWidth, &Sum)) {
QualType ElemType = Arg.getFieldDesc()->getElemQualType();
assert(Call->getType() == ElemType);
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

INT_TYPE_SWITCH_NO_BOOL(ElemT, {
T Result = Arg.atIndex(0).deref<T>();
unsigned BitWidth = Result.bitWidth();
for (unsigned I = 1; I != NumElems; ++I) {
T Elem = Arg.atIndex(I).deref<T>();
T PrevResult = Result;

if (ID == Builtin::BI__builtin_reduce_add) {
if (T::add(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth + 1;
(void)handleOverflow(
S, OpPC,
(Sum.toAPSInt(OverflowBits) + Elem.toAPSInt(OverflowBits)));
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) +
Elem.toAPSInt(OverflowBits)));
return false;
}
} else if (ID == Builtin::BI__builtin_reduce_mul) {
if (T::mul(Result, Elem, BitWidth, &Result)) {
unsigned OverflowBits = BitWidth * 2;
(void)handleOverflow(S, OpPC,
(PrevResult.toAPSInt(OverflowBits) *
Elem.toAPSInt(OverflowBits)));
return false;
}

} else if (ID == Builtin::BI__builtin_reduce_and) {
(void)T::bitAnd(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_or) {
(void)T::bitOr(Result, Elem, BitWidth, &Result);
} else if (ID == Builtin::BI__builtin_reduce_xor) {
(void)T::bitXor(Result, Elem, BitWidth, &Result);
} else {
llvm_unreachable("Unhandled vector reduce builtin");
}
pushInteger(S, Sum, Call->getType());
}
pushInteger(S, Result.toAPSInt(), Call->getType());
});

return true;
}

/// Can be called with an integer or vector as the first and only parameter.
static bool interp__builtin_elementwise_popcount(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func,
const CallExpr *Call) {
assert(Call->getNumArgs() == 1);
if (Call->getArg(0)->getType()->isIntegerType()) {
PrimType ArgT = *S.getContext().classify(Call->getArg(0)->getType());
APSInt Val = peekToAPSInt(S.Stk, ArgT);
pushInteger(S, Val.popcount(), Call->getType());
return true;
}
// Otherwise, the argument must be a vector.
assert(Call->getArg(0)->getType()->isVectorType());
const Pointer &Arg = S.Stk.peek<Pointer>();
assert(Arg.getFieldDesc()->isPrimitiveArray());
const Pointer &Dst = S.Stk.peek<Pointer>(primSize(PT_Ptr) * 2);
assert(Dst.getFieldDesc()->isPrimitiveArray());
assert(Arg.getFieldDesc()->getNumElems() ==
Dst.getFieldDesc()->getNumElems());

QualType ElemType = Arg.getFieldDesc()->getElemQualType();
PrimType ElemT = *S.getContext().classify(ElemType);
unsigned NumElems = Arg.getNumElems();

// FIXME: Reading from uninitialized vector elements?
for (unsigned I = 0; I != NumElems; ++I) {
INT_TYPE_SWITCH_NO_BOOL(ElemT, {
Dst.atIndex(I).deref<T>() =
T::from(Arg.atIndex(I).deref<T>().toAPSInt().popcount());
});
}

return true;
}
static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame,
const Function *Func, const CallExpr *Call) {
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
Pointer DestPtr = getParam<Pointer>(Frame, 0);
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
assert(!Size.isSigned() && "memcpy and friends take an unsigned size");

if (ID == Builtin::BImemcpy || ID == Builtin::BImemmove)
diagnoseNonConstexprBuiltin(S, OpPC, ID);

bool Move = (ID == Builtin::BI__builtin_memmove || ID == Builtin::BImemmove);

if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

// If the size is zero, we treat this as always being a valid no-op.
if (Size.isZero()) {
S.Stk.push<Pointer>(DestPtr);
return true;
}

llvm_unreachable("Unsupported vector reduce builtin");
if (SrcPtr.isZero() || DestPtr.isZero()) {
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
<< DiagPtr.toDiagnosticString(S.getASTContext());
return false;
}

if (!DoBitCastPtr(S, OpPC, SrcPtr, DestPtr))
return false;

S.Stk.push<Pointer>(DestPtr);
return true;
}

bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
Expand All @@ -1742,7 +1850,8 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
return false;
break;
case Builtin::BI__builtin_strlen:
if (!interp__builtin_strlen(S, OpPC, Frame, Call))
case Builtin::BIstrlen:
if (!interp__builtin_strlen(S, OpPC, Frame, F, Call))
return false;
break;
case Builtin::BI__builtin_nan:
Expand Down Expand Up @@ -2169,10 +2278,27 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
break;

case Builtin::BI__builtin_reduce_add:
case Builtin::BI__builtin_reduce_mul:
case Builtin::BI__builtin_reduce_and:
case Builtin::BI__builtin_reduce_or:
case Builtin::BI__builtin_reduce_xor:
if (!interp__builtin_vector_reduce(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_elementwise_popcount:
if (!interp__builtin_elementwise_popcount(S, OpPC, Frame, F, Call))
return false;
break;

case Builtin::BI__builtin_memcpy:
case Builtin::BImemcpy:
case Builtin::BI__builtin_memmove:
case Builtin::BImemmove:
if (!interp__builtin_memcpy(S, OpPC, Frame, F, Call))
return false;
break;

default:
S.FFDiag(S.Current->getLocation(OpPC),
diag::note_invalid_subexpr_in_const_expr)
Expand Down
21 changes: 16 additions & 5 deletions clang/lib/AST/ExprConstant.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11310,7 +11310,8 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {
switch (E->getBuiltinCallee()) {
default:
return false;
case Builtin::BI__builtin_elementwise_popcount: {
case Builtin::BI__builtin_elementwise_popcount:
case Builtin::BI__builtin_elementwise_bitreverse: {
APValue Source;
if (!EvaluateAsRValue(Info, E->getArg(0), Source))
return false;
Expand All @@ -11322,9 +11323,18 @@ bool VectorExprEvaluator::VisitCallExpr(const CallExpr *E) {

for (unsigned EltNum = 0; EltNum < SourceLen; ++EltNum) {
APSInt Elt = Source.getVectorElt(EltNum).getInt();
ResultElements.push_back(
APValue(APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
switch (E->getBuiltinCallee()) {
case Builtin::BI__builtin_elementwise_popcount:
ResultElements.push_back(APValue(
APSInt(APInt(Info.Ctx.getIntWidth(DestEltTy), Elt.popcount()),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
case Builtin::BI__builtin_elementwise_bitreverse:
ResultElements.push_back(
APValue(APSInt(Elt.reverseBits(),
DestEltTy->isUnsignedIntegerOrEnumerationType())));
break;
}
}

return Success(APValue(ResultElements.data(), ResultElements.size()), E);
Expand Down Expand Up @@ -12833,7 +12843,8 @@ bool IntExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
case Builtin::BI__builtin_bitreverse8:
case Builtin::BI__builtin_bitreverse16:
case Builtin::BI__builtin_bitreverse32:
case Builtin::BI__builtin_bitreverse64: {
case Builtin::BI__builtin_bitreverse64:
case Builtin::BI__builtin_elementwise_bitreverse: {
APSInt Val;
if (!EvaluateInteger(E->getArg(0), Val, Info))
return false;
Expand Down
71 changes: 71 additions & 0 deletions clang/lib/AST/ItaniumMangle.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,7 @@ class CXXNameMangler {
static StringRef getCallingConvQualifierName(CallingConv CC);
void mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo info);
void mangleExtFunctionInfo(const FunctionType *T);
void mangleSMEAttrs(unsigned SMEAttrs);
void mangleBareFunctionType(const FunctionProtoType *T, bool MangleReturnType,
const FunctionDecl *FD = nullptr);
void mangleNeonVectorType(const VectorType *T);
Expand Down Expand Up @@ -3532,6 +3533,69 @@ void CXXNameMangler::mangleExtFunctionInfo(const FunctionType *T) {
// FIXME: noreturn
}

enum class AAPCSBitmaskSME : unsigned {
ArmStreamingBit = 1 << 0,
ArmStreamingCompatibleBit = 1 << 1,
ArmAgnosticSMEZAStateBit = 1 << 2,
ZA_Shift = 3,
ZT0_Shift = 6,
NoState = 0b000,
ArmIn = 0b001,
ArmOut = 0b010,
ArmInOut = 0b011,
ArmPreserves = 0b100,
LLVM_MARK_AS_BITMASK_ENUM(/*LargestValue=*/ArmPreserves << ZT0_Shift)
};

static AAPCSBitmaskSME encodeAAPCSZAState(unsigned SMEAttrs) {
switch (SMEAttrs) {
case FunctionType::ARM_None:
return AAPCSBitmaskSME::NoState;
case FunctionType::ARM_In:
return AAPCSBitmaskSME::ArmIn;
case FunctionType::ARM_Out:
return AAPCSBitmaskSME::ArmOut;
case FunctionType::ARM_InOut:
return AAPCSBitmaskSME::ArmInOut;
case FunctionType::ARM_Preserves:
return AAPCSBitmaskSME::ArmPreserves;
default:
llvm_unreachable("Unrecognised SME attribute");
}
}

// The mangling scheme for function types which have SME attributes is
// implemented as a "pseudo" template:
//
// '__SME_ATTRS<<normal_function_type>, <sme_state>>'
//
// Combining the function type with a bitmask representing the streaming and ZA
// properties of the function's interface.
//
// Mangling of SME keywords is described in more detail in the AArch64 ACLE:
// https://github.com/ARM-software/acle/blob/main/main/acle.md#c-mangling-of-sme-keywords
//
void CXXNameMangler::mangleSMEAttrs(unsigned SMEAttrs) {
if (!SMEAttrs)
return;

AAPCSBitmaskSME Bitmask = AAPCSBitmaskSME(0);
if (SMEAttrs & FunctionType::SME_PStateSMEnabledMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingBit;
else if (SMEAttrs & FunctionType::SME_PStateSMCompatibleMask)
Bitmask |= AAPCSBitmaskSME::ArmStreamingCompatibleBit;

// TODO: Must represent __arm_agnostic("sme_za_state")

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZAState(SMEAttrs))
<< AAPCSBitmaskSME::ZA_Shift;

Bitmask |= encodeAAPCSZAState(FunctionType::getArmZT0State(SMEAttrs))
<< AAPCSBitmaskSME::ZT0_Shift;

Out << "Lj" << static_cast<unsigned>(Bitmask) << "EE";
}

void
CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// Vendor-specific qualifiers are emitted in reverse alphabetical order.
Expand Down Expand Up @@ -3569,6 +3633,11 @@ CXXNameMangler::mangleExtParameterInfo(FunctionProtoType::ExtParameterInfo PI) {
// <function-type> ::= [<CV-qualifiers>] F [Y]
// <bare-function-type> [<ref-qualifier>] E
void CXXNameMangler::mangleType(const FunctionProtoType *T) {
unsigned SMEAttrs = T->getAArch64SMEAttributes();

if (SMEAttrs)
Out << "11__SME_ATTRSI";

mangleExtFunctionInfo(T);

// Mangle CV-qualifiers, if present. These are 'this' qualifiers,
Expand Down Expand Up @@ -3603,6 +3672,8 @@ void CXXNameMangler::mangleType(const FunctionProtoType *T) {
mangleRefQualifier(T->getRefQualifier());

Out << 'E';

mangleSMEAttrs(SMEAttrs);
}

void CXXNameMangler::mangleType(const FunctionNoProtoType *T) {
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/AST/Type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4723,7 +4723,9 @@ LinkageInfo LinkageComputer::computeTypeLinkageInfo(const Type *T) {
case Type::Pipe:
return computeTypeLinkageInfo(cast<PipeType>(T)->getElementType());
case Type::HLSLAttributedResource:
llvm_unreachable("not yet implemented");
return computeTypeLinkageInfo(cast<HLSLAttributedResourceType>(T)
->getContainedType()
->getCanonicalTypeInternal());
}

llvm_unreachable("unhandled type class");
Expand Down
34 changes: 34 additions & 0 deletions clang/lib/Basic/Targets/WebAssembly.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ bool WebAssemblyTargetInfo::hasFeature(StringRef Feature) const {
return llvm::StringSwitch<bool>(Feature)
.Case("atomics", HasAtomics)
.Case("bulk-memory", HasBulkMemory)
.Case("bulk-memory-opt", HasBulkMemoryOpt)
.Case("call-indirect-overlong", HasCallIndirectOverlong)
.Case("exception-handling", HasExceptionHandling)
.Case("extended-const", HasExtendedConst)
.Case("fp16", HasFP16)
Expand Down Expand Up @@ -79,6 +81,8 @@ void WebAssemblyTargetInfo::getTargetDefines(const LangOptions &Opts,
Builder.defineMacro("__wasm_atomics__");
if (HasBulkMemory)
Builder.defineMacro("__wasm_bulk_memory__");
if (HasBulkMemoryOpt)
Builder.defineMacro("__wasm_bulk_memory_opt__");
if (HasExceptionHandling)
Builder.defineMacro("__wasm_exception_handling__");
if (HasExtendedConst)
Expand Down Expand Up @@ -155,6 +159,8 @@ bool WebAssemblyTargetInfo::initFeatureMap(
const std::vector<std::string> &FeaturesVec) const {
auto addGenericFeatures = [&]() {
Features["bulk-memory"] = true;
Features["bulk-memory-opt"] = true;
Features["call-indirect-overlong"] = true;
Features["multivalue"] = true;
Features["mutable-globals"] = true;
Features["nontrapping-fptoint"] = true;
Expand Down Expand Up @@ -200,6 +206,22 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
HasBulkMemory = false;
continue;
}
if (Feature == "+bulk-memory-opt") {
HasBulkMemoryOpt = true;
continue;
}
if (Feature == "-bulk-memory-opt") {
HasBulkMemoryOpt = false;
continue;
}
if (Feature == "+call-indirect-overlong") {
HasCallIndirectOverlong = true;
continue;
}
if (Feature == "-call-indirect-overlong") {
HasCallIndirectOverlong = false;
continue;
}
if (Feature == "+exception-handling") {
HasExceptionHandling = true;
continue;
Expand Down Expand Up @@ -310,6 +332,18 @@ bool WebAssemblyTargetInfo::handleTargetFeatures(
<< Feature << "-target-feature";
return false;
}

// bulk-memory-opt is a subset of bulk-memory.
if (HasBulkMemory) {
HasBulkMemoryOpt = true;
}

// The reference-types feature included the change to `call_indirect`
// encodings to support overlong immediates.
if (HasReferenceTypes) {
HasCallIndirectOverlong = true;
}

return true;
}

Expand Down
42 changes: 22 additions & 20 deletions clang/lib/Basic/Targets/WebAssembly.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,26 +22,26 @@ namespace clang {
namespace targets {

static const unsigned WebAssemblyAddrSpaceMap[] = {
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
0, // ptr32_sptr
0, // ptr32_uptr
0, // ptr64
0, // hlsl_groupshared
20, // wasm_funcref
};

Expand All @@ -55,6 +55,8 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyTargetInfo : public TargetInfo {

bool HasAtomics = false;
bool HasBulkMemory = false;
bool HasBulkMemoryOpt = false;
bool HasCallIndirectOverlong = false;
bool HasExceptionHandling = false;
bool HasExtendedConst = false;
bool HasFP16 = false;
Expand Down
3 changes: 0 additions & 3 deletions clang/lib/CIR/FrontendAction/CIRGenAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,6 @@ class CIRGenConsumer : public clang::ASTConsumer {
MlirModule->print(*OutputStream, Flags);
}
break;
default:
llvm_unreachable("NYI: CIRGenAction other than EmitCIR");
break;
}
}
};
Expand Down
14 changes: 14 additions & 0 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19060,6 +19060,16 @@ Value *CodeGenFunction::EmitHLSLBuiltinExpr(unsigned BuiltinID,
return nullptr;

switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_resource_getpointer: {
Value *HandleOp = EmitScalarExpr(E->getArg(0));
Value *IndexOp = EmitScalarExpr(E->getArg(1));

// TODO: Map to an hlsl_device address space.
llvm::Type *RetTy = llvm::PointerType::getUnqual(getLLVMContext());

return Builder.CreateIntrinsic(RetTy, Intrinsic::dx_resource_getpointer,
ArrayRef<Value *>{HandleOp, IndexOp});
}
case Builtin::BI__builtin_hlsl_all: {
Value *Op0 = EmitScalarExpr(E->getArg(0));
return Builder.CreateIntrinsic(
Expand Down Expand Up @@ -19726,6 +19736,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
case AMDGPU::BI__builtin_amdgcn_ds_read_tr4_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr8_b64_v2i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr6_b96_v3i32:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16: {
Intrinsic::ID IID;
switch (BuiltinID) {
Expand All @@ -19751,6 +19763,8 @@ Value *CodeGenFunction::EmitAMDGPUBuiltinExpr(unsigned BuiltinID,
IID = Intrinsic::amdgcn_ds_read_tr6_b96;
break;
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4i16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4f16:
case AMDGPU::BI__builtin_amdgcn_ds_read_tr16_b64_v4bf16:
IID = Intrinsic::amdgcn_ds_read_tr16_b64;
break;
}
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/CodeGen/CGCall.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1314,10 +1314,10 @@ static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
}
if (ScalableDstTy->getElementType() == FixedSrcTy->getElementType()) {
auto *Load = CGF.Builder.CreateLoad(Src);
auto *UndefVec = llvm::UndefValue::get(ScalableDstTy);
auto *PoisonVec = llvm::PoisonValue::get(ScalableDstTy);
auto *Zero = llvm::Constant::getNullValue(CGF.CGM.Int64Ty);
llvm::Value *Result = CGF.Builder.CreateInsertVector(
ScalableDstTy, UndefVec, Load, Zero, "cast.scalable");
ScalableDstTy, PoisonVec, Load, Zero, "cast.scalable");
if (ScalableDstTy != Ty)
Result = CGF.Builder.CreateBitCast(Result, Ty);
return Result;
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,7 +602,8 @@ static bool checkAliasedGlobal(
// mangled name.
for (const auto &[Decl, Name] : MangledDeclNames) {
if (const auto *ND = dyn_cast<NamedDecl>(Decl.getDecl())) {
if (ND->getName() == GV->getName()) {
IdentifierInfo *II = ND->getIdentifier();
if (II && II->getName() == GV->getName()) {
Diags.Report(Location, diag::note_alias_mangled_name_alternative)
<< Name
<< FixItHint::CreateReplacement(
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1348,6 +1348,7 @@ static bool isSignedCharDefault(const llvm::Triple &Triple) {
case llvm::Triple::riscv64:
case llvm::Triple::systemz:
case llvm::Triple::xcore:
case llvm::Triple::xtensa:
return false;
}
}
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8119,6 +8119,14 @@ void Parser::ParseParameterDeclarationClause(
}

if (TryConsumeToken(tok::ellipsis, EllipsisLoc)) {
if (getLangOpts().CPlusPlus26) {
// C++26 [dcl.dcl.fct]p3:
// A parameter-declaration-clause of the form
// parameter-list '...' is deprecated.
Diag(EllipsisLoc, diag::warn_deprecated_missing_comma_before_ellipsis)
<< FixItHint::CreateInsertion(EllipsisLoc, ", ");
}

if (!getLangOpts().CPlusPlus) {
// We have ellipsis without a preceding ',', which is ill-formed
// in C. Complain and provide the fix.
Expand Down
188 changes: 87 additions & 101 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,8 @@ struct BuiltinTypeDeclBuilder {
assert(!Record->isCompleteDefinition() && "record is already complete");

ASTContext &Ctx = SemaRef.getASTContext();
TypeSourceInfo *ElementTypeInfo = nullptr;

QualType ElemTy = Ctx.Char8Ty;
if (Template)
ElemTy = getFirstTemplateTypeParam();
ElementTypeInfo = Ctx.getTrivialTypeSourceInfo(ElemTy, SourceLocation());
TypeSourceInfo *ElementTypeInfo =
Ctx.getTrivialTypeSourceInfo(getHandleElementType(), SourceLocation());

// add handle member with resource type attributes
QualType AttributedResTy = QualType();
Expand Down Expand Up @@ -171,80 +167,12 @@ struct BuiltinTypeDeclBuilder {
}

BuiltinTypeDeclBuilder &addArraySubscriptOperators() {
addArraySubscriptOperator(true);
addArraySubscriptOperator(false);
return *this;
}

BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
assert(!Record->isCompleteDefinition() && "record is already complete");

ASTContext &AST = Record->getASTContext();
QualType ElemTy = AST.Char8Ty;
if (Template)
ElemTy = getFirstTemplateTypeParam();
QualType ReturnTy = ElemTy;

FunctionProtoType::ExtProtoInfo ExtInfo;

// Subscript operators return references to elements, const makes the
// reference and method const so that the underlying data is not mutable.
if (IsConst) {
ExtInfo.TypeQuals.addConst();
ReturnTy.addConst();
}
ReturnTy = AST.getLValueReferenceType(ReturnTy);

QualType MethodTy =
AST.getFunctionType(ReturnTy, {AST.UnsignedIntTy}, ExtInfo);
auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
auto *MethodDecl = CXXMethodDecl::Create(
AST, Record, SourceLocation(),
DeclarationNameInfo(
AST.DeclarationNames.getCXXOperatorName(OO_Subscript),
SourceLocation()),
MethodTy, TSInfo, SC_None, false, false, ConstexprSpecKind::Unspecified,
SourceLocation());

IdentifierInfo &II = AST.Idents.get("Idx", tok::TokenKind::identifier);
auto *IdxParam = ParmVarDecl::Create(
AST, MethodDecl->getDeclContext(), SourceLocation(), SourceLocation(),
&II, AST.UnsignedIntTy,
AST.getTrivialTypeSourceInfo(AST.UnsignedIntTy, SourceLocation()),
SC_None, nullptr);
MethodDecl->setParams({IdxParam});

// Also add the parameter to the function prototype.
auto FnProtoLoc = TSInfo->getTypeLoc().getAs<FunctionProtoTypeLoc>();
FnProtoLoc.setParam(0, IdxParam);

// FIXME: Placeholder to make sure we return the correct type - create
// field of element_type and return reference to it. This field will go
// away once indexing into resources is properly implemented in
// llvm/llvm-project#95956.
if (Fields.count("e") == 0) {
addMemberVariable("e", ElemTy, {});
}
FieldDecl *ElemFieldDecl = Fields["e"];

auto *This =
CXXThisExpr::Create(AST, SourceLocation(),
MethodDecl->getFunctionObjectParameterType(), true);
Expr *ElemField = MemberExpr::CreateImplicit(
AST, This, false, ElemFieldDecl, ElemFieldDecl->getType(), VK_LValue,
OK_Ordinary);
auto *Return =
ReturnStmt::Create(AST, SourceLocation(), ElemField, nullptr);

MethodDecl->setBody(CompoundStmt::Create(AST, {Return}, FPOptionsOverride(),
SourceLocation(),
SourceLocation()));
MethodDecl->setLexicalDeclContext(Record);
MethodDecl->setAccess(AccessSpecifier::AS_public);
MethodDecl->addAttr(AlwaysInlineAttr::CreateImplicit(
AST, SourceRange(), AlwaysInlineAttr::CXX11_clang_always_inline));
Record->addDecl(MethodDecl);
DeclarationName Subscript =
AST.DeclarationNames.getCXXOperatorName(OO_Subscript);

addHandleAccessFunction(Subscript, /*IsConst=*/true, /*IsRef=*/true);
addHandleAccessFunction(Subscript, /*IsConst=*/false, /*IsRef=*/true);
return *this;
}

Expand All @@ -265,6 +193,13 @@ struct BuiltinTypeDeclBuilder {
return QualType();
}

QualType getHandleElementType() {
if (Template)
return getFirstTemplateTypeParam();
// TODO: Should we default to VoidTy? Using `i8` is arguably ambiguous.
return SemaRef.getASTContext().Char8Ty;
}

BuiltinTypeDeclBuilder &startDefinition() {
assert(!Record->isCompleteDefinition() && "record is already complete");
Record->startDefinition();
Expand Down Expand Up @@ -294,6 +229,8 @@ struct BuiltinTypeDeclBuilder {
// Builtin types methods
BuiltinTypeDeclBuilder &addIncrementCounterMethod();
BuiltinTypeDeclBuilder &addDecrementCounterMethod();
BuiltinTypeDeclBuilder &addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef);
};

struct TemplateParameterListBuilder {
Expand Down Expand Up @@ -453,7 +390,7 @@ struct TemplateParameterListBuilder {
// Builder for methods of builtin types. Allows adding methods to builtin types
// using the builder pattern like this:
//
// BuiltinTypeMethodBuilder(Sema, RecordBuilder, "MethodName", ReturnType)
// BuiltinTypeMethodBuilder(RecordBuilder, "MethodName", ReturnType)
// .addParam("param_name", Type, InOutModifier)
// .callBuiltin("builtin_name", BuiltinParams...)
// .finalizeMethod();
Expand Down Expand Up @@ -486,6 +423,7 @@ struct BuiltinTypeMethodBuilder {
DeclarationNameInfo NameInfo;
QualType ReturnTy;
CXXMethodDecl *Method;
bool IsConst;
llvm::SmallVector<MethodParam> Params;
llvm::SmallVector<Stmt *> StmtsList;

Expand All @@ -508,11 +446,16 @@ struct BuiltinTypeMethodBuilder {
Expr *convertPlaceholder(Expr *E) { return E; }

public:
BuiltinTypeMethodBuilder(Sema &S, BuiltinTypeDeclBuilder &DB, StringRef Name,
QualType ReturnTy)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr) {
BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, DeclarationName &Name,
QualType ReturnTy, bool IsConst = false)
: DeclBuilder(DB), NameInfo(DeclarationNameInfo(Name, SourceLocation())),
ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {}

BuiltinTypeMethodBuilder(BuiltinTypeDeclBuilder &DB, StringRef Name,
QualType ReturnTy, bool IsConst = false)
: DeclBuilder(DB), ReturnTy(ReturnTy), Method(nullptr), IsConst(IsConst) {
const IdentifierInfo &II =
S.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
DB.SemaRef.getASTContext().Idents.get(Name, tok::TokenKind::identifier);
NameInfo = DeclarationNameInfo(DeclarationName(&II), SourceLocation());
}

Expand All @@ -535,8 +478,12 @@ struct BuiltinTypeMethodBuilder {
SmallVector<QualType> ParamTypes;
for (MethodParam &MP : Params)
ParamTypes.emplace_back(MP.Ty);
QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes,
FunctionProtoType::ExtProtoInfo());

FunctionProtoType::ExtProtoInfo ExtInfo;
if (IsConst)
ExtInfo.TypeQuals.addConst();

QualType MethodTy = AST.getFunctionType(ReturnTy, ParamTypes, ExtInfo);

// create method decl
auto *TSInfo = AST.getTrivialTypeSourceInfo(MethodTy, SourceLocation());
Expand Down Expand Up @@ -586,7 +533,8 @@ struct BuiltinTypeMethodBuilder {
}

template <typename... Ts>
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName, Ts... ArgSpecs) {
BuiltinTypeMethodBuilder &callBuiltin(StringRef BuiltinName,
QualType ReturnType, Ts... ArgSpecs) {
std::array<Expr *, sizeof...(ArgSpecs)> Args{
convertPlaceholder(std::forward<Ts>(ArgSpecs))...};

Expand All @@ -599,15 +547,32 @@ struct BuiltinTypeMethodBuilder {
FunctionDecl *FD = lookupBuiltinFunction(DeclBuilder.SemaRef, BuiltinName);
DeclRefExpr *DRE = DeclRefExpr::Create(
AST, NestedNameSpecifierLoc(), SourceLocation(), FD, false,
FD->getNameInfo(), FD->getType(), VK_PRValue);
FD->getNameInfo(), AST.BuiltinFnTy, VK_PRValue);

if (ReturnType.isNull())
ReturnType = FD->getReturnType();

Expr *Call =
CallExpr::Create(AST, DRE, Args, FD->getReturnType(), VK_PRValue,
SourceLocation(), FPOptionsOverride());
Expr *Call = CallExpr::Create(AST, DRE, Args, ReturnType, VK_PRValue,
SourceLocation(), FPOptionsOverride());
StmtsList.push_back(Call);
return *this;
}

BuiltinTypeMethodBuilder &dereference() {
assert(!StmtsList.empty() && "Nothing to dereference");
ASTContext &AST = DeclBuilder.SemaRef.getASTContext();

Expr *LastExpr = dyn_cast<Expr>(StmtsList.back());
assert(LastExpr && "No expression to dereference");
Expr *Deref = UnaryOperator::Create(
AST, LastExpr, UO_Deref, LastExpr->getType()->getPointeeType(),
VK_PRValue, OK_Ordinary, SourceLocation(),
/*CanOverflow=*/false, FPOptionsOverride());
StmtsList.pop_back();
StmtsList.push_back(Deref);
return *this;
}

BuiltinTypeDeclBuilder &finalizeMethod() {
assert(!DeclBuilder.Record->isCompleteDefinition() &&
"record is already complete");
Expand All @@ -621,11 +586,8 @@ struct BuiltinTypeMethodBuilder {
"nothing to return from non-void method");
if (ReturnTy != AST.VoidTy) {
if (Expr *LastExpr = dyn_cast<Expr>(StmtsList.back())) {
assert(AST.hasSameUnqualifiedType(
isa<CallExpr>(LastExpr)
? cast<CallExpr>(LastExpr)->getCallReturnType(AST)
: LastExpr->getType(),
ReturnTy) &&
assert(AST.hasSameUnqualifiedType(LastExpr->getType(),
ReturnTy.getNonReferenceType()) &&
"Return type of the last statement must match the return type "
"of the method");
if (!isa<ReturnStmt>(LastExpr)) {
Expand Down Expand Up @@ -672,19 +634,43 @@ BuiltinTypeDeclBuilder::addSimpleTemplateParams(ArrayRef<StringRef> Names,

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addIncrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "IncrementCounter",
return BuiltinTypeMethodBuilder(*this, "IncrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(1))
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
PH::Handle, getConstantIntExpr(1))
.finalizeMethod();
}

BuiltinTypeDeclBuilder &BuiltinTypeDeclBuilder::addDecrementCounterMethod() {
using PH = BuiltinTypeMethodBuilder::PlaceHolder;
return BuiltinTypeMethodBuilder(SemaRef, *this, "DecrementCounter",
return BuiltinTypeMethodBuilder(*this, "DecrementCounter",
SemaRef.getASTContext().UnsignedIntTy)
.callBuiltin("__builtin_hlsl_buffer_update_counter", PH::Handle,
getConstantIntExpr(-1))
.callBuiltin("__builtin_hlsl_buffer_update_counter", QualType(),
PH::Handle, getConstantIntExpr(-1))
.finalizeMethod();
}

BuiltinTypeDeclBuilder &
BuiltinTypeDeclBuilder::addHandleAccessFunction(DeclarationName &Name,
bool IsConst, bool IsRef) {
assert(!Record->isCompleteDefinition() && "record is already complete");
ASTContext &AST = SemaRef.getASTContext();
using PH = BuiltinTypeMethodBuilder::PlaceHolder;

QualType ElemTy = getHandleElementType();
// TODO: Map to an hlsl_device address space.
QualType ElemPtrTy = AST.getPointerType(ElemTy);
QualType ReturnTy = ElemTy;
if (IsConst)
ReturnTy.addConst();
if (IsRef)
ReturnTy = AST.getLValueReferenceType(ReturnTy);

return BuiltinTypeMethodBuilder(*this, Name, ReturnTy, IsConst)
.addParam("Index", AST.UnsignedIntTy)
.callBuiltin("__builtin_hlsl_resource_getpointer", ElemPtrTy, PH::Handle,
PH::_0)
.dereference()
.finalizeMethod();
}

Expand Down
58 changes: 36 additions & 22 deletions clang/lib/Sema/SemaAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,34 +270,48 @@ void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
}

void Sema::inferLifetimeCaptureByAttribute(FunctionDecl *FD) {
if (!FD)
auto *MD = dyn_cast_if_present<CXXMethodDecl>(FD);
if (!MD || !MD->getParent()->isInStdNamespace())
return;
auto *MD = dyn_cast<CXXMethodDecl>(FD);
if (!MD || !MD->getIdentifier() || !MD->getParent()->isInStdNamespace())
auto Annotate = [this](const FunctionDecl *MD) {
// Do not infer if any parameter is explicitly annotated.
for (ParmVarDecl *PVD : MD->parameters())
if (PVD->hasAttr<LifetimeCaptureByAttr>())
return;
for (ParmVarDecl *PVD : MD->parameters()) {
// Methods in standard containers that capture values typically accept
// reference-type parameters, e.g., `void push_back(const T& value)`.
// We only apply the lifetime_capture_by attribute to parameters of
// pointer-like reference types (`const T&`, `T&&`).
if (PVD->getType()->isReferenceType() &&
sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
PVD->addAttr(
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
}
}
};

if (!MD->getIdentifier()) {
static const llvm::StringSet<> MapLikeContainer{
"map",
"multimap",
"unordered_map",
"unordered_multimap",
};
// Infer for the map's operator []:
// std::map<string_view, ...> m;
// m[ReturnString(..)] = ...; // !dangling references in m.
if (MD->getOverloadedOperator() == OO_Subscript &&
MapLikeContainer.contains(MD->getParent()->getName()))
Annotate(MD);
return;
// FIXME: Infer for operator[] for map-like containers. For example:
// std::map<string_view, ...> m;
// m[ReturnString(..)] = ...;
}
static const llvm::StringSet<> CapturingMethods{"insert", "push",
"push_front", "push_back"};
if (!CapturingMethods.contains(MD->getName()))
return;
// Do not infer if any parameter is explicitly annotated.
for (ParmVarDecl *PVD : MD->parameters())
if (PVD->hasAttr<LifetimeCaptureByAttr>())
return;
for (ParmVarDecl *PVD : MD->parameters()) {
// Methods in standard containers that capture values typically accept
// reference-type parameters, e.g., `void push_back(const T& value)`.
// We only apply the lifetime_capture_by attribute to parameters of
// pointer-like reference types (`const T&`, `T&&`).
if (PVD->getType()->isReferenceType() &&
sema::isPointerLikeType(PVD->getType().getNonReferenceType())) {
int CaptureByThis[] = {LifetimeCaptureByAttr::THIS};
PVD->addAttr(
LifetimeCaptureByAttr::CreateImplicit(Context, CaptureByThis, 1));
}
}
Annotate(MD);
}

void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
Expand Down
21 changes: 18 additions & 3 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15519,10 +15519,25 @@ LambdaScopeInfo *Sema::RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator) {
LSI->CallOperator = CallOperator;
LSI->Lambda = LambdaClass;
LSI->ReturnType = CallOperator->getReturnType();
// This function in calls in situation where the context of the call operator
// is not entered, so we set AfterParameterList to false, so that
// When this function is called in situation where the context of the call
// operator is not entered, we set AfterParameterList to false, so that
// `tryCaptureVariable` finds explicit captures in the appropriate context.
LSI->AfterParameterList = false;
// There is also at least a situation as in FinishTemplateArgumentDeduction(),
// where we would set the CurContext to the lambda operator before
// substituting into it. In this case the flag needs to be true such that
// tryCaptureVariable can correctly handle potential captures thereof.
LSI->AfterParameterList = CurContext == CallOperator;

// GLTemplateParameterList is necessary for getCurGenericLambda() which is
// used at the point of dealing with potential captures.
//
// We don't use LambdaClass->isGenericLambda() because this value doesn't
// flip for instantiated generic lambdas, where no FunctionTemplateDecls are
// associated. (Technically, we could recover that list from their
// instantiation patterns, but for now, the GLTemplateParameterList seems
// unnecessary in these cases.)
if (FunctionTemplateDecl *FTD = CallOperator->getDescribedFunctionTemplate())
LSI->GLTemplateParameterList = FTD->getTemplateParameters();
const LambdaCaptureDefault LCD = LambdaClass->getLambdaCaptureDefault();

if (LCD == LCD_None)
Expand Down
40 changes: 17 additions & 23 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11451,29 +11451,23 @@ bool Sema::CheckDeductionGuideDeclarator(Declarator &D, QualType &R,
bool MightInstantiateToSpecialization = false;
if (auto RetTST =
TSI->getTypeLoc().getAsAdjusted<TemplateSpecializationTypeLoc>()) {
const TemplateSpecializationType *TST = RetTST.getTypePtr();
while (TST && TST->isTypeAlias())
TST = TST->getAliasedType()->getAs<TemplateSpecializationType>();

if (TST) {
TemplateName SpecifiedName = TST->getTemplateName();
bool TemplateMatches = Context.hasSameTemplateName(
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);

const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
assert(Qualifiers && "expected QualifiedTemplate");
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
Qualifiers->getQualifier() == nullptr;
if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
// names the wrong class template.
auto *TD = SpecifiedName.getAsTemplateDecl();
MightInstantiateToSpecialization =
!(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
}
TemplateName SpecifiedName = RetTST.getTypePtr()->getTemplateName();
bool TemplateMatches = Context.hasSameTemplateName(
SpecifiedName, GuidedTemplate, /*IgnoreDeduced=*/true);

const QualifiedTemplateName *Qualifiers =
SpecifiedName.getAsQualifiedTemplateName();
assert(Qualifiers && "expected QualifiedTemplate");
bool SimplyWritten = !Qualifiers->hasTemplateKeyword() &&
Qualifiers->getQualifier() == nullptr;
if (SimplyWritten && TemplateMatches)
AcceptableReturnType = true;
else {
// This could still instantiate to the right type, unless we know it
// names the wrong class template.
auto *TD = SpecifiedName.getAsTemplateDecl();
MightInstantiateToSpecialization =
!(TD && isa<ClassTemplateDecl>(TD) && !TemplateMatches);
}
} else if (!RetTy.hasQualifiers() && RetTy->isDependentType()) {
MightInstantiateToSpecialization = true;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,9 @@ Sema::VarArgKind Sema::isValidVarArgType(const QualType &Ty) {
if (Ty->isObjCObjectType())
return VAK_Invalid;

if (getLangOpts().HLSL && Ty->getAs<HLSLAttributedResourceType>())
return VAK_Valid;

if (getLangOpts().MSVCCompat)
return VAK_MSVCUndefined;

Expand Down
18 changes: 17 additions & 1 deletion clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1908,7 +1908,7 @@ static bool CheckResourceHandle(
const HLSLAttributedResourceType *ResTy =
ArgType.getTypePtr()->getAs<HLSLAttributedResourceType>();
if (!ResTy) {
S->Diag(TheCall->getArg(0)->getBeginLoc(),
S->Diag(TheCall->getArg(ArgIndex)->getBeginLoc(),
diag::err_typecheck_expect_hlsl_resource)
<< ArgType;
return true;
Expand All @@ -1926,6 +1926,22 @@ static bool CheckResourceHandle(
// returning an ExprError
bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
switch (BuiltinID) {
case Builtin::BI__builtin_hlsl_resource_getpointer: {
if (SemaRef.checkArgCount(TheCall, 2) ||
CheckResourceHandle(&SemaRef, TheCall, 0) ||
CheckArgTypeMatches(&SemaRef, TheCall->getArg(1),
SemaRef.getASTContext().UnsignedIntTy))
return true;

auto *ResourceTy =
TheCall->getArg(0)->getType()->castAs<HLSLAttributedResourceType>();
QualType ContainedTy = ResourceTy->getContainedType();
// TODO: Map to an hlsl_device address space.
TheCall->setType(getASTContext().getPointerType(ContainedTy));
TheCall->setValueKind(VK_LValue);

break;
}
case Builtin::BI__builtin_hlsl_all:
case Builtin::BI__builtin_hlsl_any: {
if (SemaRef.checkArgCount(TheCall, 1))
Expand Down
72 changes: 39 additions & 33 deletions clang/lib/Sema/SemaOpenACC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -598,9 +598,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitDefaultClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitTileClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// TODO OpenACC: Remove this when we get combined construct impl for this.
if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
return isNotImplemented();

// Duplicates here are not really sensible. We could possible permit
// multiples if they all had the same value, but there isn't really a good
Expand Down Expand Up @@ -877,10 +874,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitPresentClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
// Restrictions only properly implemented on 'compute'/'combined' constructs,
// and 'compute'/'combined' constructs are the only construct that can do
// anything with this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
!isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
return isNotImplemented();
// ActOnVar ensured that everything is a valid variable reference, so there
// really isn't anything to do here. GCC does some duplicate-finding, though
Expand All @@ -893,10 +891,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
// Restrictions only properly implemented on 'compute'/'combined' constructs,
// and 'compute'/'combined' constructs are the only construct that can do
// anything with this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
!isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
return isNotImplemented();
// ActOnVar ensured that everything is a valid variable reference, so there
// really isn't anything to do here. GCC does some duplicate-finding, though
Expand All @@ -909,10 +908,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyInClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
// Restrictions only properly implemented on 'compute'/'combined' constructs,
// and 'compute'/'combined' constructs are the only construct that can do
// anything with this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
!isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
return isNotImplemented();
// ActOnVar ensured that everything is a valid variable reference, so there
// really isn't anything to do here. GCC does some duplicate-finding, though
Expand All @@ -925,10 +925,11 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitCopyOutClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitCreateClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// Restrictions only properly implemented on 'compute' constructs, and
// 'compute' constructs are the only construct that can do anything with
// this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()))
// Restrictions only properly implemented on 'compute'/'combined' constructs,
// and 'compute'/'combined' constructs are the only construct that can do
// anything with this yet, so skip/treat as unimplemented in this case.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
!isOpenACCCombinedDirectiveKind(Clause.getDirectiveKind()))
return isNotImplemented();
// ActOnVar ensured that everything is a valid variable reference, so there
// really isn't anything to do here. GCC does some duplicate-finding, though
Expand Down Expand Up @@ -1500,10 +1501,6 @@ OpenACCClause *SemaOpenACCClauseVisitor::VisitReductionClause(

OpenACCClause *SemaOpenACCClauseVisitor::VisitCollapseClause(
SemaOpenACC::OpenACCParsedClause &Clause) {
// TODO: Remove this check once we implement this for combined constructs.
if (!isOpenACCComputeDirectiveKind(Clause.getDirectiveKind()) &&
Clause.getDirectiveKind() != OpenACCDirectiveKind::Loop)
return isNotImplemented();
// Duplicates here are not really sensible. We could possible permit
// multiples if they all had the same value, but there isn't really a good
// reason to do so. Also, this simplifies the suppression of duplicates, in
Expand Down Expand Up @@ -1697,6 +1694,7 @@ void SemaOpenACC::AssociatedStmtRAII::SetCollapseInfoBeforeAssociatedStmt(
SemaRef.CollapseInfo.CollapseDepthSatisfied = false;
SemaRef.CollapseInfo.CurCollapseCount =
cast<ConstantExpr>(LoopCount)->getResultAsAPSInt();
SemaRef.CollapseInfo.DirectiveKind = DirKind;
}

void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt(
Expand All @@ -1717,6 +1715,7 @@ void SemaOpenACC::AssociatedStmtRAII::SetTileInfoBeforeAssociatedStmt(
SemaRef.TileInfo.ActiveTile = TileClause;
SemaRef.TileInfo.TileDepthSatisfied = false;
SemaRef.TileInfo.CurTileCount = TileClause->getSizeExprs().size();
SemaRef.TileInfo.DirectiveKind = DirKind;
}

SemaOpenACC::AssociatedStmtRAII::~AssociatedStmtRAII() {
Expand Down Expand Up @@ -2593,7 +2592,8 @@ void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {

if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(WhileLoc, diag::err_acc_invalid_in_loop)
<< /*while loop*/ 1 << OpenACCClauseKind::Collapse;
<< /*while loop*/ 1 << CollapseInfo.DirectiveKind
<< OpenACCClauseKind::Collapse;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_active_clause_here)
Expand All @@ -2606,7 +2606,8 @@ void SemaOpenACC::ActOnWhileStmt(SourceLocation WhileLoc) {

if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
Diag(WhileLoc, diag::err_acc_invalid_in_loop)
<< /*while loop*/ 1 << OpenACCClauseKind::Tile;
<< /*while loop*/ 1 << TileInfo.DirectiveKind
<< OpenACCClauseKind::Tile;
assert(TileInfo.ActiveTile && "tile count without object?");
Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Tile;
Expand All @@ -2626,7 +2627,8 @@ void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {

if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(DoLoc, diag::err_acc_invalid_in_loop)
<< /*do loop*/ 2 << OpenACCClauseKind::Collapse;
<< /*do loop*/ 2 << CollapseInfo.DirectiveKind
<< OpenACCClauseKind::Collapse;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_active_clause_here)
Expand All @@ -2639,7 +2641,7 @@ void SemaOpenACC::ActOnDoStmt(SourceLocation DoLoc) {

if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
Diag(DoLoc, diag::err_acc_invalid_in_loop)
<< /*do loop*/ 2 << OpenACCClauseKind::Tile;
<< /*do loop*/ 2 << TileInfo.DirectiveKind << OpenACCClauseKind::Tile;
assert(TileInfo.ActiveTile && "tile count without object?");
Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Tile;
Expand All @@ -2666,7 +2668,8 @@ void SemaOpenACC::ForStmtBeginHelper(SourceLocation ForLoc,
// This checks for more than 1 loop at the current level, the
// 'depth'-satisifed checking manages the 'not zero' case.
if (LoopInfo.CurLevelHasLoopAlready) {
Diag(ForLoc, diag::err_acc_clause_multiple_loops) << /*Collapse*/ 0;
Diag(ForLoc, diag::err_acc_clause_multiple_loops)
<< CollapseInfo.DirectiveKind << OpenACCClauseKind::Collapse;
assert(CollapseInfo.ActiveCollapse && "No collapse object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_active_clause_here)
Expand All @@ -2685,7 +2688,8 @@ void SemaOpenACC::ForStmtBeginHelper(SourceLocation ForLoc,
C.check();

if (LoopInfo.CurLevelHasLoopAlready) {
Diag(ForLoc, diag::err_acc_clause_multiple_loops) << /*Tile*/ 1;
Diag(ForLoc, diag::err_acc_clause_multiple_loops)
<< TileInfo.DirectiveKind << OpenACCClauseKind::Tile;
assert(TileInfo.ActiveTile && "No tile object?");
Diag(TileInfo.ActiveTile->getBeginLoc(),
diag::note_acc_active_clause_here)
Expand Down Expand Up @@ -3188,15 +3192,15 @@ void SemaOpenACC::ActOnForStmtEnd(SourceLocation ForLoc, StmtResult Body) {

if (OtherStmtLoc.isValid() && IsActiveCollapse) {
Diag(OtherStmtLoc, diag::err_acc_intervening_code)
<< OpenACCClauseKind::Collapse;
<< OpenACCClauseKind::Collapse << CollapseInfo.DirectiveKind;
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Collapse;
}

if (OtherStmtLoc.isValid() && IsActiveTile) {
Diag(OtherStmtLoc, diag::err_acc_intervening_code)
<< OpenACCClauseKind::Tile;
<< OpenACCClauseKind::Tile << TileInfo.DirectiveKind;
Diag(TileInfo.ActiveTile->getBeginLoc(),
diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Tile;
Expand All @@ -3216,15 +3220,17 @@ bool SemaOpenACC::ActOnStartStmtDirective(OpenACCDirectiveKind K,
// ALL constructs are ill-formed if there is an active 'collapse'
if (CollapseInfo.CurCollapseCount && *CollapseInfo.CurCollapseCount > 0) {
Diag(StartLoc, diag::err_acc_invalid_in_loop)
<< /*OpenACC Construct*/ 0 << OpenACCClauseKind::Collapse << K;
<< /*OpenACC Construct*/ 0 << CollapseInfo.DirectiveKind
<< OpenACCClauseKind::Collapse << K;
assert(CollapseInfo.ActiveCollapse && "Collapse count without object?");
Diag(CollapseInfo.ActiveCollapse->getBeginLoc(),
diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Collapse;
}
if (TileInfo.CurTileCount && *TileInfo.CurTileCount > 0) {
Diag(StartLoc, diag::err_acc_invalid_in_loop)
<< /*OpenACC Construct*/ 0 << OpenACCClauseKind::Tile << K;
<< /*OpenACC Construct*/ 0 << TileInfo.DirectiveKind
<< OpenACCClauseKind::Tile << K;
assert(TileInfo.ActiveTile && "Tile count without object?");
Diag(TileInfo.ActiveTile->getBeginLoc(), diag::note_acc_active_clause_here)
<< OpenACCClauseKind::Tile;
Expand Down
11 changes: 6 additions & 5 deletions clang/lib/StaticAnalyzer/Core/CoreEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -649,14 +649,15 @@ StmtNodeBuilder::~StmtNodeBuilder() {
void BranchNodeBuilder::anchor() {}

ExplodedNode *BranchNodeBuilder::generateNode(ProgramStateRef State,
bool branch,
bool Branch,
ExplodedNode *NodePred) {
// If the branch has been marked infeasible we should not generate a node.
if (!isFeasible(branch))
const CFGBlock *Dst = Branch ? DstT : DstF;

if (!Dst)
return nullptr;

ProgramPoint Loc = BlockEdge(C.getBlock(), branch ? DstT : DstF,
NodePred->getLocationContext());
ProgramPoint Loc =
BlockEdge(C.getBlock(), Dst, NodePred->getLocationContext());
ExplodedNode *Succ = generateNodeImpl(Loc, State, NodePred);
return Succ;
}
Expand Down
37 changes: 9 additions & 28 deletions clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1647,10 +1647,8 @@ void ExprEngine::processCleanupTemporaryBranch(const CXXBindTemporaryExpr *BTE,
ProgramStateRef State = Pred->getState();
const LocationContext *LC = Pred->getLocationContext();
if (getObjectUnderConstruction(State, BTE, LC)) {
TempDtorBuilder.markInfeasible(false);
TempDtorBuilder.generateNode(State, true, Pred);
} else {
TempDtorBuilder.markInfeasible(true);
TempDtorBuilder.generateNode(State, false, Pred);
}
}
Expand Down Expand Up @@ -2770,7 +2768,6 @@ void ExprEngine::processBranch(const Stmt *Condition,
// Check for NULL conditions; e.g. "for(;;)"
if (!Condition) {
BranchNodeBuilder NullCondBldr(Pred, Dst, BldCtx, DstT, DstF);
NullCondBldr.markInfeasible(false);
NullCondBldr.generateNode(Pred->getState(), true, Pred);
return;
}
Expand All @@ -2790,40 +2787,25 @@ void ExprEngine::processBranch(const Stmt *Condition,
if (CheckersOutSet.empty())
return;

BranchNodeBuilder builder(CheckersOutSet, Dst, BldCtx, DstT, DstF);
BranchNodeBuilder Builder(CheckersOutSet, Dst, BldCtx, DstT, DstF);
for (ExplodedNode *PredN : CheckersOutSet) {
if (PredN->isSink())
continue;

ProgramStateRef PrevState = PredN->getState();

ProgramStateRef StTrue, StFalse;
ProgramStateRef StTrue = PrevState, StFalse = PrevState;
if (const auto KnownCondValueAssumption = assumeCondition(Condition, PredN))
std::tie(StTrue, StFalse) = *KnownCondValueAssumption;
else {
assert(!isa<ObjCForCollectionStmt>(Condition));
builder.generateNode(PrevState, true, PredN);
builder.generateNode(PrevState, false, PredN);
continue;
}

if (StTrue && StFalse)
assert(!isa<ObjCForCollectionStmt>(Condition));

// Process the true branch.
if (builder.isFeasible(true)) {
if (StTrue)
builder.generateNode(StTrue, true, PredN);
else
builder.markInfeasible(true);
}
if (StTrue)
Builder.generateNode(StTrue, true, PredN);

// Process the false branch.
if (builder.isFeasible(false)) {
if (StFalse)
builder.generateNode(StFalse, false, PredN);
else
builder.markInfeasible(false);
}
if (StFalse)
Builder.generateNode(StFalse, false, PredN);
}
currBldrCtx = nullptr;
}
Expand All @@ -2845,14 +2827,13 @@ void ExprEngine::processStaticInitializer(const DeclStmt *DS,
const auto *VD = cast<VarDecl>(DS->getSingleDecl());
ProgramStateRef state = Pred->getState();
bool initHasRun = state->contains<InitializedGlobalsSet>(VD);
BranchNodeBuilder builder(Pred, Dst, BuilderCtx, DstT, DstF);
BranchNodeBuilder Builder(Pred, Dst, BuilderCtx, DstT, DstF);

if (!initHasRun) {
state = state->add<InitializedGlobalsSet>(VD);
}

builder.generateNode(state, initHasRun, Pred);
builder.markInfeasible(!initHasRun);
Builder.generateNode(state, initHasRun, Pred);

currBldrCtx = nullptr;
}
Expand Down
19 changes: 19 additions & 0 deletions clang/test/AST/ByteCode/altivec.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -target-feature +altivec -target-feature +vsx -fsyntax-only -verify=expected,both %s
// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -target-feature +altivec -target-feature -vsx -fsyntax-only -verify=expected,both %s
// RUN: %clang_cc1 -triple=powerpc-ibm-aix -target-feature +altivec -fsyntax-only -verify=expected,both %s
// RUN: %clang_cc1 -triple=powerpc64-ibm-aix -target-feature +altivec -target-feature -vsx -fsyntax-only -verify=expected,both %s

// RUN: %clang_cc1 -triple=powerpc64-unknown-linux-gnu -target-feature +altivec -target-feature +vsx -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -triple=powerpc64le-unknown-linux-gnu -target-feature +altivec -target-feature -vsx -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -triple=powerpc-ibm-aix -target-feature +altivec -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter %s
// RUN: %clang_cc1 -triple=powerpc64-ibm-aix -target-feature +altivec -target-feature -vsx -fsyntax-only -verify=expected,both -fexperimental-new-constant-interpreter %s

// both-no-diagnostics.

/// From test/Parser/altivec.c
vector char v1 = (vector char)((vector int)(1, 2, 3, 4));
vector char v2 = (vector char)((vector float)(1.0f, 2.0f, 3.0f, 4.0f));
vector char v3 = (vector char)((vector int)('a', 'b', 'c', 'd'));
vector int v4 = (vector int)(1, 2, 3, 4);
vector float v5 = (vector float)(1.0f, 2.0f, 3.0f, 4.0f);
vector char v6 = (vector char)((vector int)(1+2, -2, (int)(2.0 * 3), -(5-3)));
121 changes: 120 additions & 1 deletion clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -991,7 +991,6 @@ namespace BuiltinInImplicitCtor {
static_assert(Foo.a == 0, "");
}


typedef double vector4double __attribute__((__vector_size__(32)));
typedef float vector4float __attribute__((__vector_size__(16)));
typedef long long vector4long __attribute__((__vector_size__(32)));
Expand Down Expand Up @@ -1035,3 +1034,123 @@ namespace RecuceAdd {
static_assert(reduceAddInt3 == 0);
#endif
}

namespace ReduceMul {
static_assert(__builtin_reduce_mul((vector4char){}) == 0);
static_assert(__builtin_reduce_mul((vector4char){1, 2, 3, 4}) == 24);
static_assert(__builtin_reduce_mul((vector4short){1, 2, 30, 40}) == 2400);
#ifndef __AVR__
static_assert(__builtin_reduce_mul((vector4int){10, 20, 300, 400}) == 24'000'000);
#endif
static_assert(__builtin_reduce_mul((vector4long){1000L, 2000L, 3000L, 4000L}) == 24'000'000'000'000L);
constexpr int reduceMulInt1 = __builtin_reduce_mul((vector4int){~(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'int'}}
constexpr long long reduceMulLong1 = __builtin_reduce_mul((vector4long){~(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'long long'}}
constexpr int reduceMulInt2 = __builtin_reduce_mul((vector4int){(1 << (sizeof(int) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'int'}}
constexpr long long reduceMulLong2 = __builtin_reduce_mul((vector4long){(1LL << (sizeof(long long) * 8 - 1)), 1, 1, 2});
// both-error@-1 {{must be initialized by a constant expression}} \
// both-note@-1 {{outside the range of representable values of type 'long long'}}
static_assert(__builtin_reduce_mul((vector4uint){~0U, 1, 1, 2}) ==
#ifdef __AVR__
0);
#else
(~0U - 1));
#endif
static_assert(__builtin_reduce_mul((vector4ulong){~0ULL, 1, 1, 2}) == ~0ULL - 1);
}

namespace ReduceAnd {
static_assert(__builtin_reduce_and((vector4char){}) == 0);
static_assert(__builtin_reduce_and((vector4char){(char)0x11, (char)0x22, (char)0x44, (char)0x88}) == 0);
static_assert(__builtin_reduce_and((vector4short){(short)0x1111, (short)0x2222, (short)0x4444, (short)0x8888}) == 0);
static_assert(__builtin_reduce_and((vector4int){(int)0x11111111, (int)0x22222222, (int)0x44444444, (int)0x88888888}) == 0);
#if __INT_WIDTH__ == 32
static_assert(__builtin_reduce_and((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == 0L);
static_assert(__builtin_reduce_and((vector4char){(char)-1, (char)~0x22, (char)~0x44, (char)~0x88}) == 0x11);
static_assert(__builtin_reduce_and((vector4short){(short)~0x1111, (short)-1, (short)~0x4444, (short)~0x8888}) == 0x2222);
static_assert(__builtin_reduce_and((vector4int){(int)~0x11111111, (int)~0x22222222, (int)-1, (int)~0x88888888}) == 0x44444444);
static_assert(__builtin_reduce_and((vector4long){(long long)~0x1111111111111111L, (long long)~0x2222222222222222L, (long long)~0x4444444444444444L, (long long)-1}) == 0x8888888888888888L);
static_assert(__builtin_reduce_and((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0U);
static_assert(__builtin_reduce_and((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0L);
#endif
}

namespace ReduceOr {
static_assert(__builtin_reduce_or((vector4char){}) == 0);
static_assert(__builtin_reduce_or((vector4char){(char)0x11, (char)0x22, (char)0x44, (char)0x88}) == (char)0xFF);
static_assert(__builtin_reduce_or((vector4short){(short)0x1111, (short)0x2222, (short)0x4444, (short)0x8888}) == (short)0xFFFF);
static_assert(__builtin_reduce_or((vector4int){(int)0x11111111, (int)0x22222222, (int)0x44444444, (int)0x88888888}) == (int)0xFFFFFFFF);
#if __INT_WIDTH__ == 32
static_assert(__builtin_reduce_or((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0xFFFFFFFFFFFFFFFFL);
static_assert(__builtin_reduce_or((vector4char){(char)0, (char)0x22, (char)0x44, (char)0x88}) == ~0x11);
static_assert(__builtin_reduce_or((vector4short){(short)0x1111, (short)0, (short)0x4444, (short)0x8888}) == ~0x2222);
static_assert(__builtin_reduce_or((vector4int){(int)0x11111111, (int)0x22222222, (int)0, (int)0x88888888}) == ~0x44444444);
static_assert(__builtin_reduce_or((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0}) == ~0x8888888888888888L);
static_assert(__builtin_reduce_or((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0xFFFFFFFFU);
static_assert(__builtin_reduce_or((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0xFFFFFFFFFFFFFFFFL);
#endif
}

namespace ReduceXor {
static_assert(__builtin_reduce_xor((vector4char){}) == 0);
static_assert(__builtin_reduce_xor((vector4char){(char)0x11, (char)0x22, (char)0x44, (char)0x88}) == (char)0xFF);
static_assert(__builtin_reduce_xor((vector4short){(short)0x1111, (short)0x2222, (short)0x4444, (short)0x8888}) == (short)0xFFFF);
#if __INT_WIDTH__ == 32
static_assert(__builtin_reduce_xor((vector4int){(int)0x11111111, (int)0x22222222, (int)0x44444444, (int)0x88888888}) == (int)0xFFFFFFFF);
static_assert(__builtin_reduce_xor((vector4long){(long long)0x1111111111111111L, (long long)0x2222222222222222L, (long long)0x4444444444444444L, (long long)0x8888888888888888L}) == (long long)0xFFFFFFFFFFFFFFFFL);
static_assert(__builtin_reduce_xor((vector4uint){0x11111111U, 0x22222222U, 0x44444444U, 0x88888888U}) == 0xFFFFFFFFU);
static_assert(__builtin_reduce_xor((vector4ulong){0x1111111111111111UL, 0x2222222222222222UL, 0x4444444444444444UL, 0x8888888888888888UL}) == 0xFFFFFFFFFFFFFFFFUL);
#endif
}

namespace ElementwisePopcount {
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){1, 2, 3, 4})) == 5);
#if __INT_WIDTH__ == 32
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4int){0, 0xF0F0, ~0, ~0xF0F0})) == 16 * sizeof(int));
#endif
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){1L, 2L, 3L, 4L})) == 5L);
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4long){0L, 0xF0F0L, ~0L, ~0xF0F0L})) == 16 * sizeof(long long));
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){1U, 2U, 3U, 4U})) == 5U);
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4uint){0U, 0xF0F0U, ~0U, ~0xF0F0U})) == 16 * sizeof(int));
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){1UL, 2UL, 3UL, 4UL})) == 5UL);
static_assert(__builtin_reduce_add(__builtin_elementwise_popcount((vector4ulong){0ULL, 0xF0F0ULL, ~0ULL, ~0xF0F0ULL})) == 16 * sizeof(unsigned long long));
static_assert(__builtin_elementwise_popcount(0) == 0);
static_assert(__builtin_elementwise_popcount(0xF0F0) == 8);
static_assert(__builtin_elementwise_popcount(~0) == 8 * sizeof(int));
static_assert(__builtin_elementwise_popcount(0U) == 0);
static_assert(__builtin_elementwise_popcount(0xF0F0U) == 8);
static_assert(__builtin_elementwise_popcount(~0U) == 8 * sizeof(int));
static_assert(__builtin_elementwise_popcount(0L) == 0);
static_assert(__builtin_elementwise_popcount(0xF0F0L) == 8);
static_assert(__builtin_elementwise_popcount(~0LL) == 8 * sizeof(long long));
}

namespace BuiltinMemcpy {
constexpr int simple() {
int a = 12;
int b = 0;
__builtin_memcpy(&b, &a, sizeof(a));
return b;
}
static_assert(simple() == 12);


extern struct Incomplete incomplete;
constexpr struct Incomplete *null_incomplete = 0;
static_assert(__builtin_memcpy(null_incomplete, null_incomplete, sizeof(wchar_t))); // both-error {{not an integral constant expression}} \
// both-note {{source of 'memcpy' is nullptr}}


constexpr int simpleMove() {
int a = 12;
int b = 0;
__builtin_memmove(&b, &a, sizeof(a));
return b;
}
static_assert(simpleMove() == 12);
}
3 changes: 1 addition & 2 deletions clang/test/AST/ByteCode/vectors.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,9 @@ namespace Vector {
static_assert(__builtin_vectorelements(v2) == (32 / sizeof(double)), "");
}

/// FIXME: We need to support BitCasts between vector types.
namespace {
typedef float __attribute__((vector_size(16))) VI42;
constexpr VI42 A2 = A; // expected-error {{must be initialized by a constant expression}}
constexpr VI42 A2 = A;
}

namespace BoolToSignedIntegralCast{
Expand Down
28 changes: 22 additions & 6 deletions clang/test/AST/HLSL/StructuredBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -75,19 +75,35 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit RawBuffer

// CHECK-SUBSCRIPT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const [[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK-SUBSCRIPT-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-SUBSCRIPT-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-SUBSCRIPT-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
// CHECK-SUBSCRIPT-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-SUBSCRIPT-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::resource_class(
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SUBSCRIPT-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SUBSCRIPT-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
// CHECK-SUBSCRIPT-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-SUBSCRIPT-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
// CHECK-SUBSCRIPT-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK-NOSUBSCRIPT-NOT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'
Expand All @@ -97,7 +113,7 @@ RESOURCE<float> Buffer;
// CHECK-COUNTER-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-COUNTER-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-COUNTER-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'
// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int (...) noexcept' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
// CHECK-COUNTER-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::raw_buffer]]
Expand All @@ -110,7 +126,7 @@ RESOURCE<float> Buffer;
// CHECK-COUNTER-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-COUNTER-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-COUNTER-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int'
// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int (...) noexcept' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
// CHECK-COUNTER-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_buffer_update_counter' 'unsigned int (...) noexcept'
// CHECK-COUNTER-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-COUNTER-SAME{LITERAL}: [[hlsl::raw_buffer]]
Expand Down
22 changes: 18 additions & 4 deletions clang/test/AST/HLSL/TypedBuffers-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -58,19 +58,33 @@ RESOURCE<float> Buffer;
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'const element_type &(unsigned int) const'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
// CHECK-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'const [[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK-NEXT: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &(unsigned int)'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Idx 'unsigned int'
// CHECK-NEXT: ParmVarDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> Index 'unsigned int'
// CHECK-NEXT: CompoundStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: ReturnStmt 0x{{[0-9A-Fa-f]+}} <<invalid sloc>>
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' lvalue .e 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: UnaryOperator 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type' prefix '*' cannot overflow
// CHECK-NEXT: CallExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'element_type *'
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '<builtin fn type>' Function 0x{{[0-9A-Fa-f]+}} '__builtin_hlsl_resource_getpointer' 'void (...) noexcept'
// CHECK-NEXT: MemberExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ' lvalue .__handle 0x{{[0-9A-Fa-f]+}}
// CHECK-NEXT: CXXThisExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> '[[RESOURCE]]<element_type>' lvalue implicit this
// CHECK-NEXT: DeclRefExpr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> 'unsigned int' ParmVar 0x{{[0-9A-Fa-f]+}} 'Index' 'unsigned int'
// CHECK-NEXT: AlwaysInlineAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit always_inline

// CHECK: ClassTemplateSpecializationDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> class [[RESOURCE]] definition
Expand Down
54 changes: 54 additions & 0 deletions clang/test/AST/ast-print-openacc-combined-construct.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -fopenacc -Wno-openacc-deprecated-clause-alias -ast-print %s -o - | FileCheck %s

constexpr int get_value() { return 1; }
void foo() {
int *iPtr;
// CHECK: #pragma acc parallel loop
Expand Down Expand Up @@ -170,4 +171,57 @@ void foo() {
#pragma acc parallel loop no_create(i, array[1], array, array[1:2]) present(i, array[1], array, array[1:2])
for(int i = 0;i<5;++i);

// CHECK: #pragma acc parallel loop copy(i, array[1], array, array[1:2]) pcopy(i, array[1], array, array[1:2]) present_or_copy(i, array[1], array, array[1:2])
#pragma acc parallel loop copy(i, array[1], array, array[1:2]) pcopy(i, array[1], array, array[1:2]) present_or_copy(i, array[1], array, array[1:2])
for(int i = 0;i<5;++i);

// CHECK: #pragma acc parallel loop copyin(i, array[1], array, array[1:2]) pcopyin(readonly: i, array[1], array, array[1:2]) present_or_copyin(i, array[1], array, array[1:2])
#pragma acc parallel loop copyin(i, array[1], array, array[1:2]) pcopyin(readonly:i, array[1], array, array[1:2]) present_or_copyin(i, array[1], array, array[1:2])
for(int i = 0;i<5;++i);

// CHECK: #pragma acc parallel loop copyout(i, array[1], array, array[1:2]) pcopyout(zero: i, array[1], array, array[1:2]) present_or_copyout(i, array[1], array, array[1:2])
#pragma acc parallel loop copyout(i, array[1], array, array[1:2]) pcopyout(zero: i, array[1], array, array[1:2]) present_or_copyout(i, array[1], array, array[1:2])
for(int i = 0;i<5;++i);

// CHECK: #pragma acc parallel loop create(i, array[1], array, array[1:2]) pcreate(zero: i, array[1], array, array[1:2]) present_or_create(i, array[1], array, array[1:2])
#pragma acc parallel loop create(i, array[1], array, array[1:2]) pcreate(zero: i, array[1], array, array[1:2]) present_or_create(i, array[1], array, array[1:2])
for(int i = 0;i<5;++i);

// CHECK: #pragma acc parallel loop collapse(1)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: ;
#pragma acc parallel loop collapse(1)
for(int i = 0;i<5;++i);
// CHECK: #pragma acc serial loop collapse(force:1)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: ;
#pragma acc serial loop collapse(force:1)
for(int i = 0;i<5;++i);
// CHECK: #pragma acc kernels loop collapse(2)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: ;
#pragma acc kernels loop collapse(2)
for(int i = 0;i<5;++i)
for(int i = 0;i<5;++i);
// CHECK: #pragma acc parallel loop collapse(force:2)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: ;
#pragma acc parallel loop collapse(force:2)
for(int i = 0;i<5;++i)
for(int i = 0;i<5;++i);

// CHECK: #pragma acc serial loop tile(1, 3, *, get_value())
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: for (int i = 0; i < 5; ++i)
// CHECK-NEXT: ;
#pragma acc serial loop tile(1, 3, *, get_value())
for(int i = 0;i<5;++i)
for(int i = 0;i<5;++i)
for(int i = 0;i<5;++i)
for(int i = 0;i<5;++i);

}
16 changes: 16 additions & 0 deletions clang/test/AST/attr-lifetime-capture-by.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ struct vector {

void insert(iterator, T&&);
};

template <typename Key, typename Value>
struct map {
Value& operator[](Key&& p);
Value& operator[](const Key& p);
};
} // namespace std

// CHECK-NOT: LifetimeCaptureByAttr
Expand Down Expand Up @@ -99,3 +105,13 @@ std::vector<int> ints;
// CHECK-NEXT: ParmVarDecl {{.*}} 'iterator'
// CHECK-NEXT: ParmVarDecl {{.*}} 'int &&'
// CHECK-NOT: LifetimeCaptureByAttr

std::map<View, int> map;
// CHECK: ClassTemplateSpecializationDecl {{.*}} struct map definition implicit_instantiation

// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(View &&)' implicit_instantiation
// CHECK-NEXT: ParmVarDecl {{.*}} p 'View &&'
// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit
// CHECK: CXXMethodDecl {{.*}} operator[] 'int &(const View &)' implicit_instantiation
// CHECK-NEXT: ParmVarDecl {{.*}} p 'const View &'
// CHECK-NEXT: LifetimeCaptureByAttr {{.*}} Implicit
Loading