diff --git a/clang/docs/ClangLinkerWrapper.rst b/clang/docs/ClangLinkerWrapper.rst index 6d7770b50e7260..3bef5584757351 100644 --- a/clang/docs/ClangLinkerWrapper.rst +++ b/clang/docs/ClangLinkerWrapper.rst @@ -79,6 +79,14 @@ linking is desired, simply do not run the binaries through the ``clang-linker-wrapper``. This will simply append the embedded device code so that it can be linked later. +Matching +======== + +The linker wrapper will link extracted device code that is compatible with each +other. Generally, this requires that the target triple and architecture match. +An exception is made when the architecture is listed as ``generic``, which will +cause it be linked with any other device code with the same target triple. + Example ======= diff --git a/clang/docs/analyzer/checkers.rst b/clang/docs/analyzer/checkers.rst index bb637cf1b8007b..510629d8a2d480 100644 --- a/clang/docs/analyzer/checkers.rst +++ b/clang/docs/analyzer/checkers.rst @@ -1890,28 +1890,6 @@ the locking/unlocking of ``mtx_t`` mutexes. mtx_lock(&mtx1); // warn: This lock has already been acquired } -.. _alpha-core-CallAndMessageUnInitRefArg: - -alpha.core.CallAndMessageUnInitRefArg (C,C++, ObjC) -""""""""""""""""""""""""""""""""""""""""""""""""""" -Check for logical errors for function calls and Objective-C -message expressions (e.g., uninitialized arguments, null function pointers, and pointer to undefined variables). - -.. code-block:: c - - void test(void) { - int t; - int &p = t; - int &s = p; - int &q = s; - foo(q); // warn - } - - void test(void) { - int x; - foo(&x); // warn - } - .. _alpha-core-CastSize: alpha.core.CastSize (C) diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 537b0890e19478..bf11bcd1a01012 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3728,6 +3728,8 @@ def err_sme_definition_using_zt0_in_non_sme2_target : Error< "function using ZT0 state requires 'sme2'">; def err_conflicting_attributes_arm_state : Error< "conflicting attributes for state '%0'">; +def err_sme_streaming_cannot_be_multiversioned : Error< + "streaming function cannot be multi-versioned">; def err_unknown_arm_state : Error< "unknown state '%0'">; def err_missing_arm_state : Error< diff --git a/clang/include/clang/Basic/IdentifierTable.h b/clang/include/clang/Basic/IdentifierTable.h index 1ac182d4fce26f..fa8969eb73ddbf 100644 --- a/clang/include/clang/Basic/IdentifierTable.h +++ b/clang/include/clang/Basic/IdentifierTable.h @@ -15,6 +15,7 @@ #ifndef LLVM_CLANG_BASIC_IDENTIFIERTABLE_H #define LLVM_CLANG_BASIC_IDENTIFIERTABLE_H +#include "clang/Basic/Builtins.h" #include "clang/Basic/DiagnosticIDs.h" #include "clang/Basic/LLVM.h" #include "clang/Basic/TokenKinds.h" @@ -86,19 +87,26 @@ enum { IdentifierInfoAlignment = 8 }; static constexpr int ObjCOrBuiltinIDBits = 16; /// The "layout" of ObjCOrBuiltinID is: -/// - The first value (0) represents "not a special identifier". -/// - The next (NUM_OBJC_KEYWORDS - 1) values represent ObjCKeywordKinds (not -/// including objc_not_keyword). -/// - The next (NUM_INTERESTING_IDENTIFIERS - 1) values represent -/// InterestingIdentifierKinds (not including not_interesting). -/// - The rest of the values represent builtin IDs (not including NotBuiltin). -static constexpr int FirstObjCKeywordID = 1; -static constexpr int LastObjCKeywordID = - FirstObjCKeywordID + tok::NUM_OBJC_KEYWORDS - 2; -static constexpr int FirstInterestingIdentifierID = LastObjCKeywordID + 1; -static constexpr int LastInterestingIdentifierID = - FirstInterestingIdentifierID + tok::NUM_INTERESTING_IDENTIFIERS - 2; -static constexpr int FirstBuiltinID = LastInterestingIdentifierID + 1; +/// - ObjCKeywordKind enumerators +/// - InterestingIdentifierKind enumerators +/// - Builtin::ID enumerators +/// - NonSpecialIdentifier +enum class ObjCKeywordOrInterestingOrBuiltin { +#define OBJC_AT_KEYWORD(X) objc_##X, +#include "clang/Basic/TokenKinds.def" + NUM_OBJC_KEYWORDS, + +#define INTERESTING_IDENTIFIER(X) X, +#include "clang/Basic/TokenKinds.def" + NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS, + + NotBuiltin, +#define BUILTIN(ID, TYPE, ATTRS) BI##ID, +#include "clang/Basic/Builtins.inc" + FirstTSBuiltin, + + NonSpecialIdentifier = 65534 +}; /// One of these records is kept for each identifier that /// is lexed. This contains information about whether the token was \#define'd, @@ -113,9 +121,7 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { LLVM_PREFERRED_TYPE(tok::TokenKind) unsigned TokenID : 9; - // ObjC keyword ('protocol' in '@protocol') or builtin (__builtin_inf). - // First NUM_OBJC_KEYWORDS values are for Objective-C, - // the remaining values are for builtins. + LLVM_PREFERRED_TYPE(ObjCKeywordOrInterestingOrBuiltin) unsigned ObjCOrBuiltinID : ObjCOrBuiltinIDBits; // True if there is a #define for this. @@ -198,13 +204,16 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { llvm::StringMapEntry *Entry = nullptr; IdentifierInfo() - : TokenID(tok::identifier), ObjCOrBuiltinID(0), HasMacro(false), - HadMacro(false), IsExtension(false), IsFutureCompatKeyword(false), - IsPoisoned(false), IsCPPOperatorKeyword(false), - NeedsHandleIdentifier(false), IsFromAST(false), ChangedAfterLoad(false), - FEChangedAfterLoad(false), RevertedTokenID(false), OutOfDate(false), - IsModulesImport(false), IsMangledOpenMPVariantName(false), - IsDeprecatedMacro(false), IsRestrictExpansion(false), IsFinal(false) {} + : TokenID(tok::identifier), + ObjCOrBuiltinID(llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier)), + HasMacro(false), HadMacro(false), IsExtension(false), + IsFutureCompatKeyword(false), IsPoisoned(false), + IsCPPOperatorKeyword(false), NeedsHandleIdentifier(false), + IsFromAST(false), ChangedAfterLoad(false), FEChangedAfterLoad(false), + RevertedTokenID(false), OutOfDate(false), IsModulesImport(false), + IsMangledOpenMPVariantName(false), IsDeprecatedMacro(false), + IsRestrictExpansion(false), IsFinal(false) {} public: IdentifierInfo(const IdentifierInfo &) = delete; @@ -332,42 +341,66 @@ class alignas(IdentifierInfoAlignment) IdentifierInfo { /// /// For example, 'class' will return tok::objc_class if ObjC is enabled. tok::ObjCKeywordKind getObjCKeywordID() const { - static_assert(FirstObjCKeywordID == 1, - "hard-coding this assumption to simplify code"); - if (ObjCOrBuiltinID <= LastObjCKeywordID) - return tok::ObjCKeywordKind(ObjCOrBuiltinID); - else - return tok::objc_not_keyword; + assert(0 == llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::objc_not_keyword)); + auto Value = + static_cast(ObjCOrBuiltinID); + if (Value < ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS) + return static_cast(ObjCOrBuiltinID); + return tok::objc_not_keyword; + } + void setObjCKeywordID(tok::ObjCKeywordKind ID) { + assert(0 == llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::objc_not_keyword)); + ObjCOrBuiltinID = ID; + assert(getObjCKeywordID() == ID && "ID too large for field!"); } - void setObjCKeywordID(tok::ObjCKeywordKind ID) { ObjCOrBuiltinID = ID; } /// Return a value indicating whether this is a builtin function. - /// - /// 0 is not-built-in. 1+ are specific builtin functions. unsigned getBuiltinID() const { - if (ObjCOrBuiltinID >= FirstBuiltinID) - return 1 + (ObjCOrBuiltinID - FirstBuiltinID); - else - return 0; + auto Value = + static_cast(ObjCOrBuiltinID); + if (Value > ObjCKeywordOrInterestingOrBuiltin:: + NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS && + Value != ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier) { + auto FirstBuiltin = + llvm::to_underlying(ObjCKeywordOrInterestingOrBuiltin::NotBuiltin); + return static_cast(ObjCOrBuiltinID - FirstBuiltin); + } + return Builtin::ID::NotBuiltin; } void setBuiltinID(unsigned ID) { - assert(ID != 0); - ObjCOrBuiltinID = FirstBuiltinID + (ID - 1); + assert(ID != Builtin::ID::NotBuiltin); + auto FirstBuiltin = + llvm::to_underlying(ObjCKeywordOrInterestingOrBuiltin::NotBuiltin); + ObjCOrBuiltinID = ID + FirstBuiltin; assert(getBuiltinID() == ID && "ID too large for field!"); } - void clearBuiltinID() { ObjCOrBuiltinID = 0; } + void clearBuiltinID() { + ObjCOrBuiltinID = llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::NonSpecialIdentifier); + } tok::InterestingIdentifierKind getInterestingIdentifierID() const { - if (ObjCOrBuiltinID >= FirstInterestingIdentifierID && - ObjCOrBuiltinID <= LastInterestingIdentifierID) - return tok::InterestingIdentifierKind( - 1 + (ObjCOrBuiltinID - FirstInterestingIdentifierID)); - else - return tok::not_interesting; + auto Value = + static_cast(ObjCOrBuiltinID); + if (Value > ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS && + Value < ObjCKeywordOrInterestingOrBuiltin:: + NUM_OBJC_KEYWORDS_AND_INTERESTING_IDENTIFIERS) { + auto FirstInterestingIdentifier = + 1 + llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS); + return static_cast( + ObjCOrBuiltinID - FirstInterestingIdentifier); + } + return tok::not_interesting; } void setInterestingIdentifierID(unsigned ID) { assert(ID != tok::not_interesting); - ObjCOrBuiltinID = FirstInterestingIdentifierID + (ID - 1); + auto FirstInterestingIdentifier = + 1 + llvm::to_underlying( + ObjCKeywordOrInterestingOrBuiltin::NUM_OBJC_KEYWORDS); + ObjCOrBuiltinID = ID + FirstInterestingIdentifier; assert(getInterestingIdentifierID() == ID && "ID too large for field!"); } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index c017821e0a79f5..b9c1200ebd2ff6 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -353,6 +353,72 @@ class PreferredTypeBuilder { llvm::function_ref ComputeType; }; +/// Describes the result of template argument deduction. +/// +/// The TemplateDeductionResult enumeration describes the result of +/// template argument deduction, as returned from +/// DeduceTemplateArguments(). The separate TemplateDeductionInfo +/// structure provides additional information about the results of +/// template argument deduction, e.g., the deduced template argument +/// list (if successful) or the specific template parameters or +/// deduced arguments that were involved in the failure. +enum class TemplateDeductionResult { + /// Template argument deduction was successful. + Success = 0, + /// The declaration was invalid; do nothing. + Invalid, + /// Template argument deduction exceeded the maximum template + /// instantiation depth (which has already been diagnosed). + InstantiationDepth, + /// Template argument deduction did not deduce a value + /// for every template parameter. + Incomplete, + /// Template argument deduction did not deduce a value for every + /// expansion of an expanded template parameter pack. + IncompletePack, + /// Template argument deduction produced inconsistent + /// deduced values for the given template parameter. + Inconsistent, + /// Template argument deduction failed due to inconsistent + /// cv-qualifiers on a template parameter type that would + /// otherwise be deduced, e.g., we tried to deduce T in "const T" + /// but were given a non-const "X". + Underqualified, + /// Substitution of the deduced template argument values + /// resulted in an error. + SubstitutionFailure, + /// After substituting deduced template arguments, a dependent + /// parameter type did not match the corresponding argument. + DeducedMismatch, + /// After substituting deduced template arguments, an element of + /// a dependent parameter type did not match the corresponding element + /// of the corresponding argument (when deducing from an initializer list). + DeducedMismatchNested, + /// A non-depnedent component of the parameter did not match the + /// corresponding component of the argument. + NonDeducedMismatch, + /// When performing template argument deduction for a function + /// template, there were too many call arguments. + TooManyArguments, + /// When performing template argument deduction for a function + /// template, there were too few call arguments. + TooFewArguments, + /// The explicitly-specified template arguments were not valid + /// template arguments for the given template. + InvalidExplicitArguments, + /// Checking non-dependent argument conversions failed. + NonDependentConversionFailure, + /// The deduced arguments did not satisfy the constraints associated + /// with the template. + ConstraintsNotSatisfied, + /// Deduction failed; that's all we know. + MiscellaneousDeductionFailure, + /// CUDA Target attributes do not match. + CUDATargetMismatch, + /// Some error which was already diagnosed. + AlreadyDiagnosed +}; + /// Sema - This implements semantic analysis and AST building for C. class Sema final { Sema(const Sema &) = delete; @@ -4842,13 +4908,12 @@ class Sema final { llvm::Error isValidSectionSpecifier(StringRef Str); bool checkSectionName(SourceLocation LiteralLoc, StringRef Str); bool checkTargetAttr(SourceLocation LiteralLoc, StringRef Str); - bool checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &Str, - bool &isDefault); - bool - checkTargetClonesAttrString(SourceLocation LiteralLoc, StringRef Str, - const StringLiteral *Literal, bool &HasDefault, - bool &HasCommas, bool &HasNotDefault, - SmallVectorImpl> &StringsBuffer); + bool checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, + StringRef &Str, bool &isDefault); + bool checkTargetClonesAttrString( + SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, + Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + SmallVectorImpl> &StringsBuffer); bool checkMSInheritanceAttrOnDefinition( CXXRecordDecl *RD, SourceRange Range, bool BestCase, MSInheritanceModel SemanticSpelling); @@ -9266,72 +9331,6 @@ class Sema final { QualType adjustCCAndNoReturn(QualType ArgFunctionType, QualType FunctionType, bool AdjustExceptionSpec = false); - /// Describes the result of template argument deduction. - /// - /// The TemplateDeductionResult enumeration describes the result of - /// template argument deduction, as returned from - /// DeduceTemplateArguments(). The separate TemplateDeductionInfo - /// structure provides additional information about the results of - /// template argument deduction, e.g., the deduced template argument - /// list (if successful) or the specific template parameters or - /// deduced arguments that were involved in the failure. - enum TemplateDeductionResult { - /// Template argument deduction was successful. - TDK_Success = 0, - /// The declaration was invalid; do nothing. - TDK_Invalid, - /// Template argument deduction exceeded the maximum template - /// instantiation depth (which has already been diagnosed). - TDK_InstantiationDepth, - /// Template argument deduction did not deduce a value - /// for every template parameter. - TDK_Incomplete, - /// Template argument deduction did not deduce a value for every - /// expansion of an expanded template parameter pack. - TDK_IncompletePack, - /// Template argument deduction produced inconsistent - /// deduced values for the given template parameter. - TDK_Inconsistent, - /// Template argument deduction failed due to inconsistent - /// cv-qualifiers on a template parameter type that would - /// otherwise be deduced, e.g., we tried to deduce T in "const T" - /// but were given a non-const "X". - TDK_Underqualified, - /// Substitution of the deduced template argument values - /// resulted in an error. - TDK_SubstitutionFailure, - /// After substituting deduced template arguments, a dependent - /// parameter type did not match the corresponding argument. - TDK_DeducedMismatch, - /// After substituting deduced template arguments, an element of - /// a dependent parameter type did not match the corresponding element - /// of the corresponding argument (when deducing from an initializer list). - TDK_DeducedMismatchNested, - /// A non-depnedent component of the parameter did not match the - /// corresponding component of the argument. - TDK_NonDeducedMismatch, - /// When performing template argument deduction for a function - /// template, there were too many call arguments. - TDK_TooManyArguments, - /// When performing template argument deduction for a function - /// template, there were too few call arguments. - TDK_TooFewArguments, - /// The explicitly-specified template arguments were not valid - /// template arguments for the given template. - TDK_InvalidExplicitArguments, - /// Checking non-dependent argument conversions failed. - TDK_NonDependentConversionFailure, - /// The deduced arguments did not satisfy the constraints associated - /// with the template. - TDK_ConstraintsNotSatisfied, - /// Deduction failed; that's all we know. - TDK_MiscellaneousDeductionFailure, - /// CUDA Target attributes do not match. - TDK_CUDATargetMismatch, - /// Some error which was already diagnosed. - TDK_AlreadyDiagnosed - }; - TemplateDeductionResult DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, ArrayRef TemplateArgs, @@ -14449,7 +14448,7 @@ class Sema final { }; DeductionFailureInfo -MakeDeductionFailureInfo(ASTContext &Context, Sema::TemplateDeductionResult TDK, +MakeDeductionFailureInfo(ASTContext &Context, TemplateDeductionResult TDK, sema::TemplateDeductionInfo &Info); /// Contains a late templated function. diff --git a/clang/include/clang/Sema/TemplateDeduction.h b/clang/include/clang/Sema/TemplateDeduction.h index 85691c66a04433..28b014fd84e4b3 100644 --- a/clang/include/clang/Sema/TemplateDeduction.h +++ b/clang/include/clang/Sema/TemplateDeduction.h @@ -33,6 +33,7 @@ namespace clang { class Decl; struct DeducedPack; class Sema; +enum class TemplateDeductionResult; namespace sema { @@ -295,6 +296,10 @@ struct DeductionFailureInfo { /// Free any memory associated with this deduction failure. void Destroy(); + + TemplateDeductionResult getResult() const { + return static_cast(Result); + } }; /// TemplateSpecCandidate - This is a generalization of OverloadCandidate diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp index 6993d751fe58f0..8a2c1e54e10a50 100644 --- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp +++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp @@ -2283,8 +2283,7 @@ bool ByteCodeExprGen::dereferenceParam( const Expr *LV, PrimType T, const ParmVarDecl *PD, DerefKind AK, llvm::function_ref Direct, llvm::function_ref Indirect) { - auto It = this->Params.find(PD); - if (It != this->Params.end()) { + if (auto It = this->Params.find(PD); It != this->Params.end()) { unsigned Idx = It->second.Offset; switch (AK) { case DerefKind::Read: diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 15c137098af355..e2fda18e3f44d4 100644 --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1187,15 +1187,18 @@ inline bool GetPtrGlobal(InterpState &S, CodePtr OpPC, uint32_t I) { /// 2) Pushes Pointer.atField(Off) on the stack inline bool GetPtrField(InterpState &S, CodePtr OpPC, uint32_t Off) { const Pointer &Ptr = S.Stk.pop(); + if (S.inConstantContext() && !CheckNull(S, OpPC, Ptr, CSK_Field)) return false; - if (!CheckExtern(S, OpPC, Ptr)) - return false; - if (!CheckRange(S, OpPC, Ptr, CSK_Field)) - return false; - if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) - return false; + if (CheckDummy(S, OpPC, Ptr)) { + if (!CheckExtern(S, OpPC, Ptr)) + return false; + if (!CheckRange(S, OpPC, Ptr, CSK_Field)) + return false; + if (!CheckSubobject(S, OpPC, Ptr, CSK_Field)) + return false; + } S.Stk.push(Ptr.atField(Off)); return true; } @@ -1896,8 +1899,10 @@ inline bool ArrayElemPop(InterpState &S, CodePtr OpPC, uint32_t Index) { inline bool ArrayDecay(InterpState &S, CodePtr OpPC) { const Pointer &Ptr = S.Stk.pop(); - if (Ptr.isDummy()) - return false; + if (Ptr.isDummy()) { + S.Stk.push(Ptr); + return true; + } if (!Ptr.isUnknownSizeArray()) { S.Stk.push(Ptr.atIndex(0)); diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp index 316a7ed5fa1bb8..8a0a15547b0f2f 100644 --- a/clang/lib/AST/Interp/Pointer.cpp +++ b/clang/lib/AST/Interp/Pointer.cpp @@ -83,63 +83,48 @@ void Pointer::operator=(Pointer &&P) { } APValue Pointer::toAPValue() const { - APValue::LValueBase Base; llvm::SmallVector Path; - CharUnits Offset; - bool IsNullPtr; - bool IsOnePastEnd; - - if (isZero()) { - Base = static_cast(nullptr); - IsNullPtr = true; - IsOnePastEnd = false; - Offset = CharUnits::Zero(); - } else { - // Build the lvalue base from the block. - const Descriptor *Desc = getDeclDesc(); - if (auto *VD = Desc->asValueDecl()) - Base = VD; - else if (auto *E = Desc->asExpr()) - Base = E; - else - llvm_unreachable("Invalid allocation type"); - - // Not a null pointer. - IsNullPtr = false; - - if (isUnknownSizeArray()) { - IsOnePastEnd = false; - Offset = CharUnits::Zero(); - } else if (Desc->asExpr()) { - // Pointer pointing to a an expression. - IsOnePastEnd = false; - Offset = CharUnits::Zero(); + + if (isZero()) + return APValue(static_cast(nullptr), CharUnits::Zero(), Path, + /*IsOnePastEnd=*/false, /*IsNullPtr=*/true); + + // Build the lvalue base from the block. + const Descriptor *Desc = getDeclDesc(); + APValue::LValueBase Base; + if (const auto *VD = Desc->asValueDecl()) + Base = VD; + else if (const auto *E = Desc->asExpr()) + Base = E; + else + llvm_unreachable("Invalid allocation type"); + + if (isDummy() || isUnknownSizeArray() || Desc->asExpr()) + return APValue(Base, CharUnits::Zero(), Path, + /*IsOnePastEnd=*/false, /*IsNullPtr=*/false); + + // TODO: compute the offset into the object. + CharUnits Offset = CharUnits::Zero(); + bool IsOnePastEnd = isOnePastEnd(); + + // Build the path into the object. + Pointer Ptr = *this; + while (Ptr.isField() || Ptr.isArrayElement()) { + if (Ptr.isArrayElement()) { + Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); + Ptr = Ptr.getArray(); } else { - // TODO: compute the offset into the object. - Offset = CharUnits::Zero(); - - // Build the path into the object. - Pointer Ptr = *this; - while (Ptr.isField() || Ptr.isArrayElement()) { - if (Ptr.isArrayElement()) { - Path.push_back(APValue::LValuePathEntry::ArrayIndex(Ptr.getIndex())); - Ptr = Ptr.getArray(); - } else { - // TODO: figure out if base is virtual - bool IsVirtual = false; - - // Create a path entry for the field. - const Descriptor *Desc = Ptr.getFieldDesc(); - if (const auto *BaseOrMember = Desc->asDecl()) { - Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); - Ptr = Ptr.getBase(); - continue; - } - llvm_unreachable("Invalid field type"); - } + // TODO: figure out if base is virtual + bool IsVirtual = false; + + // Create a path entry for the field. + const Descriptor *Desc = Ptr.getFieldDesc(); + if (const auto *BaseOrMember = Desc->asDecl()) { + Path.push_back(APValue::LValuePathEntry({BaseOrMember, IsVirtual})); + Ptr = Ptr.getBase(); + continue; } - - IsOnePastEnd = isOnePastEnd(); + llvm_unreachable("Invalid field type"); } } @@ -149,7 +134,7 @@ APValue Pointer::toAPValue() const { // Just invert the order of the elements. std::reverse(Path.begin(), Path.end()); - return APValue(Base, Offset, Path, IsOnePastEnd, IsNullPtr); + return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false); } std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const { diff --git a/clang/lib/CodeGen/CGAtomic.cpp b/clang/lib/CodeGen/CGAtomic.cpp index e2dcc405772afd..a8d846b4f6a592 100644 --- a/clang/lib/CodeGen/CGAtomic.cpp +++ b/clang/lib/CodeGen/CGAtomic.cpp @@ -811,29 +811,6 @@ static void EmitAtomicOp(CodeGenFunction &CGF, AtomicExpr *Expr, Address Dest, Builder.SetInsertPoint(ContBB); } -static void -AddDirectArgument(CodeGenFunction &CGF, CallArgList &Args, - bool UseOptimizedLibcall, llvm::Value *Val, QualType ValTy, - SourceLocation Loc, CharUnits SizeInChars) { - if (UseOptimizedLibcall) { - // Load value and pass it to the function directly. - CharUnits Align = CGF.getContext().getTypeAlignInChars(ValTy); - int64_t SizeInBits = CGF.getContext().toBits(SizeInChars); - ValTy = - CGF.getContext().getIntTypeForBitwidth(SizeInBits, /*Signed=*/false); - llvm::Type *ITy = llvm::IntegerType::get(CGF.getLLVMContext(), SizeInBits); - Address Ptr = Address(Val, ITy, Align); - Val = CGF.EmitLoadOfScalar(Ptr, false, - CGF.getContext().getPointerType(ValTy), - Loc); - // Coerce the value into an appropriately sized integer type. - Args.add(RValue::get(Val), ValTy); - } else { - // Non-optimized functions always take a reference. - Args.add(RValue::get(Val), CGF.getContext().VoidPtrTy); - } -} - RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { QualType AtomicTy = E->getPtr()->getType()->getPointeeType(); QualType MemTy = AtomicTy; @@ -857,21 +834,16 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { uint64_t Size = TInfo.Width.getQuantity(); unsigned MaxInlineWidthInBits = getTarget().getMaxAtomicInlineWidth(); - bool Oversized = getContext().toBits(TInfo.Width) > MaxInlineWidthInBits; - bool Misaligned = (Ptr.getAlignment() % TInfo.Width) != 0; - bool UseLibcall = Misaligned | Oversized; - bool ShouldCastToIntPtrTy = true; - CharUnits MaxInlineWidth = getContext().toCharUnitsFromBits(MaxInlineWidthInBits); DiagnosticsEngine &Diags = CGM.getDiags(); - + bool Misaligned = (Ptr.getAlignment() % TInfo.Width) != 0; + bool Oversized = getContext().toBits(TInfo.Width) > MaxInlineWidthInBits; if (Misaligned) { Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_misaligned) << (int)TInfo.Width.getQuantity() << (int)Ptr.getAlignment().getQuantity(); } - if (Oversized) { Diags.Report(E->getBeginLoc(), diag::warn_atomic_op_oversized) << (int)TInfo.Width.getQuantity() << (int)MaxInlineWidth.getQuantity(); @@ -880,6 +852,7 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { llvm::Value *Order = EmitScalarExpr(E->getOrder()); llvm::Value *Scope = E->getScopeModel() ? EmitScalarExpr(E->getScope()) : nullptr; + bool ShouldCastToIntPtrTy = true; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: @@ -1046,122 +1019,25 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { Dest = Atomics.castToAtomicIntPointer(Dest); } - // Use a library call. See: http://gcc.gnu.org/wiki/Atomic/GCCMM/LIbrary . + bool PowerOf2Size = (Size & (Size - 1)) == 0; + bool UseLibcall = !PowerOf2Size || (Size > 16); + + // For atomics larger than 16 bytes, emit a libcall from the frontend. This + // avoids the overhead of dealing with excessively-large value types in IR. + // Non-power-of-2 values also lower to libcall here, as they are not currently + // permitted in IR instructions (although that constraint could be relaxed in + // the future). For other cases where a libcall is required on a given + // platform, we let the backend handle it (this includes handling for all of + // the size-optimized libcall variants, which are only valid up to 16 bytes.) + // + // See: https://llvm.org/docs/Atomics.html#libcalls-atomic if (UseLibcall) { - bool UseOptimizedLibcall = false; - switch (E->getOp()) { - case AtomicExpr::AO__c11_atomic_init: - case AtomicExpr::AO__opencl_atomic_init: - llvm_unreachable("Already handled above with EmitAtomicInit!"); - - case AtomicExpr::AO__atomic_fetch_add: - case AtomicExpr::AO__atomic_fetch_and: - case AtomicExpr::AO__atomic_fetch_max: - case AtomicExpr::AO__atomic_fetch_min: - case AtomicExpr::AO__atomic_fetch_nand: - case AtomicExpr::AO__atomic_fetch_or: - case AtomicExpr::AO__atomic_fetch_sub: - case AtomicExpr::AO__atomic_fetch_xor: - case AtomicExpr::AO__atomic_add_fetch: - case AtomicExpr::AO__atomic_and_fetch: - case AtomicExpr::AO__atomic_max_fetch: - case AtomicExpr::AO__atomic_min_fetch: - case AtomicExpr::AO__atomic_nand_fetch: - case AtomicExpr::AO__atomic_or_fetch: - case AtomicExpr::AO__atomic_sub_fetch: - case AtomicExpr::AO__atomic_xor_fetch: - case AtomicExpr::AO__c11_atomic_fetch_add: - case AtomicExpr::AO__c11_atomic_fetch_and: - case AtomicExpr::AO__c11_atomic_fetch_max: - case AtomicExpr::AO__c11_atomic_fetch_min: - case AtomicExpr::AO__c11_atomic_fetch_nand: - case AtomicExpr::AO__c11_atomic_fetch_or: - case AtomicExpr::AO__c11_atomic_fetch_sub: - case AtomicExpr::AO__c11_atomic_fetch_xor: - case AtomicExpr::AO__hip_atomic_fetch_add: - case AtomicExpr::AO__hip_atomic_fetch_and: - case AtomicExpr::AO__hip_atomic_fetch_max: - case AtomicExpr::AO__hip_atomic_fetch_min: - case AtomicExpr::AO__hip_atomic_fetch_or: - case AtomicExpr::AO__hip_atomic_fetch_sub: - case AtomicExpr::AO__hip_atomic_fetch_xor: - case AtomicExpr::AO__opencl_atomic_fetch_add: - case AtomicExpr::AO__opencl_atomic_fetch_and: - case AtomicExpr::AO__opencl_atomic_fetch_max: - case AtomicExpr::AO__opencl_atomic_fetch_min: - case AtomicExpr::AO__opencl_atomic_fetch_or: - case AtomicExpr::AO__opencl_atomic_fetch_sub: - case AtomicExpr::AO__opencl_atomic_fetch_xor: - case AtomicExpr::AO__scoped_atomic_fetch_add: - case AtomicExpr::AO__scoped_atomic_fetch_and: - case AtomicExpr::AO__scoped_atomic_fetch_max: - case AtomicExpr::AO__scoped_atomic_fetch_min: - case AtomicExpr::AO__scoped_atomic_fetch_nand: - case AtomicExpr::AO__scoped_atomic_fetch_or: - case AtomicExpr::AO__scoped_atomic_fetch_sub: - case AtomicExpr::AO__scoped_atomic_fetch_xor: - case AtomicExpr::AO__scoped_atomic_add_fetch: - case AtomicExpr::AO__scoped_atomic_and_fetch: - case AtomicExpr::AO__scoped_atomic_max_fetch: - case AtomicExpr::AO__scoped_atomic_min_fetch: - case AtomicExpr::AO__scoped_atomic_nand_fetch: - case AtomicExpr::AO__scoped_atomic_or_fetch: - case AtomicExpr::AO__scoped_atomic_sub_fetch: - case AtomicExpr::AO__scoped_atomic_xor_fetch: - // For these, only library calls for certain sizes exist. - UseOptimizedLibcall = true; - break; - - case AtomicExpr::AO__atomic_load: - case AtomicExpr::AO__atomic_store: - case AtomicExpr::AO__atomic_exchange: - case AtomicExpr::AO__atomic_compare_exchange: - case AtomicExpr::AO__scoped_atomic_load: - case AtomicExpr::AO__scoped_atomic_store: - case AtomicExpr::AO__scoped_atomic_exchange: - case AtomicExpr::AO__scoped_atomic_compare_exchange: - // Use the generic version if we don't know that the operand will be - // suitably aligned for the optimized version. - if (Misaligned) - break; - [[fallthrough]]; - case AtomicExpr::AO__atomic_load_n: - case AtomicExpr::AO__atomic_store_n: - case AtomicExpr::AO__atomic_exchange_n: - case AtomicExpr::AO__atomic_compare_exchange_n: - case AtomicExpr::AO__c11_atomic_load: - case AtomicExpr::AO__c11_atomic_store: - case AtomicExpr::AO__c11_atomic_exchange: - case AtomicExpr::AO__c11_atomic_compare_exchange_weak: - case AtomicExpr::AO__c11_atomic_compare_exchange_strong: - case AtomicExpr::AO__hip_atomic_load: - case AtomicExpr::AO__hip_atomic_store: - case AtomicExpr::AO__hip_atomic_exchange: - case AtomicExpr::AO__hip_atomic_compare_exchange_weak: - case AtomicExpr::AO__hip_atomic_compare_exchange_strong: - case AtomicExpr::AO__opencl_atomic_load: - case AtomicExpr::AO__opencl_atomic_store: - case AtomicExpr::AO__opencl_atomic_exchange: - case AtomicExpr::AO__opencl_atomic_compare_exchange_weak: - case AtomicExpr::AO__opencl_atomic_compare_exchange_strong: - case AtomicExpr::AO__scoped_atomic_load_n: - case AtomicExpr::AO__scoped_atomic_store_n: - case AtomicExpr::AO__scoped_atomic_exchange_n: - case AtomicExpr::AO__scoped_atomic_compare_exchange_n: - // Only use optimized library calls for sizes for which they exist. - // FIXME: Size == 16 optimized library functions exist too. - if (Size == 1 || Size == 2 || Size == 4 || Size == 8) - UseOptimizedLibcall = true; - break; - } - CallArgList Args; - if (!UseOptimizedLibcall) { - // For non-optimized library calls, the size is the first parameter - Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)), - getContext().getSizeType()); - } - // Atomic address is the first or second parameter + // For non-optimized library calls, the size is the first parameter. + Args.add(RValue::get(llvm::ConstantInt::get(SizeTy, Size)), + getContext().getSizeType()); + + // The atomic address is the second parameter. // The OpenCL atomic library functions only accept pointer arguments to // generic address space. auto CastToGenericAddrSpace = [&](llvm::Value *V, QualType PT) { @@ -1176,18 +1052,14 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { return getTargetHooks().performAddrSpaceCast( *this, V, AS, LangAS::opencl_generic, DestType, false); }; - Args.add(RValue::get(CastToGenericAddrSpace(Ptr.getPointer(), E->getPtr()->getType())), getContext().VoidPtrTy); + // The next 1-3 parameters are op-dependent. std::string LibCallName; - QualType LoweredMemTy = - MemTy->isPointerType() ? getContext().getIntPtrType() : MemTy; QualType RetTy; bool HaveRetTy = false; - llvm::Instruction::BinaryOps PostOp = (llvm::Instruction::BinaryOps)0; - bool PostOpMinMax = false; switch (E->getOp()) { case AtomicExpr::AO__c11_atomic_init: case AtomicExpr::AO__opencl_atomic_init: @@ -1198,8 +1070,6 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { // and exchange. // bool __atomic_compare_exchange(size_t size, void *mem, void *expected, // void *desired, int success, int failure) - // bool __atomic_compare_exchange_N(T *mem, T *expected, T desired, - // int success, int failure) case AtomicExpr::AO__atomic_compare_exchange: case AtomicExpr::AO__atomic_compare_exchange_n: case AtomicExpr::AO__c11_atomic_compare_exchange_weak: @@ -1216,14 +1086,14 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), E->getVal1()->getType())), getContext().VoidPtrTy); - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val2.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); + Args.add(RValue::get(CastToGenericAddrSpace(Val2.getPointer(), + E->getVal2()->getType())), + getContext().VoidPtrTy); Args.add(RValue::get(Order), getContext().IntTy); Order = OrderFail; break; // void __atomic_exchange(size_t size, void *mem, void *val, void *return, // int order) - // T __atomic_exchange_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_exchange: case AtomicExpr::AO__atomic_exchange_n: case AtomicExpr::AO__c11_atomic_exchange: @@ -1232,11 +1102,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__scoped_atomic_exchange: case AtomicExpr::AO__scoped_atomic_exchange_n: LibCallName = "__atomic_exchange"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); + Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + E->getVal1()->getType())), + getContext().VoidPtrTy); break; // void __atomic_store(size_t size, void *mem, void *val, int order) - // void __atomic_store_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: case AtomicExpr::AO__c11_atomic_store: @@ -1247,11 +1117,11 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { LibCallName = "__atomic_store"; RetTy = getContext().VoidTy; HaveRetTy = true; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); + Args.add(RValue::get(CastToGenericAddrSpace(Val1.getPointer(), + E->getVal1()->getType())), + getContext().VoidPtrTy); break; // void __atomic_load(size_t size, void *mem, void *return, int order) - // T __atomic_load_N(T *mem, int order) case AtomicExpr::AO__atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__c11_atomic_load: @@ -1261,183 +1131,85 @@ RValue CodeGenFunction::EmitAtomicExpr(AtomicExpr *E) { case AtomicExpr::AO__scoped_atomic_load_n: LibCallName = "__atomic_load"; break; - // T __atomic_add_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_add_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_add_fetch: case AtomicExpr::AO__scoped_atomic_add_fetch: - PostOp = llvm::Instruction::Add; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_add: case AtomicExpr::AO__c11_atomic_fetch_add: case AtomicExpr::AO__hip_atomic_fetch_add: case AtomicExpr::AO__opencl_atomic_fetch_add: case AtomicExpr::AO__scoped_atomic_fetch_add: - LibCallName = "__atomic_fetch_add"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - LoweredMemTy, E->getExprLoc(), TInfo.Width); - break; - // T __atomic_and_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_and_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_and_fetch: case AtomicExpr::AO__scoped_atomic_and_fetch: - PostOp = llvm::Instruction::And; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_and: case AtomicExpr::AO__c11_atomic_fetch_and: case AtomicExpr::AO__hip_atomic_fetch_and: case AtomicExpr::AO__opencl_atomic_fetch_and: case AtomicExpr::AO__scoped_atomic_fetch_and: - LibCallName = "__atomic_fetch_and"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); - break; - // T __atomic_or_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_or_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_or_fetch: case AtomicExpr::AO__scoped_atomic_or_fetch: - PostOp = llvm::Instruction::Or; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_or: case AtomicExpr::AO__c11_atomic_fetch_or: case AtomicExpr::AO__hip_atomic_fetch_or: case AtomicExpr::AO__opencl_atomic_fetch_or: case AtomicExpr::AO__scoped_atomic_fetch_or: - LibCallName = "__atomic_fetch_or"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); - break; - // T __atomic_sub_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_sub_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_sub_fetch: case AtomicExpr::AO__scoped_atomic_sub_fetch: - PostOp = llvm::Instruction::Sub; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_sub: case AtomicExpr::AO__c11_atomic_fetch_sub: case AtomicExpr::AO__hip_atomic_fetch_sub: case AtomicExpr::AO__opencl_atomic_fetch_sub: case AtomicExpr::AO__scoped_atomic_fetch_sub: - LibCallName = "__atomic_fetch_sub"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - LoweredMemTy, E->getExprLoc(), TInfo.Width); - break; - // T __atomic_xor_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_xor_N(T *mem, T val, int order) case AtomicExpr::AO__atomic_xor_fetch: case AtomicExpr::AO__scoped_atomic_xor_fetch: - PostOp = llvm::Instruction::Xor; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_xor: case AtomicExpr::AO__c11_atomic_fetch_xor: case AtomicExpr::AO__hip_atomic_fetch_xor: case AtomicExpr::AO__opencl_atomic_fetch_xor: case AtomicExpr::AO__scoped_atomic_fetch_xor: - LibCallName = "__atomic_fetch_xor"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); - break; + case AtomicExpr::AO__atomic_nand_fetch: + case AtomicExpr::AO__atomic_fetch_nand: + case AtomicExpr::AO__c11_atomic_fetch_nand: + case AtomicExpr::AO__scoped_atomic_fetch_nand: + case AtomicExpr::AO__scoped_atomic_nand_fetch: case AtomicExpr::AO__atomic_min_fetch: - case AtomicExpr::AO__scoped_atomic_min_fetch: - PostOpMinMax = true; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_min: case AtomicExpr::AO__c11_atomic_fetch_min: - case AtomicExpr::AO__scoped_atomic_fetch_min: case AtomicExpr::AO__hip_atomic_fetch_min: case AtomicExpr::AO__opencl_atomic_fetch_min: - LibCallName = E->getValueType()->isSignedIntegerType() - ? "__atomic_fetch_min" - : "__atomic_fetch_umin"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - LoweredMemTy, E->getExprLoc(), TInfo.Width); - break; + case AtomicExpr::AO__scoped_atomic_fetch_min: + case AtomicExpr::AO__scoped_atomic_min_fetch: case AtomicExpr::AO__atomic_max_fetch: - case AtomicExpr::AO__scoped_atomic_max_fetch: - PostOpMinMax = true; - [[fallthrough]]; case AtomicExpr::AO__atomic_fetch_max: case AtomicExpr::AO__c11_atomic_fetch_max: case AtomicExpr::AO__hip_atomic_fetch_max: case AtomicExpr::AO__opencl_atomic_fetch_max: case AtomicExpr::AO__scoped_atomic_fetch_max: - LibCallName = E->getValueType()->isSignedIntegerType() - ? "__atomic_fetch_max" - : "__atomic_fetch_umax"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - LoweredMemTy, E->getExprLoc(), TInfo.Width); - break; - // T __atomic_nand_fetch_N(T *mem, T val, int order) - // T __atomic_fetch_nand_N(T *mem, T val, int order) - case AtomicExpr::AO__atomic_nand_fetch: - case AtomicExpr::AO__scoped_atomic_nand_fetch: - PostOp = llvm::Instruction::And; // the NOT is special cased below - [[fallthrough]]; - case AtomicExpr::AO__atomic_fetch_nand: - case AtomicExpr::AO__c11_atomic_fetch_nand: - case AtomicExpr::AO__scoped_atomic_fetch_nand: - LibCallName = "__atomic_fetch_nand"; - AddDirectArgument(*this, Args, UseOptimizedLibcall, Val1.getPointer(), - MemTy, E->getExprLoc(), TInfo.Width); - break; + case AtomicExpr::AO__scoped_atomic_max_fetch: + llvm_unreachable("Integral atomic operations always become atomicrmw!"); } if (E->isOpenCL()) { - LibCallName = std::string("__opencl") + - StringRef(LibCallName).drop_front(1).str(); - + LibCallName = + std::string("__opencl") + StringRef(LibCallName).drop_front(1).str(); } - // Optimized functions have the size in their name. - if (UseOptimizedLibcall) - LibCallName += "_" + llvm::utostr(Size); // By default, assume we return a value of the atomic type. if (!HaveRetTy) { - if (UseOptimizedLibcall) { - // Value is returned directly. - // The function returns an appropriately sized integer type. - RetTy = getContext().getIntTypeForBitwidth( - getContext().toBits(TInfo.Width), /*Signed=*/false); - } else { - // Value is returned through parameter before the order. - RetTy = getContext().VoidTy; - Args.add(RValue::get(Dest.getPointer()), getContext().VoidPtrTy); - } + // Value is returned through parameter before the order. + RetTy = getContext().VoidTy; + Args.add(RValue::get(CastToGenericAddrSpace(Dest.getPointer(), RetTy)), + getContext().VoidPtrTy); } - // order is always the last parameter + // Order is always the last parameter. Args.add(RValue::get(Order), getContext().IntTy); if (E->isOpenCL()) Args.add(RValue::get(Scope), getContext().IntTy); - // PostOp is only needed for the atomic_*_fetch operations, and - // thus is only needed for and implemented in the - // UseOptimizedLibcall codepath. - assert(UseOptimizedLibcall || (!PostOp && !PostOpMinMax)); - RValue Res = emitAtomicLibcall(*this, LibCallName, RetTy, Args); // The value is returned directly from the libcall. if (E->isCmpXChg()) return Res; - // The value is returned directly for optimized libcalls but the expr - // provided an out-param. - if (UseOptimizedLibcall && Res.getScalarVal()) { - llvm::Value *ResVal = Res.getScalarVal(); - if (PostOpMinMax) { - llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal(); - ResVal = EmitPostAtomicMinMax(Builder, E->getOp(), - E->getValueType()->isSignedIntegerType(), - ResVal, LoadVal1); - } else if (PostOp) { - llvm::Value *LoadVal1 = Args[1].getRValue(*this).getScalarVal(); - ResVal = Builder.CreateBinOp(PostOp, ResVal, LoadVal1); - } - if (E->getOp() == AtomicExpr::AO__atomic_nand_fetch || - E->getOp() == AtomicExpr::AO__scoped_atomic_nand_fetch) - ResVal = Builder.CreateNot(ResVal); - - Builder.CreateStore(ResVal, Dest.withElementType(ResVal->getType())); - } - if (RValTy->isVoidType()) return RValue::get(nullptr); diff --git a/clang/lib/Format/FormatToken.cpp b/clang/lib/Format/FormatToken.cpp index 33bcde3c25ece9..b791c5a26bbe3a 100644 --- a/clang/lib/Format/FormatToken.cpp +++ b/clang/lib/Format/FormatToken.cpp @@ -14,7 +14,9 @@ #include "FormatToken.h" #include "ContinuationIndenter.h" -#include "TokenAnalyzer.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Debug.h" +#include namespace clang { namespace format { @@ -32,9 +34,41 @@ const char *getTokenTypeName(TokenType Type) { return nullptr; } +// FIXME: This is copy&pasted from Sema. Put it in a common place and remove +// duplication. bool FormatToken::isSimpleTypeSpecifier() const { - assert(LangOpts.CPlusPlus); - return Tok.isSimpleTypeSpecifier(LangOpts); + switch (Tok.getKind()) { + case tok::kw_short: + case tok::kw_long: + case tok::kw___int64: + case tok::kw___int128: + case tok::kw_signed: + case tok::kw_unsigned: + case tok::kw_void: + case tok::kw_char: + case tok::kw_int: + case tok::kw_half: + case tok::kw_float: + case tok::kw_double: + case tok::kw___bf16: + case tok::kw__Float16: + case tok::kw___float128: + case tok::kw___ibm128: + case tok::kw_wchar_t: + case tok::kw_bool: +#define TRANSFORM_TYPE_TRAIT_DEF(_, Trait) case tok::kw___##Trait: +#include "clang/Basic/TransformTypeTraits.def" + case tok::annot_typename: + case tok::kw_char8_t: + case tok::kw_char16_t: + case tok::kw_char32_t: + case tok::kw_typeof: + case tok::kw_decltype: + case tok::kw__Atomic: + return true; + default: + return false; + } } bool FormatToken::isTypeOrIdentifier() const { diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h index bace91b5f99b4d..0c1dce7a294082 100644 --- a/clang/lib/Format/FormatToken.h +++ b/clang/lib/Format/FormatToken.h @@ -150,7 +150,17 @@ namespace format { TYPE(StructuredBindingLSquare) \ TYPE(TableGenBangOperator) \ TYPE(TableGenCondOperator) \ + TYPE(TableGenCondOperatorColon) \ + TYPE(TableGenCondOperatorComma) \ + TYPE(TableGenDAGArgCloser) \ + TYPE(TableGenDAGArgListColon) \ + TYPE(TableGenDAGArgListComma) \ + TYPE(TableGenDAGArgOpener) \ + TYPE(TableGenListCloser) \ + TYPE(TableGenListOpener) \ TYPE(TableGenMultiLineString) \ + TYPE(TableGenTrailingPasteOperator) \ + TYPE(TableGenValueSuffix) \ TYPE(TemplateCloser) \ TYPE(TemplateOpener) \ TYPE(TemplateString) \ diff --git a/clang/lib/Format/FormatTokenLexer.cpp b/clang/lib/Format/FormatTokenLexer.cpp index a57659fd422720..492e7e96dd22e6 100644 --- a/clang/lib/Format/FormatTokenLexer.cpp +++ b/clang/lib/Format/FormatTokenLexer.cpp @@ -812,7 +812,7 @@ void FormatTokenLexer::handleTableGenMultilineString() { auto CloseOffset = Lex->getBuffer().find("}]", OpenOffset); if (CloseOffset == StringRef::npos) return; - auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset + 2); + auto Text = Lex->getBuffer().substr(OpenOffset, CloseOffset - OpenOffset + 2); MultiLineString->TokenText = Text; resetLexer(SourceMgr.getFileOffset( Lex->getSourceLocation(Lex->getBufferLocation() - 2 + Text.size()))); diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp index b1034002f351bf..b9a000faae7cf7 100644 --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/clang/lib/Format/TokenAnnotator.cpp @@ -256,6 +256,18 @@ class AnnotatingParser { } } } + if (Style.isTableGen()) { + if (CurrentToken->isOneOf(tok::comma, tok::equal)) { + // They appear as separators. Unless they are not in class definition. + next(); + continue; + } + // In angle, there must be Value like tokens. Types are also able to be + // parsed in the same way with Values. + if (!parseTableGenValue()) + return false; + continue; + } if (!consumeToken()) return false; } @@ -388,6 +400,28 @@ class AnnotatingParser { Contexts.back().IsExpression = !IsForOrCatch; } + if (Style.isTableGen()) { + if (FormatToken *Prev = OpeningParen.Previous) { + if (Prev->is(TT_TableGenCondOperator)) { + Contexts.back().IsTableGenCondOpe = true; + Contexts.back().IsExpression = true; + } else if (Contexts.size() > 1 && + Contexts[Contexts.size() - 2].IsTableGenBangOpe) { + // Hack to handle bang operators. The parent context's flag + // was set by parseTableGenSimpleValue(). + // We have to specify the context outside because the prev of "(" may + // be ">", not the bang operator in this case. + Contexts.back().IsTableGenBangOpe = true; + Contexts.back().IsExpression = true; + } else { + // Otherwise, this paren seems DAGArg. + if (!parseTableGenDAGArg()) + return false; + return parseTableGenDAGArgAndList(&OpeningParen); + } + } + } + // Infer the role of the l_paren based on the previous token if we haven't // detected one yet. if (PrevNonComment && OpeningParen.is(TT_Unknown)) { @@ -549,6 +583,22 @@ class AnnotatingParser { if (CurrentToken->is(tok::comma)) Contexts.back().CanBeExpression = true; + if (Style.isTableGen()) { + if (CurrentToken->is(tok::comma)) { + if (Contexts.back().IsTableGenCondOpe) + CurrentToken->setType(TT_TableGenCondOperatorComma); + next(); + } else if (CurrentToken->is(tok::colon)) { + if (Contexts.back().IsTableGenCondOpe) + CurrentToken->setType(TT_TableGenCondOperatorColon); + next(); + } + // In TableGen there must be Values in parens. + if (!parseTableGenValue()) + return false; + continue; + } + FormatToken *Tok = CurrentToken; if (!consumeToken()) return false; @@ -803,6 +853,8 @@ class AnnotatingParser { if (Left->BlockParameterCount > 1) Contexts.back().FirstObjCSelectorName->LongestObjCSelectorName = 0; } + if (Style.isTableGen() && Left->is(TT_TableGenListOpener)) + CurrentToken->setType(TT_TableGenListCloser); next(); return true; } @@ -833,6 +885,19 @@ class AnnotatingParser { Left->setType(TT_ArrayInitializerLSquare); } FormatToken *Tok = CurrentToken; + if (Style.isTableGen()) { + if (CurrentToken->isOneOf(tok::comma, tok::minus, tok::ellipsis)) { + // '-' and '...' appears as a separator in slice. + next(); + } else { + // In TableGen there must be a list of Values in square brackets. + // It must be ValueList or SliceElements. + if (!parseTableGenValue()) + return false; + } + updateParameterCount(Left, Tok); + continue; + } if (!consumeToken()) return false; updateParameterCount(Left, Tok); @@ -840,6 +905,193 @@ class AnnotatingParser { return false; } + void skipToNextNonComment() { + next(); + while (CurrentToken && CurrentToken->is(tok::comment)) + next(); + } + + // Simplified parser for TableGen Value. Returns true on success. + // It consists of SimpleValues, SimpleValues with Suffixes, and Value followed + // by '#', paste operator. + // There also exists the case the Value is parsed as NameValue. + // In this case, the Value ends if '{' is found. + bool parseTableGenValue(bool ParseNameMode = false) { + if (!CurrentToken) + return false; + while (CurrentToken->is(tok::comment)) + next(); + if (!parseTableGenSimpleValue()) + return false; + if (!CurrentToken) + return true; + // Value "#" [Value] + if (CurrentToken->is(tok::hash)) { + if (CurrentToken->Next && + CurrentToken->Next->isOneOf(tok::colon, tok::semi, tok::l_brace)) { + // Trailing paste operator. + // These are only the allowed cases in TGParser::ParseValue(). + CurrentToken->setType(TT_TableGenTrailingPasteOperator); + next(); + return true; + } + FormatToken *HashTok = CurrentToken; + skipToNextNonComment(); + HashTok->setType(TT_Unknown); + if (!parseTableGenValue(ParseNameMode)) + return false; + } + // In name mode, '{' is regarded as the end of the value. + // See TGParser::ParseValue in TGParser.cpp + if (ParseNameMode && CurrentToken->is(tok::l_brace)) + return true; + // These tokens indicates this is a value with suffixes. + if (CurrentToken->isOneOf(tok::l_brace, tok::l_square, tok::period)) { + CurrentToken->setType(TT_TableGenValueSuffix); + FormatToken *Suffix = CurrentToken; + skipToNextNonComment(); + if (Suffix->is(tok::l_square)) + return parseSquare(); + if (Suffix->is(tok::l_brace)) { + Scopes.push_back(getScopeType(*Suffix)); + return parseBrace(); + } + } + return true; + } + + // TokVarName ::= "$" ualpha (ualpha | "0"..."9")* + // Appears as a part of DagArg. + // This does not change the current token on fail. + bool tryToParseTableGenTokVar() { + if (!CurrentToken) + return false; + if (CurrentToken->is(tok::identifier) && + CurrentToken->TokenText.front() == '$') { + skipToNextNonComment(); + return true; + } + return false; + } + + // DagArg ::= Value [":" TokVarName] | TokVarName + // Appears as a part of SimpleValue6. + bool parseTableGenDAGArg() { + if (tryToParseTableGenTokVar()) + return true; + if (parseTableGenValue()) { + if (CurrentToken && CurrentToken->is(tok::colon)) { + CurrentToken->setType(TT_TableGenDAGArgListColon); + skipToNextNonComment(); + return tryToParseTableGenTokVar(); + } + return true; + } + return false; + } + + // SimpleValue6 ::= "(" DagArg [DagArgList] ")" + // This parses SimpleValue 6's inside part of "(" ")" + bool parseTableGenDAGArgAndList(FormatToken *Opener) { + if (!parseTableGenDAGArg()) + return false; + // Parse the [DagArgList] part + bool FirstDAGArgListElm = true; + while (CurrentToken) { + if (!FirstDAGArgListElm && CurrentToken->is(tok::comma)) { + CurrentToken->setType(TT_TableGenDAGArgListComma); + skipToNextNonComment(); + } + if (CurrentToken && CurrentToken->is(tok::r_paren)) { + CurrentToken->setType(TT_TableGenDAGArgCloser); + Opener->MatchingParen = CurrentToken; + CurrentToken->MatchingParen = Opener; + skipToNextNonComment(); + return true; + } + if (!parseTableGenDAGArg()) + return false; + FirstDAGArgListElm = false; + } + return false; + } + + bool parseTableGenSimpleValue() { + assert(Style.isTableGen()); + if (!CurrentToken) + return false; + FormatToken *Tok = CurrentToken; + skipToNextNonComment(); + // SimpleValue 1, 2, 3: Literals + if (Tok->isOneOf(tok::numeric_constant, tok::string_literal, + TT_TableGenMultiLineString, tok::kw_true, tok::kw_false, + tok::question, tok::kw_int)) { + return true; + } + // SimpleValue 4: ValueList, Type + if (Tok->is(tok::l_brace)) { + Scopes.push_back(getScopeType(*Tok)); + return parseBrace(); + } + // SimpleValue 5: List initializer + if (Tok->is(tok::l_square)) { + Tok->setType(TT_TableGenListOpener); + if (!parseSquare()) + return false; + if (Tok->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + return parseAngle(); + } + return true; + } + // SimpleValue 6: DAGArg [DAGArgList] + // SimpleValue6 ::= "(" DagArg [DagArgList] ")" + if (Tok->is(tok::l_paren)) { + Tok->setType(TT_TableGenDAGArgOpener); + return parseTableGenDAGArgAndList(Tok); + } + // SimpleValue 9: Bang operator + if (Tok->is(TT_TableGenBangOperator)) { + if (CurrentToken && CurrentToken->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + skipToNextNonComment(); + if (!parseAngle()) + return false; + } + if (!CurrentToken || CurrentToken->isNot(tok::l_paren)) + return false; + skipToNextNonComment(); + // FIXME: Hack using inheritance to child context + Contexts.back().IsTableGenBangOpe = true; + bool Result = parseParens(); + Contexts.back().IsTableGenBangOpe = false; + return Result; + } + // SimpleValue 9: Cond operator + if (Tok->is(TT_TableGenCondOperator)) { + Tok = CurrentToken; + skipToNextNonComment(); + if (!Tok || Tok->isNot(tok::l_paren)) + return false; + bool Result = parseParens(); + return Result; + } + // We have to check identifier at the last because the kind of bang/cond + // operators are also identifier. + // SimpleValue 7: Identifiers + if (Tok->is(tok::identifier)) { + // SimpleValue 8: Anonymous record + if (CurrentToken && CurrentToken->is(tok::less)) { + CurrentToken->setType(TT_TemplateOpener); + skipToNextNonComment(); + return parseAngle(); + } + return true; + } + + return false; + } + bool couldBeInStructArrayInitializer() const { if (Contexts.size() < 2) return false; @@ -880,6 +1132,8 @@ class AnnotatingParser { OpeningBrace.getPreviousNonComment()->isNot(Keywords.kw_apostrophe))) { Contexts.back().VerilogMayBeConcatenation = true; } + if (Style.isTableGen()) + Contexts.back().ColonIsDictLiteral = false; unsigned CommaCount = 0; while (CurrentToken) { @@ -906,7 +1160,7 @@ class AnnotatingParser { FormatToken *Previous = CurrentToken->getPreviousNonComment(); if (Previous->is(TT_JsTypeOptionalQuestion)) Previous = Previous->getPreviousNonComment(); - if ((CurrentToken->is(tok::colon) && + if ((CurrentToken->is(tok::colon) && !Style.isTableGen() && (!Contexts.back().ColonIsDictLiteral || !Style.isCpp())) || Style.isProto()) { OpeningBrace.setType(TT_DictLiteral); @@ -915,10 +1169,12 @@ class AnnotatingParser { Previous->setType(TT_SelectorName); } } - if (CurrentToken->is(tok::colon) && OpeningBrace.is(TT_Unknown)) + if (CurrentToken->is(tok::colon) && OpeningBrace.is(TT_Unknown) && + !Style.isTableGen()) { OpeningBrace.setType(TT_DictLiteral); - else if (Style.isJavaScript()) + } else if (Style.isJavaScript()) { OpeningBrace.overwriteFixedType(TT_DictLiteral); + } } if (CurrentToken->is(tok::comma)) { if (Style.isJavaScript()) @@ -989,6 +1245,9 @@ class AnnotatingParser { // operators. if (Tok->is(TT_VerilogTableItem)) return true; + // Multi-line string itself is a single annotated token. + if (Tok->is(TT_TableGenMultiLineString)) + return true; switch (Tok->Tok.getKind()) { case tok::plus: case tok::minus: @@ -1119,6 +1378,10 @@ class AnnotatingParser { Tok->setType(TT_ObjCMethodExpr); } else if (Contexts.back().ContextKind == tok::l_paren && !Line.InPragmaDirective) { + if (Style.isTableGen() && Contexts.back().IsTableGenDAGArg) { + Tok->setType(TT_TableGenDAGArgListColon); + break; + } Tok->setType(TT_InlineASMColon); } break; @@ -1130,6 +1393,14 @@ class AnnotatingParser { Tok->setType(TT_JsTypeOperator); break; case tok::kw_if: + if (Style.isTableGen()) { + // In TableGen it has the form 'if' 'then'. + if (!parseTableGenValue()) + return false; + if (CurrentToken && CurrentToken->is(Keywords.kw_then)) + next(); // skip then + break; + } if (CurrentToken && CurrentToken->isOneOf(tok::kw_constexpr, tok::identifier)) { next(); @@ -1235,6 +1506,8 @@ class AnnotatingParser { } break; case tok::l_square: + if (Style.isTableGen()) + Tok->setType(TT_TableGenListOpener); if (!parseSquare()) return false; break; @@ -1264,6 +1537,8 @@ class AnnotatingParser { if (Previous && Previous->getType() != TT_DictLiteral) Previous->setType(TT_SelectorName); } + if (Style.isTableGen()) + Tok->setType(TT_TemplateOpener); } else { Tok->setType(TT_BinaryOperator); NonTemplateLess.insert(Tok); @@ -1423,11 +1698,28 @@ class AnnotatingParser { if (!Tok->getPreviousNonComment()) Line.IsContinuation = true; } + if (Style.isTableGen()) { + if (Tok->is(Keywords.kw_assert)) { + if (!parseTableGenValue()) + return false; + } else if (Tok->isOneOf(Keywords.kw_def, Keywords.kw_defm) && + (!Tok->Next || + !Tok->Next->isOneOf(tok::colon, tok::l_brace))) { + // The case NameValue appears. + if (!parseTableGenValue(true)) + return false; + } + } break; case tok::arrow: if (Tok->Previous && Tok->Previous->is(tok::kw_noexcept)) Tok->setType(TT_TrailingReturnArrow); break; + case tok::equal: + // In TableGen, there must be a value after "="; + if (Style.isTableGen() && !parseTableGenValue()) + return false; + break; default: break; } @@ -1757,6 +2049,9 @@ class AnnotatingParser { // Whether the braces may mean concatenation instead of structure or array // literal. bool VerilogMayBeConcatenation = false; + bool IsTableGenDAGArg = false; + bool IsTableGenBangOpe = false; + bool IsTableGenCondOpe = false; enum { Unknown, // Like the part after `:` in a constructor. @@ -2061,6 +2356,9 @@ class AnnotatingParser { // In JavaScript, `interface X { foo?(): bar; }` is an optional method // on the interface, not a ternary expression. Current.setType(TT_JsTypeOptionalQuestion); + } else if (Style.isTableGen()) { + // In TableGen, '?' is just an identifier like token. + Current.setType(TT_Unknown); } else { Current.setType(TT_ConditionalExpr); } @@ -2239,6 +2537,9 @@ class AnnotatingParser { // keywords such as let and def* defines names. if (Keywords.isTableGenDefinition(*PreviousNotConst)) return true; + // Otherwise C++ style declarations is available only inside the brace. + if (Contexts.back().ContextKind != tok::l_brace) + return false; } bool IsPPKeyword = PreviousNotConst->is(tok::identifier) && diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index d4f9b3f9df524e..d84914c6a4cf1c 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -495,12 +495,15 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) { do { NextTok = Tokens->getNextToken(); } while (NextTok->is(tok::comment)); - while (NextTok->is(tok::hash) && !Line->InMacroBody) { - NextTok = Tokens->getNextToken(); - do { + if (!Style.isTableGen()) { + // InTableGen, '#' is like binary operator. Not a preprocessor directive. + while (NextTok->is(tok::hash) && !Line->InMacroBody) { NextTok = Tokens->getNextToken(); - } while (NextTok->is(tok::comment) || - (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof))); + do { + NextTok = Tokens->getNextToken(); + } while (NextTok->is(tok::comment) || + (NextTok->NewlinesBefore == 0 && NextTok->isNot(tok::eof))); + } } switch (Tok->Tok.getKind()) { diff --git a/clang/lib/Headers/ia32intrin.h b/clang/lib/Headers/ia32intrin.h index 1b979770e19623..8e65f232a0def8 100644 --- a/clang/lib/Headers/ia32intrin.h +++ b/clang/lib/Headers/ia32intrin.h @@ -26,8 +26,8 @@ #define __DEFAULT_FN_ATTRS_CONSTEXPR __DEFAULT_FN_ATTRS #endif -/// Find the first set bit starting from the lsb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the least significant bit. The result +/// is undefined if the input is 0. /// /// \headerfile /// @@ -43,8 +43,8 @@ __bsfd(int __A) { return __builtin_ctz((unsigned int)__A); } -/// Find the first set bit starting from the msb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the most significant bit. The result +/// is undefined if the input is 0. /// /// \headerfile /// @@ -90,8 +90,8 @@ _bswap(int __A) { return (int)__builtin_bswap32((unsigned int)__A); } -/// Find the first set bit starting from the lsb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the least significant bit. The result +/// is undefined if the input is 0. /// /// \headerfile /// @@ -108,8 +108,8 @@ _bswap(int __A) { /// \see __bsfd #define _bit_scan_forward(A) __bsfd((A)) -/// Find the first set bit starting from the msb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the most significant bit. The result +/// is undefined if the input is 0. /// /// \headerfile /// @@ -127,8 +127,8 @@ _bswap(int __A) { #define _bit_scan_reverse(A) __bsrd((A)) #ifdef __x86_64__ -/// Find the first set bit starting from the lsb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the least significant bit. The result +/// is undefined if the input is 0. /// /// \headerfile /// @@ -143,8 +143,8 @@ __bsfq(long long __A) { return (long long)__builtin_ctzll((unsigned long long)__A); } -/// Find the first set bit starting from the msb. Result is undefined if -/// input is 0. +/// Finds the first set bit starting from the most significant bit. The result +/// is undefined if input is 0. /// /// \headerfile /// @@ -159,7 +159,7 @@ __bsrq(long long __A) { return 63 - __builtin_clzll((unsigned long long)__A); } -/// Swaps the bytes in the input. Converting little endian to big endian or +/// Swaps the bytes in the input, converting little endian to big endian or /// vice versa. /// /// \headerfile @@ -175,7 +175,7 @@ __bswapq(long long __A) { return (long long)__builtin_bswap64((unsigned long long)__A); } -/// Swaps the bytes in the input. Converting little endian to big endian or +/// Swaps the bytes in the input, converting little endian to big endian or /// vice versa. /// /// \headerfile @@ -198,7 +198,7 @@ __bswapq(long long __A) { /// \headerfile /// /// This intrinsic corresponds to the \c POPCNT instruction or a -/// a sequence of arithmetic and logic ops to calculate it. +/// sequence of arithmetic and logic operations to calculate it. /// /// \param __A /// An unsigned 32-bit integer operand. @@ -220,7 +220,7 @@ __popcntd(unsigned int __A) /// \endcode /// /// This intrinsic corresponds to the \c POPCNT instruction or a -/// a sequence of arithmetic and logic ops to calculate it. +/// sequence of arithmetic and logic operations to calculate it. /// /// \param A /// An unsigned 32-bit integer operand. @@ -235,7 +235,7 @@ __popcntd(unsigned int __A) /// \headerfile /// /// This intrinsic corresponds to the \c POPCNT instruction or a -/// a sequence of arithmetic and logic ops to calculate it. +/// sequence of arithmetic and logic operations to calculate it. /// /// \param __A /// An unsigned 64-bit integer operand. @@ -257,7 +257,7 @@ __popcntq(unsigned long long __A) /// \endcode /// /// This intrinsic corresponds to the \c POPCNT instruction or a -/// a sequence of arithmetic and logic ops to calculate it. +/// sequence of arithmetic and logic operations to calculate it. /// /// \param A /// An unsigned 64-bit integer operand. @@ -268,7 +268,7 @@ __popcntq(unsigned long long __A) #endif /* __x86_64__ */ #ifdef __x86_64__ -/// Returns the program status and control \c RFLAGS register with the \c VM +/// Returns the program status-and-control \c RFLAGS register with the \c VM /// and \c RF flags cleared. /// /// \headerfile @@ -282,7 +282,7 @@ __readeflags(void) return __builtin_ia32_readeflags_u64(); } -/// Writes the specified value to the program status and control \c RFLAGS +/// Writes the specified value to the program status-and-control \c RFLAGS /// register. Reserved bits are not affected. /// /// \headerfile @@ -298,7 +298,7 @@ __writeeflags(unsigned long long __f) } #else /* !__x86_64__ */ -/// Returns the program status and control \c EFLAGS register with the \c VM +/// Returns the program status-and-control \c EFLAGS register with the \c VM /// and \c RF flags cleared. /// /// \headerfile @@ -312,7 +312,7 @@ __readeflags(void) return __builtin_ia32_readeflags_u32(); } -/// Writes the specified value to the program status and control \c EFLAGS +/// Writes the specified value to the program status-and-control \c EFLAGS /// register. Reserved bits are not affected. /// /// \headerfile @@ -328,7 +328,7 @@ __writeeflags(unsigned int __f) } #endif /* !__x86_64__ */ -/// Cast a 32-bit float value to a 32-bit unsigned integer value. +/// Casts a 32-bit float value to a 32-bit unsigned integer value. /// /// \headerfile /// @@ -337,13 +337,13 @@ __writeeflags(unsigned int __f) /// /// \param __A /// A 32-bit float value. -/// \returns a 32-bit unsigned integer containing the converted value. +/// \returns A 32-bit unsigned integer containing the converted value. static __inline__ unsigned int __DEFAULT_FN_ATTRS_CAST _castf32_u32(float __A) { return __builtin_bit_cast(unsigned int, __A); } -/// Cast a 64-bit float value to a 64-bit unsigned integer value. +/// Casts a 64-bit float value to a 64-bit unsigned integer value. /// /// \headerfile /// @@ -352,13 +352,13 @@ _castf32_u32(float __A) { /// /// \param __A /// A 64-bit float value. -/// \returns a 64-bit unsigned integer containing the converted value. +/// \returns A 64-bit unsigned integer containing the converted value. static __inline__ unsigned long long __DEFAULT_FN_ATTRS_CAST _castf64_u64(double __A) { return __builtin_bit_cast(unsigned long long, __A); } -/// Cast a 32-bit unsigned integer value to a 32-bit float value. +/// Casts a 32-bit unsigned integer value to a 32-bit float value. /// /// \headerfile /// @@ -367,13 +367,13 @@ _castf64_u64(double __A) { /// /// \param __A /// A 32-bit unsigned integer value. -/// \returns a 32-bit float value containing the converted value. +/// \returns A 32-bit float value containing the converted value. static __inline__ float __DEFAULT_FN_ATTRS_CAST _castu32_f32(unsigned int __A) { return __builtin_bit_cast(float, __A); } -/// Cast a 64-bit unsigned integer value to a 64-bit float value. +/// Casts a 64-bit unsigned integer value to a 64-bit float value. /// /// \headerfile /// @@ -382,7 +382,7 @@ _castu32_f32(unsigned int __A) { /// /// \param __A /// A 64-bit unsigned integer value. -/// \returns a 64-bit float value containing the converted value. +/// \returns A 64-bit float value containing the converted value. static __inline__ double __DEFAULT_FN_ATTRS_CAST _castu64_f64(unsigned long long __A) { return __builtin_bit_cast(double, __A); @@ -470,7 +470,7 @@ __crc32q(unsigned long long __C, unsigned long long __D) } #endif /* __x86_64__ */ -/// Reads the specified performance monitoring counter. Refer to your +/// Reads the specified performance-monitoring counter. Refer to your /// processor's documentation to determine which performance counters are /// supported. /// @@ -487,7 +487,7 @@ __rdpmc(int __A) { return __builtin_ia32_rdpmc(__A); } -/// Reads the processor's time stamp counter and the \c IA32_TSC_AUX MSR +/// Reads the processor's time-stamp counter and the \c IA32_TSC_AUX MSR /// \c (0xc0000103). /// /// \headerfile @@ -495,14 +495,14 @@ __rdpmc(int __A) { /// This intrinsic corresponds to the \c RDTSCP instruction. /// /// \param __A -/// Address of where to store the 32-bit \c IA32_TSC_AUX value. -/// \returns The 64-bit value of the time stamp counter. +/// The address of where to store the 32-bit \c IA32_TSC_AUX value. +/// \returns The 64-bit value of the time-stamp counter. static __inline__ unsigned long long __DEFAULT_FN_ATTRS __rdtscp(unsigned int *__A) { return __builtin_ia32_rdtscp(__A); } -/// Reads the processor's time stamp counter. +/// Reads the processor's time-stamp counter. /// /// \headerfile /// @@ -512,7 +512,7 @@ __rdtscp(unsigned int *__A) { /// /// This intrinsic corresponds to the \c RDTSC instruction. /// -/// \returns The 64-bit value of the time stamp counter. +/// \returns The 64-bit value of the time-stamp counter. #define _rdtsc() __rdtsc() /// Reads the specified performance monitoring counter. Refer to your diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 049f39c085bf54..1fd0f2479251ce 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -7161,13 +7161,11 @@ static bool CheckNonNullExpr(Sema &S, const Expr *Expr) { // As a special case, transparent unions initialized with zero are // considered null for the purposes of the nonnull attribute. - if (const RecordType *UT = Expr->getType()->getAsUnionType()) { - if (UT->getDecl()->hasAttr()) - if (const CompoundLiteralExpr *CLE = - dyn_cast(Expr)) - if (const InitListExpr *ILE = - dyn_cast(CLE->getInitializer())) - Expr = ILE->getInit(0); + if (const RecordType *UT = Expr->getType()->getAsUnionType(); + UT && UT->getDecl()->hasAttr()) { + if (const auto *CLE = dyn_cast(Expr)) + if (const auto *ILE = dyn_cast(CLE->getInitializer())) + Expr = ILE->getInit(0); } bool Result; diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 529fbcbfeff8e2..be23c0fffe0576 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -13070,7 +13070,8 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, TemplateDeductionInfo Info(DeduceInit->getExprLoc()); TemplateDeductionResult Result = DeduceAutoType(TSI->getTypeLoc(), DeduceInit, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) { + if (Result != TemplateDeductionResult::Success && + Result != TemplateDeductionResult::AlreadyDiagnosed) { if (!IsInitCapture) DiagnoseAutoDeductionFailure(VDecl, DeduceInit); else if (isa(Init)) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index d785714c4d811e..d5526957937bbb 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -3501,9 +3501,16 @@ bool Sema::checkTargetAttr(SourceLocation LiteralLoc, StringRef AttrStr) { return false; } +static bool hasArmStreamingInterface(const FunctionDecl *FD) { + if (const auto *T = FD->getType()->getAs()) + if (T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) + return true; + return false; +} + // Check Target Version attrs -bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, - bool &isDefault) { +bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, Decl *D, + StringRef &AttrStr, bool &isDefault) { enum FirstParam { Unsupported }; enum SecondParam { None }; enum ThirdParam { Target, TargetClones, TargetVersion }; @@ -3519,6 +3526,8 @@ bool Sema::checkTargetVersionAttr(SourceLocation LiteralLoc, StringRef &AttrStr, return Diag(LiteralLoc, diag::warn_unsupported_target_attribute) << Unsupported << None << CurFeature << TargetVersion; } + if (hasArmStreamingInterface(cast(D))) + return Diag(LiteralLoc, diag::err_sme_streaming_cannot_be_multiversioned); return false; } @@ -3527,7 +3536,7 @@ static void handleTargetVersionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { SourceLocation LiteralLoc; bool isDefault = false; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &LiteralLoc) || - S.checkTargetVersionAttr(LiteralLoc, Str, isDefault)) + S.checkTargetVersionAttr(LiteralLoc, D, Str, isDefault)) return; // Do not create default only target_version attribute if (!isDefault) { @@ -3550,7 +3559,7 @@ static void handleTargetAttr(Sema &S, Decl *D, const ParsedAttr &AL) { bool Sema::checkTargetClonesAttrString( SourceLocation LiteralLoc, StringRef Str, const StringLiteral *Literal, - bool &HasDefault, bool &HasCommas, bool &HasNotDefault, + Decl *D, bool &HasDefault, bool &HasCommas, bool &HasNotDefault, SmallVectorImpl> &StringsBuffer) { enum FirstParam { Unsupported, Duplicate, Unknown }; enum SecondParam { None, CPU, Tune }; @@ -3619,6 +3628,9 @@ bool Sema::checkTargetClonesAttrString( HasNotDefault = true; } } + if (hasArmStreamingInterface(cast(D))) + return Diag(LiteralLoc, + diag::err_sme_streaming_cannot_be_multiversioned); } else { // Other targets ( currently X86 ) if (Cur.starts_with("arch=")) { @@ -3670,7 +3682,7 @@ static void handleTargetClonesAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!S.checkStringLiteralArgumentAttr(AL, I, CurStr, &LiteralLoc) || S.checkTargetClonesAttrString( LiteralLoc, CurStr, - cast(AL.getArgAsExpr(I)->IgnoreParenCasts()), + cast(AL.getArgAsExpr(I)->IgnoreParenCasts()), D, HasDefault, HasCommas, HasNotDefault, StringsBuffer)) return; } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 246d2313e089f3..f2b89135af21cf 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -1554,12 +1554,13 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, TemplateDeductionInfo Info(Deduce->getExprLoc()); TemplateDeductionResult Result = DeduceAutoType(TInfo->getTypeLoc(), Deduce, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (Result != TemplateDeductionResult::Success && + Result != TemplateDeductionResult::AlreadyDiagnosed) return ExprError(Diag(TyBeginLoc, diag::err_auto_expr_deduction_failure) << Ty << Deduce->getType() << FullRange << Deduce->getSourceRange()); if (DeducedType.isNull()) { - assert(Result == TDK_AlreadyDiagnosed); + assert(Result == TemplateDeductionResult::AlreadyDiagnosed); return ExprError(); } @@ -2098,12 +2099,13 @@ ExprResult Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, TemplateDeductionInfo Info(Deduce->getExprLoc()); TemplateDeductionResult Result = DeduceAutoType(AllocTypeInfo->getTypeLoc(), Deduce, DeducedType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (Result != TemplateDeductionResult::Success && + Result != TemplateDeductionResult::AlreadyDiagnosed) return ExprError(Diag(StartLoc, diag::err_auto_new_deduction_failure) << AllocType << Deduce->getType() << TypeRange << Deduce->getSourceRange()); if (DeducedType.isNull()) { - assert(Result == TDK_AlreadyDiagnosed); + assert(Result == TemplateDeductionResult::AlreadyDiagnosed); return ExprError(); } AllocType = DeducedType; @@ -2883,7 +2885,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // expected function type. TemplateDeductionInfo Info(StartLoc); if (DeduceTemplateArguments(FnTmpl, nullptr, ExpectedFunctionType, Fn, - Info)) + Info) != TemplateDeductionResult::Success) continue; } else Fn = cast((*D)->getUnderlyingDecl()); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 02b1a045df44c2..d3a9c7abd0e944 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -1200,8 +1200,8 @@ static bool LookupDirect(Sema &S, LookupResult &R, const DeclContext *DC) { // Perform template argument deduction against the type that we would // expect the function to have. if (R.getSema().DeduceTemplateArguments(ConvTemplate, nullptr, ExpectedType, - Specialization, Info) - == Sema::TDK_Success) { + Specialization, Info) == + TemplateDeductionResult::Success) { R.addDecl(Specialization); Found = true; } diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 42960c229077c3..9381b8c6626b64 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -628,28 +628,28 @@ namespace { /// to the form used in overload-candidate information. DeductionFailureInfo clang::MakeDeductionFailureInfo(ASTContext &Context, - Sema::TemplateDeductionResult TDK, + TemplateDeductionResult TDK, TemplateDeductionInfo &Info) { DeductionFailureInfo Result; Result.Result = static_cast(TDK); Result.HasDiagnostic = false; switch (TDK) { - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_CUDATargetMismatch: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::CUDATargetMismatch: Result.Data = nullptr; break; - case Sema::TDK_Incomplete: - case Sema::TDK_InvalidExplicitArguments: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::InvalidExplicitArguments: Result.Data = Info.Param.getOpaqueValue(); break; - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: { + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: { // FIXME: Should allocate from normal heap so that we can free this later. auto *Saved = new (Context) DFIDeducedMismatchArgs; Saved->FirstArg = Info.FirstArg; @@ -660,7 +660,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } - case Sema::TDK_NonDeducedMismatch: { + case TemplateDeductionResult::NonDeducedMismatch: { // FIXME: Should allocate from normal heap so that we can free this later. DFIArguments *Saved = new (Context) DFIArguments; Saved->FirstArg = Info.FirstArg; @@ -669,10 +669,10 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } - case Sema::TDK_IncompletePack: + case TemplateDeductionResult::IncompletePack: // FIXME: It's slightly wasteful to allocate two TemplateArguments for this. - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: { + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: { // FIXME: Should allocate from normal heap so that we can free this later. DFIParamWithArguments *Saved = new (Context) DFIParamWithArguments; Saved->Param = Info.Param; @@ -682,7 +682,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } - case Sema::TDK_SubstitutionFailure: + case TemplateDeductionResult::SubstitutionFailure: Result.Data = Info.takeSugared(); if (Info.hasSFINAEDiagnostic()) { PartialDiagnosticAt *Diag = new (Result.Diagnostic) PartialDiagnosticAt( @@ -692,7 +692,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, } break; - case Sema::TDK_ConstraintsNotSatisfied: { + case TemplateDeductionResult::ConstraintsNotSatisfied: { CNSInfo *Saved = new (Context) CNSInfo; Saved->TemplateArgs = Info.takeSugared(); Saved->Satisfaction = Info.AssociatedConstraintsSatisfaction; @@ -700,9 +700,9 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, break; } - case Sema::TDK_Success: - case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::Success: + case TemplateDeductionResult::NonDependentConversionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: llvm_unreachable("not a deduction failure"); } @@ -710,29 +710,29 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, } void DeductionFailureInfo::Destroy() { - switch (static_cast(Result)) { - case Sema::TDK_Success: - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_Incomplete: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_InvalidExplicitArguments: - case Sema::TDK_CUDATargetMismatch: - case Sema::TDK_NonDependentConversionFailure: + switch (static_cast(Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::InvalidExplicitArguments: + case TemplateDeductionResult::CUDATargetMismatch: + case TemplateDeductionResult::NonDependentConversionFailure: break; - case Sema::TDK_IncompletePack: - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: - case Sema::TDK_NonDeducedMismatch: + case TemplateDeductionResult::IncompletePack: + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: + case TemplateDeductionResult::NonDeducedMismatch: // FIXME: Destroy the data? Data = nullptr; break; - case Sema::TDK_SubstitutionFailure: + case TemplateDeductionResult::SubstitutionFailure: // FIXME: Destroy the template argument list? Data = nullptr; if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) { @@ -741,7 +741,7 @@ void DeductionFailureInfo::Destroy() { } break; - case Sema::TDK_ConstraintsNotSatisfied: + case TemplateDeductionResult::ConstraintsNotSatisfied: // FIXME: Destroy the template argument list? Data = nullptr; if (PartialDiagnosticAt *Diag = getSFINAEDiagnostic()) { @@ -751,8 +751,8 @@ void DeductionFailureInfo::Destroy() { break; // Unhandled - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: break; } } @@ -764,33 +764,33 @@ PartialDiagnosticAt *DeductionFailureInfo::getSFINAEDiagnostic() { } TemplateParameter DeductionFailureInfo::getTemplateParameter() { - switch (static_cast(Result)) { - case Sema::TDK_Success: - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: - case Sema::TDK_NonDeducedMismatch: - case Sema::TDK_CUDATargetMismatch: - case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: + switch (static_cast(Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::SubstitutionFailure: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: + case TemplateDeductionResult::NonDeducedMismatch: + case TemplateDeductionResult::CUDATargetMismatch: + case TemplateDeductionResult::NonDependentConversionFailure: + case TemplateDeductionResult::ConstraintsNotSatisfied: return TemplateParameter(); - case Sema::TDK_Incomplete: - case Sema::TDK_InvalidExplicitArguments: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::InvalidExplicitArguments: return TemplateParameter::getFromOpaqueValue(Data); - case Sema::TDK_IncompletePack: - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: + case TemplateDeductionResult::IncompletePack: + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: return static_cast(Data)->Param; // Unhandled - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: break; } @@ -798,35 +798,35 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { } TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { - switch (static_cast(Result)) { - case Sema::TDK_Success: - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_Incomplete: - case Sema::TDK_IncompletePack: - case Sema::TDK_InvalidExplicitArguments: - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: - case Sema::TDK_NonDeducedMismatch: - case Sema::TDK_CUDATargetMismatch: - case Sema::TDK_NonDependentConversionFailure: + switch (static_cast(Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::IncompletePack: + case TemplateDeductionResult::InvalidExplicitArguments: + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: + case TemplateDeductionResult::NonDeducedMismatch: + case TemplateDeductionResult::CUDATargetMismatch: + case TemplateDeductionResult::NonDependentConversionFailure: return nullptr; - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: return static_cast(Data)->TemplateArgs; - case Sema::TDK_SubstitutionFailure: + case TemplateDeductionResult::SubstitutionFailure: return static_cast(Data); - case Sema::TDK_ConstraintsNotSatisfied: + case TemplateDeductionResult::ConstraintsNotSatisfied: return static_cast(Data)->TemplateArgs; // Unhandled - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: break; } @@ -834,31 +834,31 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { } const TemplateArgument *DeductionFailureInfo::getFirstArg() { - switch (static_cast(Result)) { - case Sema::TDK_Success: - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_Incomplete: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_InvalidExplicitArguments: - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_CUDATargetMismatch: - case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: + switch (static_cast(Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::InvalidExplicitArguments: + case TemplateDeductionResult::SubstitutionFailure: + case TemplateDeductionResult::CUDATargetMismatch: + case TemplateDeductionResult::NonDependentConversionFailure: + case TemplateDeductionResult::ConstraintsNotSatisfied: return nullptr; - case Sema::TDK_IncompletePack: - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: - case Sema::TDK_NonDeducedMismatch: + case TemplateDeductionResult::IncompletePack: + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: + case TemplateDeductionResult::NonDeducedMismatch: return &static_cast(Data)->FirstArg; // Unhandled - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: break; } @@ -866,31 +866,31 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { } const TemplateArgument *DeductionFailureInfo::getSecondArg() { - switch (static_cast(Result)) { - case Sema::TDK_Success: - case Sema::TDK_Invalid: - case Sema::TDK_InstantiationDepth: - case Sema::TDK_Incomplete: - case Sema::TDK_IncompletePack: - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: - case Sema::TDK_InvalidExplicitArguments: - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_CUDATargetMismatch: - case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_ConstraintsNotSatisfied: + switch (static_cast(Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::InstantiationDepth: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::IncompletePack: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: + case TemplateDeductionResult::InvalidExplicitArguments: + case TemplateDeductionResult::SubstitutionFailure: + case TemplateDeductionResult::CUDATargetMismatch: + case TemplateDeductionResult::NonDependentConversionFailure: + case TemplateDeductionResult::ConstraintsNotSatisfied: return nullptr; - case Sema::TDK_Inconsistent: - case Sema::TDK_Underqualified: - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: - case Sema::TDK_NonDeducedMismatch: + case TemplateDeductionResult::Inconsistent: + case TemplateDeductionResult::Underqualified: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: + case TemplateDeductionResult::NonDeducedMismatch: return &static_cast(Data)->SecondArg; // Unhandled - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_AlreadyDiagnosed: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: break; } @@ -898,9 +898,9 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { } std::optional DeductionFailureInfo::getCallArgIndex() { - switch (static_cast(Result)) { - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: + switch (static_cast(Result)) { + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: return static_cast(Data)->CallArgIndex; default: @@ -7548,12 +7548,14 @@ void Sema::AddMethodTemplateCandidate( if (TemplateDeductionResult Result = DeduceTemplateArguments( MethodTmpl, ExplicitTemplateArgs, Args, Specialization, Info, PartialOverloading, /*AggregateDeductionCandidate=*/false, ObjectType, - ObjectClassification, [&](ArrayRef ParamTypes) { + ObjectClassification, + [&](ArrayRef ParamTypes) { return CheckNonDependentConversions( MethodTmpl, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, ActingContext, ObjectType, ObjectClassification, PO); - })) { + }); + Result != TemplateDeductionResult::Success) { OverloadCandidate &Candidate = CandidateSet.addCandidate(Conversions.size(), Conversions); Candidate.FoundDecl = FoundDecl; @@ -7566,7 +7568,7 @@ void Sema::AddMethodTemplateCandidate( cast(Candidate.Function)->isStatic() || ObjectType.isNull(); Candidate.ExplicitCallArguments = Args.size(); - if (Result == TDK_NonDependentConversionFailure) + if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; else { Candidate.FailureKind = ovl_fail_bad_deduction; @@ -7639,7 +7641,8 @@ void Sema::AddTemplateOverloadCandidate( return CheckNonDependentConversions( FunctionTemplate, ParamTypes, Args, CandidateSet, Conversions, SuppressUserConversions, nullptr, QualType(), {}, PO); - })) { + }); + Result != TemplateDeductionResult::Success) { OverloadCandidate &Candidate = CandidateSet.addCandidate(Conversions.size(), Conversions); Candidate.FoundDecl = FoundDecl; @@ -7655,7 +7658,7 @@ void Sema::AddTemplateOverloadCandidate( isa(Candidate.Function) && !isa(Candidate.Function); Candidate.ExplicitCallArguments = Args.size(); - if (Result == TDK_NonDependentConversionFailure) + if (Result == TemplateDeductionResult::NonDependentConversionFailure) Candidate.FailureKind = ovl_fail_bad_conversion; else { Candidate.FailureKind = ovl_fail_bad_deduction; @@ -8042,7 +8045,8 @@ void Sema::AddTemplateConversionCandidate( CXXConversionDecl *Specialization = nullptr; if (TemplateDeductionResult Result = DeduceTemplateArguments( FunctionTemplate, ObjectType, ObjectClassification, ToType, - Specialization, Info)) { + Specialization, Info); + Result != TemplateDeductionResult::Success) { OverloadCandidate &Candidate = CandidateSet.addCandidate(); Candidate.FoundDecl = FoundDecl; Candidate.Function = FunctionTemplate->getTemplatedDecl(); @@ -10655,7 +10659,8 @@ void Sema::diagnoseEquivalentInternalLinkageDeclarations( bool OverloadCandidate::NotValidBecauseConstraintExprHasError() const { return FailureKind == ovl_fail_bad_deduction && - DeductionFailure.Result == Sema::TDK_ConstraintsNotSatisfied && + static_cast(DeductionFailure.Result) == + TemplateDeductionResult::ConstraintsNotSatisfied && static_cast(DeductionFailure.Data) ->Satisfaction.ContainsErrors; } @@ -11358,11 +11363,13 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, if (NumArgs < MinParams) { assert((Cand->FailureKind == ovl_fail_too_few_arguments) || (Cand->FailureKind == ovl_fail_bad_deduction && - Cand->DeductionFailure.Result == Sema::TDK_TooFewArguments)); + Cand->DeductionFailure.getResult() == + TemplateDeductionResult::TooFewArguments)); } else { assert((Cand->FailureKind == ovl_fail_too_many_arguments) || (Cand->FailureKind == ovl_fail_bad_deduction && - Cand->DeductionFailure.Result == Sema::TDK_TooManyArguments)); + Cand->DeductionFailure.getResult() == + TemplateDeductionResult::TooManyArguments)); } return false; @@ -11445,11 +11452,18 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, (ParamD = Param.dyn_cast()) || (ParamD = Param.dyn_cast()) || (ParamD = Param.dyn_cast()); - switch (DeductionFailure.Result) { - case Sema::TDK_Success: - llvm_unreachable("TDK_success while diagnosing bad deduction"); + switch (DeductionFailure.getResult()) { + case TemplateDeductionResult::Success: + llvm_unreachable( + "TemplateDeductionResult::Success while diagnosing bad deduction"); + case TemplateDeductionResult::NonDependentConversionFailure: + llvm_unreachable("TemplateDeductionResult::NonDependentConversionFailure " + "while diagnosing bad deduction"); + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::AlreadyDiagnosed: + return; - case Sema::TDK_Incomplete: { + case TemplateDeductionResult::Incomplete: { assert(ParamD && "no parameter found for incomplete deduction result"); S.Diag(Templated->getLocation(), diag::note_ovl_candidate_incomplete_deduction) @@ -11458,7 +11472,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } - case Sema::TDK_IncompletePack: { + case TemplateDeductionResult::IncompletePack: { assert(ParamD && "no parameter found for incomplete deduction result"); S.Diag(Templated->getLocation(), diag::note_ovl_candidate_incomplete_deduction_pack) @@ -11469,7 +11483,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } - case Sema::TDK_Underqualified: { + case TemplateDeductionResult::Underqualified: { assert(ParamD && "no parameter found for bad qualifiers deduction result"); TemplateTypeParmDecl *TParam = cast(ParamD); @@ -11494,7 +11508,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } - case Sema::TDK_Inconsistent: { + case TemplateDeductionResult::Inconsistent: { assert(ParamD && "no parameter found for inconsistent deduction result"); int which = 0; if (isa(ParamD)) @@ -11539,7 +11553,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } - case Sema::TDK_InvalidExplicitArguments: + case TemplateDeductionResult::InvalidExplicitArguments: assert(ParamD && "no parameter found for invalid explicit arguments"); if (ParamD->getDeclName()) S.Diag(Templated->getLocation(), @@ -11561,7 +11575,7 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, MaybeEmitInheritedConstructorNote(S, Found); return; - case Sema::TDK_ConstraintsNotSatisfied: { + case TemplateDeductionResult::ConstraintsNotSatisfied: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; TemplateArgumentList *Args = DeductionFailure.getTemplateArgumentList(); @@ -11578,18 +11592,18 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, static_cast(DeductionFailure.Data)->Satisfaction); return; } - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: DiagnoseArityMismatch(S, Found, Templated, NumArgs); return; - case Sema::TDK_InstantiationDepth: + case TemplateDeductionResult::InstantiationDepth: S.Diag(Templated->getLocation(), diag::note_ovl_candidate_instantiation_depth); MaybeEmitInheritedConstructorNote(S, Found); return; - case Sema::TDK_SubstitutionFailure: { + case TemplateDeductionResult::SubstitutionFailure: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; if (TemplateArgumentList *Args = @@ -11639,8 +11653,8 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, return; } - case Sema::TDK_DeducedMismatch: - case Sema::TDK_DeducedMismatchNested: { + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::DeducedMismatchNested: { // Format the template argument list into the argument string. SmallString<128> TemplateArgString; if (TemplateArgumentList *Args = @@ -11656,11 +11670,12 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, << (*DeductionFailure.getCallArgIndex() + 1) << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg() << TemplateArgString - << (DeductionFailure.Result == Sema::TDK_DeducedMismatchNested); + << (DeductionFailure.getResult() == + TemplateDeductionResult::DeducedMismatchNested); break; } - case Sema::TDK_NonDeducedMismatch: { + case TemplateDeductionResult::NonDeducedMismatch: { // FIXME: Provide a source location to indicate what we couldn't match. TemplateArgument FirstTA = *DeductionFailure.getFirstArg(); TemplateArgument SecondTA = *DeductionFailure.getSecondArg(); @@ -11701,11 +11716,11 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, } // TODO: diagnose these individually, then kill off // note_ovl_candidate_bad_deduction, which is uselessly vague. - case Sema::TDK_MiscellaneousDeductionFailure: + case TemplateDeductionResult::MiscellaneousDeductionFailure: S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction); MaybeEmitInheritedConstructorNote(S, Found); return; - case Sema::TDK_CUDATargetMismatch: + case TemplateDeductionResult::CUDATargetMismatch: S.Diag(Templated->getLocation(), diag::note_cuda_ovl_candidate_target_mismatch); return; @@ -11716,8 +11731,9 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, unsigned NumArgs, bool TakingCandidateAddress) { - unsigned TDK = Cand->DeductionFailure.Result; - if (TDK == Sema::TDK_TooFewArguments || TDK == Sema::TDK_TooManyArguments) { + TemplateDeductionResult TDK = Cand->DeductionFailure.getResult(); + if (TDK == TemplateDeductionResult::TooFewArguments || + TDK == TemplateDeductionResult::TooManyArguments) { if (CheckArityMismatch(S, Cand, NumArgs)) return; } @@ -12051,38 +12067,38 @@ static SourceLocation GetLocationForCandidate(const OverloadCandidate *Cand) { } static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { - switch ((Sema::TemplateDeductionResult)DFI.Result) { - case Sema::TDK_Success: - case Sema::TDK_NonDependentConversionFailure: - case Sema::TDK_AlreadyDiagnosed: + switch (static_cast(DFI.Result)) { + case TemplateDeductionResult::Success: + case TemplateDeductionResult::NonDependentConversionFailure: + case TemplateDeductionResult::AlreadyDiagnosed: llvm_unreachable("non-deduction failure while diagnosing bad deduction"); - case Sema::TDK_Invalid: - case Sema::TDK_Incomplete: - case Sema::TDK_IncompletePack: + case TemplateDeductionResult::Invalid: + case TemplateDeductionResult::Incomplete: + case TemplateDeductionResult::IncompletePack: return 1; - case Sema::TDK_Underqualified: - case Sema::TDK_Inconsistent: + case TemplateDeductionResult::Underqualified: + case TemplateDeductionResult::Inconsistent: return 2; - case Sema::TDK_SubstitutionFailure: - case Sema::TDK_DeducedMismatch: - case Sema::TDK_ConstraintsNotSatisfied: - case Sema::TDK_DeducedMismatchNested: - case Sema::TDK_NonDeducedMismatch: - case Sema::TDK_MiscellaneousDeductionFailure: - case Sema::TDK_CUDATargetMismatch: + case TemplateDeductionResult::SubstitutionFailure: + case TemplateDeductionResult::DeducedMismatch: + case TemplateDeductionResult::ConstraintsNotSatisfied: + case TemplateDeductionResult::DeducedMismatchNested: + case TemplateDeductionResult::NonDeducedMismatch: + case TemplateDeductionResult::MiscellaneousDeductionFailure: + case TemplateDeductionResult::CUDATargetMismatch: return 3; - case Sema::TDK_InstantiationDepth: + case TemplateDeductionResult::InstantiationDepth: return 4; - case Sema::TDK_InvalidExplicitArguments: + case TemplateDeductionResult::InvalidExplicitArguments: return 5; - case Sema::TDK_TooManyArguments: - case Sema::TDK_TooFewArguments: + case TemplateDeductionResult::TooManyArguments: + case TemplateDeductionResult::TooFewArguments: return 6; } llvm_unreachable("Unhandled deduction result"); @@ -12810,11 +12826,10 @@ class AddressOfFunctionResolver { // overloaded functions considered. FunctionDecl *Specialization = nullptr; TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (Sema::TemplateDeductionResult Result - = S.DeduceTemplateArguments(FunctionTemplate, - &OvlExplicitTemplateArgs, - TargetFunctionType, Specialization, - Info, /*IsAddressOfFunction*/true)) { + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( + FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, + Specialization, Info, /*IsAddressOfFunction*/ true); + Result != TemplateDeductionResult::Success) { // Make a note of the failed deduction for diagnostics. FailedCandidates.addCandidate() .set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(), @@ -13305,10 +13320,10 @@ FunctionDecl *Sema::ResolveSingleFunctionTemplateSpecialization( // overloaded functions considered. FunctionDecl *Specialization = nullptr; TemplateDeductionInfo Info(ovl->getNameLoc()); - if (TemplateDeductionResult Result - = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, - Specialization, Info, - /*IsAddressOfFunction*/true)) { + if (TemplateDeductionResult Result = DeduceTemplateArguments( + FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info, + /*IsAddressOfFunction*/ true); + Result != TemplateDeductionResult::Success) { // Make a note of the failed deduction for diagnostics. if (FailedTSC) FailedTSC->addCandidate().set( diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index f6908718e2d151..335fad697092eb 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -2329,7 +2329,8 @@ Sema::ActOnObjCForCollectionStmt(SourceLocation ForLoc, FirstType = QualType(); TemplateDeductionResult Result = DeduceAutoType( D->getTypeSourceInfo()->getTypeLoc(), DeducedInit, FirstType, Info); - if (Result != TDK_Success && Result != TDK_AlreadyDiagnosed) + if (Result != TemplateDeductionResult::Success && + Result != TemplateDeductionResult::AlreadyDiagnosed) DiagnoseAutoDeductionFailure(D, DeducedInit); if (FirstType.isNull()) { D->setInvalidDecl(); @@ -2397,9 +2398,10 @@ static bool FinishForRangeVarDecl(Sema &SemaRef, VarDecl *Decl, Expr *Init, SemaRef.Diag(Loc, DiagID) << Init->getType(); } else { TemplateDeductionInfo Info(Init->getExprLoc()); - Sema::TemplateDeductionResult Result = SemaRef.DeduceAutoType( + TemplateDeductionResult Result = SemaRef.DeduceAutoType( Decl->getTypeSourceInfo()->getTypeLoc(), Init, InitType, Info); - if (Result != Sema::TDK_Success && Result != Sema::TDK_AlreadyDiagnosed) + if (Result != TemplateDeductionResult::Success && + Result != TemplateDeductionResult::AlreadyDiagnosed) SemaRef.Diag(Loc, DiagID) << Init->getType(); } @@ -3868,14 +3870,14 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, TemplateDeductionResult Res = DeduceAutoType( OrigResultType, RetExpr, Deduced, Info, /*DependentDeduction=*/false, /*IgnoreConstraints=*/false, &FailedTSC); - if (Res != TDK_Success && FD->isInvalidDecl()) + if (Res != TemplateDeductionResult::Success && FD->isInvalidDecl()) return true; switch (Res) { - case TDK_Success: + case TemplateDeductionResult::Success: break; - case TDK_AlreadyDiagnosed: + case TemplateDeductionResult::AlreadyDiagnosed: return true; - case TDK_Inconsistent: { + case TemplateDeductionResult::Inconsistent: { // If a function with a declared return type that contains a placeholder // type has multiple return statements, the return type is deduced for // each return statement. [...] if the type deduced is not the same in diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index cf781e0e1bf3f4..9e516da2aa27a1 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -4863,7 +4863,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, TemplateDeductionInfo Info(FailedCandidates.getLocation()); if (TemplateDeductionResult Result = - DeduceTemplateArguments(Partial, CanonicalConverted, Info)) { + DeduceTemplateArguments(Partial, CanonicalConverted, Info); + Result != TemplateDeductionResult::Success) { // Store the failed-deduction information for use in diagnostics, later. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate().set( @@ -7243,10 +7244,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // along with the other associated constraints after // checking the template argument list. /*IgnoreConstraints=*/true); - if (Result == TDK_AlreadyDiagnosed) { + if (Result == TemplateDeductionResult::AlreadyDiagnosed) { if (ParamType.isNull()) return ExprError(); - } else if (Result != TDK_Success) { + } else if (Result != TemplateDeductionResult::Success) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -9644,8 +9645,8 @@ bool Sema::CheckFunctionTemplateSpecialization( FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( cast(FunTmpl->getFirstDecl()), - ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, - Info)) { + ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info); + TDK != TemplateDeductionResult::Success) { // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. FailedCandidates.addCandidate().set( @@ -9666,7 +9667,8 @@ bool Sema::CheckFunctionTemplateSpecialization( IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttr = */ true)) { FailedCandidates.addCandidate().set( I.getPair(), FunTmpl->getTemplatedDecl(), - MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); + MakeDeductionFailureInfo( + Context, TemplateDeductionResult::CUDATargetMismatch, Info)); continue; } @@ -10816,11 +10818,10 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, TemplateDeductionInfo Info(FailedCandidates.getLocation()); FunctionDecl *Specialization = nullptr; - if (TemplateDeductionResult TDK - = DeduceTemplateArguments(FunTmpl, - (HasExplicitTemplateArgs ? &TemplateArgs - : nullptr), - R, Specialization, Info)) { + if (TemplateDeductionResult TDK = DeduceTemplateArguments( + FunTmpl, (HasExplicitTemplateArgs ? &TemplateArgs : nullptr), R, + Specialization, Info); + TDK != TemplateDeductionResult::Success) { // Keep track of almost-matches. FailedCandidates.addCandidate() .set(P.getPair(), FunTmpl->getTemplatedDecl(), @@ -10840,7 +10841,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, IdentifyCUDATarget(D.getDeclSpec().getAttributes())) { FailedCandidates.addCandidate().set( P.getPair(), FunTmpl->getTemplatedDecl(), - MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); + MakeDeductionFailureInfo( + Context, TemplateDeductionResult::CUDATargetMismatch, Info)); continue; } diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index a54ad27975890a..994c997b9f6acd 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -133,13 +133,13 @@ static bool hasSameExtendedValue(llvm::APSInt X, llvm::APSInt Y) { return X == Y; } -static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( +static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType Param, QualType Arg, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, bool PartialOrdering = false, bool DeducedFromArrayBound = false); -static Sema::TemplateDeductionResult +static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef Ps, ArrayRef As, @@ -393,10 +393,11 @@ checkDeducedTemplateArguments(ASTContext &Context, /// Deduce the value of the given non-type template parameter /// as the given deduced template argument. All non-type template parameter /// deduction is funneled through here. -static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( +static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, const DeducedTemplateArgument &NewDeduced, - QualType ValueType, TemplateDeductionInfo &Info, + const NonTypeTemplateParmDecl *NTTP, + const DeducedTemplateArgument &NewDeduced, QualType ValueType, + TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { assert(NTTP->getDepth() == Info.getDeducedDepth() && "deducing non-type template argument with wrong depth"); @@ -407,19 +408,19 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( Info.Param = const_cast(NTTP); Info.FirstArg = Deduced[NTTP->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return TemplateDeductionResult::Inconsistent; } Deduced[NTTP->getIndex()] = Result; if (!S.getLangOpts().CPlusPlus17) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (NTTP->isExpandedParameterPack()) // FIXME: We may still need to deduce parts of the type here! But we // don't have any way to find which slice of the type to use, and the // type stored on the NTTP itself is nonsense. Perhaps the type of an // expanded NTTP should be a pack expansion type? - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Get the type of the parameter for deduction. If it's a (dependent) array // or function type, we will not have decayed it yet, so do that now. @@ -446,7 +447,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( /// Deduce the value of the given non-type template parameter /// from the given integral constant. -static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( +static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, @@ -460,7 +461,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( /// Deduce the value of the given non-type template parameter /// from the given null pointer template argument type. -static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument( +static TemplateDeductionResult DeduceNullPtrTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, QualType NullPtrType, TemplateDeductionInfo &Info, @@ -481,9 +482,10 @@ static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument( /// from the given type- or value-dependent expression. /// /// \returns true if deduction succeeded, false otherwise. -static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( +static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, - const NonTypeTemplateParmDecl *NTTP, Expr *Value, TemplateDeductionInfo &Info, + const NonTypeTemplateParmDecl *NTTP, Expr *Value, + TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, DeducedTemplateArgument(Value), @@ -494,7 +496,7 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( /// from the given declaration. /// /// \returns true if deduction succeeded, false otherwise. -static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( +static TemplateDeductionResult DeduceNonTypeTemplateArgument( Sema &S, TemplateParameterList *TemplateParams, const NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T, TemplateDeductionInfo &Info, @@ -505,25 +507,23 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced); } -static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, - TemplateName Param, - TemplateName Arg, +static TemplateDeductionResult +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, + TemplateName Param, TemplateName Arg, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced) { TemplateDecl *ParamDecl = Param.getAsTemplateDecl(); if (!ParamDecl) { // The parameter type is dependent and is not a template template parameter, // so there is nothing that we can deduce. - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } if (TemplateTemplateParmDecl *TempParam = dyn_cast(ParamDecl)) { // If we're not deducing at this depth, there's nothing to deduce. if (TempParam->getDepth() != Info.getDeducedDepth()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg)); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, @@ -533,21 +533,21 @@ DeduceTemplateArguments(Sema &S, Info.Param = TempParam; Info.FirstArg = Deduced[TempParam->getIndex()]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return TemplateDeductionResult::Inconsistent; } Deduced[TempParam->getIndex()] = Result; - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } // Verify that the two template names are equivalent. if (S.Context.hasSameTemplateName(Param, Arg)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Mismatch of non-dependent template parameter to argument. Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } /// Deduce the template arguments by comparing the template parameter @@ -568,7 +568,7 @@ DeduceTemplateArguments(Sema &S, /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult +static TemplateDeductionResult DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, const QualType P, QualType A, TemplateDeductionInfo &Info, @@ -583,7 +583,7 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // If the parameter is an alias template, there is nothing to deduce. if (const auto *TD = TNP.getAsTemplateDecl(); TD && TD->isTypeAlias()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; ArrayRef PResolved = TP->template_arguments(); @@ -600,11 +600,12 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, // If the argument is an alias template, there is nothing to deduce. if (const auto *TD = TNA.getAsTemplateDecl(); TD && TD->isTypeAlias()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Perform template argument deduction for the template name. if (auto Result = - DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced)) + DeduceTemplateArguments(S, TemplateParams, TNP, TNA, Info, Deduced); + Result != TemplateDeductionResult::Success) return Result; // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be @@ -623,13 +624,14 @@ DeduceTemplateSpecArguments(Sema &S, TemplateParameterList *TemplateParams, if (!SA) { Info.FirstArg = TemplateArgument(P); Info.SecondArg = TemplateArgument(A); - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // Perform template argument deduction for the template name. if (auto Result = DeduceTemplateArguments( S, TemplateParams, TP->getTemplateName(), - TemplateName(SA->getSpecializedTemplate()), Info, Deduced)) + TemplateName(SA->getSpecializedTemplate()), Info, Deduced); + Result != TemplateDeductionResult::Success) return Result; // Perform template argument deduction for the template arguments. @@ -919,7 +921,7 @@ class PackDeductionScope { /// Finish template argument deduction for a set of argument packs, /// producing the argument packs and checking for consistency with prior /// deductions. - Sema::TemplateDeductionResult finish() { + TemplateDeductionResult finish() { // Build argument packs for each of the parameter packs expanded by this // pack expansion. for (auto &Pack : Packs) { @@ -996,7 +998,7 @@ class PackDeductionScope { Info.Param = makeTemplateParameter(Param); Info.FirstArg = OldPack; Info.SecondArg = NewPack; - return Sema::TDK_Inconsistent; + return TemplateDeductionResult::Inconsistent; } // If we have a pre-expanded pack and we didn't deduce enough elements @@ -1005,14 +1007,14 @@ class PackDeductionScope { if (*Expansions != PackElements) { Info.Param = makeTemplateParameter(Param); Info.FirstArg = Result; - return Sema::TDK_IncompletePack; + return TemplateDeductionResult::IncompletePack; } } *Loc = Result; } - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } private: @@ -1062,15 +1064,13 @@ class PackDeductionScope { /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, +static TemplateDeductionResult +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const QualType *Params, unsigned NumParams, const QualType *Args, unsigned NumArgs, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, - unsigned TDF, - bool PartialOrdering = false) { + unsigned TDF, bool PartialOrdering = false) { // C++0x [temp.deduct.type]p10: // Similarly, if P has a form that contains (T), then each parameter type // Pi of the respective parameter-type- list of P is compared with the @@ -1086,22 +1086,22 @@ DeduceTemplateArguments(Sema &S, // Make sure we have an argument. if (ArgIdx >= NumArgs) - return Sema::TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; if (isa(Args[ArgIdx])) { // C++0x [temp.deduct.type]p22: // If the original function parameter associated with A is a function // parameter pack and the function parameter associated with P is not // a function parameter pack, then template argument deduction fails. - return Sema::TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; } - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, - PartialOrdering, - /*DeducedFromArrayBound=*/false)) + if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Params[ParamIdx].getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, + /*DeducedFromArrayBound=*/false); + Result != TemplateDeductionResult::Success) return Result; ++ArgIdx; @@ -1123,11 +1123,11 @@ DeduceTemplateArguments(Sema &S, if (ParamIdx + 1 == NumParams || PackScope.hasFixedArity()) { for (; ArgIdx < NumArgs && PackScope.hasNextElement(); ++ArgIdx) { // Deduce template arguments from the pattern. - if (Sema::TemplateDeductionResult Result = - DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, Pattern.getUnqualifiedType(), - Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, - PartialOrdering, /*DeducedFromArrayBound=*/false)) + if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, Pattern.getUnqualifiedType(), + Args[ArgIdx].getUnqualifiedType(), Info, Deduced, TDF, + PartialOrdering, /*DeducedFromArrayBound=*/false); + Result != TemplateDeductionResult::Success) return Result; PackScope.nextPackElement(); @@ -1160,7 +1160,8 @@ DeduceTemplateArguments(Sema &S, // Build argument packs for each of the parameter packs expanded by this // pack expansion. - if (auto Result = PackScope.finish()) + if (auto Result = PackScope.finish(); + Result != TemplateDeductionResult::Success) return Result; } @@ -1172,13 +1173,13 @@ DeduceTemplateArguments(Sema &S, // Ai is ignored; if (PartialOrdering && ArgIdx + 1 == NumArgs && isa(Args[ArgIdx])) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Make sure we don't have any extra arguments. if (ArgIdx < NumArgs) - return Sema::TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Determine whether the parameter has qualifiers that the argument @@ -1286,7 +1287,7 @@ static CXXRecordDecl *getCanonicalRD(QualType T) { /// \returns the result of template argument deduction with the bases. "invalid" /// means no matches, "success" found a single item, and the /// "MiscellaneousDeductionFailure" result happens when the match is ambiguous. -static Sema::TemplateDeductionResult +static TemplateDeductionResult DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, TemplateParameterList *TemplateParams, QualType P, TemplateDeductionInfo &Info, @@ -1338,13 +1339,13 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, SmallVector DeducedCopy(Deduced.begin(), Deduced.end()); TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); - Sema::TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( + TemplateDeductionResult BaseResult = DeduceTemplateSpecArguments( S, TemplateParams, P, NextT, BaseInfo, DeducedCopy); // If this was a successful deduction, add it to the list of matches, // otherwise we need to continue searching its bases. const CXXRecordDecl *RD = ::getCanonicalRD(NextT); - if (BaseResult == Sema::TDK_Success) + if (BaseResult == TemplateDeductionResult::Success) Matches.insert({RD, DeducedCopy}); else AddBases(RD); @@ -1374,12 +1375,12 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, } if (Matches.empty()) - return Sema::TDK_Invalid; + return TemplateDeductionResult::Invalid; if (Matches.size() > 1) - return Sema::TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; std::swap(Matches.front().second, Deduced); - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Deduce the template arguments by comparing the parameter type and @@ -1406,7 +1407,7 @@ DeduceTemplateBases(Sema &S, const CXXRecordDecl *RD, /// \returns the result of template argument deduction so far. Note that a /// "success" result means that template argument deduction has not yet failed, /// but it may still fail, later, for other reasons. -static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( +static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Sema &S, TemplateParameterList *TemplateParams, QualType P, QualType A, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, unsigned TDF, @@ -1460,7 +1461,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( PQuals.withoutObjCLifetime() == AQuals.withoutObjCLifetime())) { Info.FirstArg = TemplateArgument(P); Info.SecondArg = TemplateArgument(A); - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } } Qualifiers DiscardedQuals; @@ -1514,7 +1515,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Just skip any attempts to deduce from a placeholder type or a parameter // at a different depth. if (A->isPlaceholderType() || Info.getDeducedDepth() != TTP->getDepth()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; unsigned Index = TTP->getIndex(); @@ -1534,13 +1535,13 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(P); Info.SecondArg = TemplateArgument(A); - return Sema::TDK_Underqualified; + return TemplateDeductionResult::Underqualified; } // Do not match a function type with a cv-qualified type. // http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1584 if (A->isFunctionType() && P.hasQualifiers()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; assert(TTP->getDepth() == Info.getDeducedDepth() && "saw template type parameter with wrong depth"); @@ -1568,7 +1569,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(P); Info.SecondArg = TemplateArgument(A); - return Sema::TDK_Underqualified; + return TemplateDeductionResult::Underqualified; } // Objective-C ARC: @@ -1588,11 +1589,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( Info.Param = cast(TemplateParams->getParam(Index)); Info.FirstArg = Deduced[Index]; Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; + return TemplateDeductionResult::Inconsistent; } Deduced[Index] = Result; - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } // Set up the template argument deduction information for a failure. @@ -1604,19 +1605,19 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // at, so we have to wait until all of the parameter packs in this // expansion have arguments. if (P->getAs()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Check the cv-qualifiers on the parameter and argument types. if (!(TDF & TDF_IgnoreQualifiers)) { if (TDF & TDF_ParamWithReferenceType) { if (hasInconsistentOrSupersetQualifiersOf(P, A)) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } else if (TDF & TDF_ArgWithReferenceType) { // C++ [temp.deduct.conv]p4: // If the original A is a reference type, A can be more cv-qualified // than the deduced A if (!A.getQualifiers().compatiblyIncludes(P.getQualifiers())) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Strip out all extra qualifiers from the argument to figure out the // type we're converting to, prior to the qualification conversion. @@ -1625,22 +1626,22 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( A = S.Context.getQualifiedType(A, P.getQualifiers()); } else if (!IsPossiblyOpaquelyQualifiedType(P)) { if (P.getCVRQualifiers() != A.getCVRQualifiers()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } } // If the parameter type is not dependent, there is nothing to deduce. if (!P->isDependentType()) { if (TDF & TDF_SkipNonDependent) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A) : S.Context.hasSameType(P, A)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (TDF & TDF_AllowCompatibleFunctionType && S.isSameOrCompatibleFunctionType(P, A)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (!(TDF & TDF_IgnoreQualifiers)) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Otherwise, when ignoring qualifiers, the types not having the same // unqualified type does not mean they do not match, so in this case we // must keep going and analyze with a non-dependent parameter type. @@ -1664,7 +1665,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // There's no corresponding wording for [temp.deduct.decl], but we treat // it the same to match other compilers. if (P->isDependentType()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; [[fallthrough]]; case Type::Builtin: case Type::VariableArray: @@ -1680,14 +1681,14 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( ((TDF & TDF_IgnoreQualifiers) ? S.Context.hasSameUnqualifiedType(P, A) : S.Context.hasSameType(P, A)) - ? Sema::TDK_Success - : Sema::TDK_NonDeducedMismatch; + ? TemplateDeductionResult::Success + : TemplateDeductionResult::NonDeducedMismatch; // _Complex T [placeholder extension] case Type::Complex: { const auto *CP = P->castAs(), *CA = A->getAs(); if (!CA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CP->getElementType(), CA->getElementType(), Info, Deduced, TDF); @@ -1697,7 +1698,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::Atomic: { const auto *PA = P->castAs(), *AA = A->getAs(); if (!AA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PA->getValueType(), AA->getValueType(), Info, Deduced, TDF); @@ -1711,7 +1712,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( } else if (const auto *PA = A->getAs()) { PointeeType = PA->getPointeeType(); } else { - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, P->castAs()->getPointeeType(), @@ -1724,7 +1725,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *RP = P->castAs(), *RA = A->getAs(); if (!RA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, @@ -1736,7 +1737,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *RP = P->castAs(), *RA = A->getAs(); if (!RA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, RP->getPointeeType(), RA->getPointeeType(), Info, @@ -1747,7 +1748,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::IncompleteArray: { const auto *IAA = S.Context.getAsIncompleteArrayType(A); if (!IAA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; const auto *IAP = S.Context.getAsIncompleteArrayType(P); assert(IAP && "Template parameter not of incomplete array type"); @@ -1763,7 +1764,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( *CAP = S.Context.getAsConstantArrayType(P); assert(CAP); if (!CAA || CAA->getSize() != CAP->getSize()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, CAP->getElementType(), CAA->getElementType(), Info, @@ -1774,21 +1775,22 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::DependentSizedArray: { const auto *AA = S.Context.getAsArrayType(A); if (!AA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Check the element type of the arrays const auto *DAP = S.Context.getAsDependentSizedArrayType(P); assert(DAP); if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, DAP->getElementType(), AA->getElementType(), - Info, Deduced, TDF & TDF_IgnoreQualifiers)) + Info, Deduced, TDF & TDF_IgnoreQualifiers); + Result != TemplateDeductionResult::Success) return Result; // Determine the array bound is something we can deduce. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, DAP->getSizeExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // We can perform template argument deduction for the given non-type // template parameter. @@ -1806,7 +1808,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, NTTP, DAA->getSizeExpr(), Info, Deduced); // Incomplete type does not match a dependently-sized array type - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // type(*)(T) @@ -1816,30 +1818,32 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *FPP = P->castAs(), *FPA = A->getAs(); if (!FPA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; if (FPP->getMethodQuals() != FPA->getMethodQuals() || FPP->getRefQualifier() != FPA->getRefQualifier() || FPP->isVariadic() != FPA->isVariadic()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Check return types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, FPP->getReturnType(), FPA->getReturnType(), Info, Deduced, 0, /*PartialOrdering=*/false, - /*DeducedFromArrayBound=*/false)) + /*DeducedFromArrayBound=*/false); + Result != TemplateDeductionResult::Success) return Result; // Check parameter types. if (auto Result = DeduceTemplateArguments( S, TemplateParams, FPP->param_type_begin(), FPP->getNumParams(), FPA->param_type_begin(), FPA->getNumParams(), Info, Deduced, - TDF & TDF_TopLevelParameterTypeList, PartialOrdering)) + TDF & TDF_TopLevelParameterTypeList, PartialOrdering); + Result != TemplateDeductionResult::Success) return Result; if (TDF & TDF_AllowCompatibleFunctionType) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // FIXME: Per core-2016/10/1019 (no corresponding core issue yet), permit // deducing through the noexcept-specifier if it's part of the canonical @@ -1877,7 +1881,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Careful about [temp.deduct.call] and [temp.deduct.conv], which allow // top-level differences in noexcept-specifications. - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } case Type::InjectedClassName: @@ -1901,7 +1905,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( auto Result = DeduceTemplateSpecArguments(S, TemplateParams, P, A, Info, Deduced); - if (Result == Sema::TDK_Success) + if (Result == TemplateDeductionResult::Success) return Result; // We cannot inspect base classes as part of deduction when the type @@ -1916,7 +1920,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Check bases according to C++14 [temp.deduct.call] p4b3: auto BaseResult = DeduceTemplateBases(S, getCanonicalRD(A), TemplateParams, P, Info, Deduced); - return BaseResult != Sema::TDK_Invalid ? BaseResult : Result; + return BaseResult != TemplateDeductionResult::Invalid ? BaseResult + : Result; } // T type::* @@ -1932,7 +1937,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *MPP = P->castAs(), *MPA = A->getAs(); if (!MPA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; QualType PPT = MPP->getPointeeType(); if (PPT->isFunctionType()) @@ -1945,7 +1950,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( unsigned SubTDF = TDF & TDF_IgnoreQualifiers; if (auto Result = DeduceTemplateArgumentsByTypeMatch( - S, TemplateParams, PPT, APT, Info, Deduced, SubTDF)) + S, TemplateParams, PPT, APT, Info, Deduced, SubTDF); + Result != TemplateDeductionResult::Success) return Result; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, QualType(MPP->getClass(), 0), @@ -1961,7 +1967,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *BPP = P->castAs(), *BPA = A->getAs(); if (!BPA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, BPP->getPointeeType(), BPA->getPointeeType(), Info, Deduced, 0); @@ -1976,7 +1982,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (const auto *VA = A->getAs()) { // Make sure that the vectors have the same number of elements. if (VP->getNumElements() != VA->getNumElements()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; ElementType = VA->getElementType(); } else if (const auto *VA = A->getAs()) { // We can't check the number of elements, since the argument has a @@ -1984,7 +1990,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // ordering. ElementType = VA->getElementType(); } else { - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // Perform deduction on the element types. return DeduceTemplateArgumentsByTypeMatch( @@ -1999,14 +2005,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = VA->getNumElements(); @@ -2022,20 +2029,21 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, VA->getSizeExpr(), Info, Deduced); } - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // (clang extension) @@ -2048,14 +2056,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = VA->getNumElements(); @@ -2071,20 +2080,21 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the element types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, VP->getElementType(), VA->getElementType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the vector size, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, VP->getSizeExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, VA->getSizeExpr(), Info, Deduced); } - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // (clang extension) @@ -2095,12 +2105,12 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *MP = P->castAs(), *MA = A->getAs(); if (!MA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Check that the dimensions are the same if (MP->getNumRows() != MA->getNumRows() || MP->getNumColumns() != MA->getNumColumns()) { - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } // Perform deduction on element types. return DeduceTemplateArgumentsByTypeMatch( @@ -2112,12 +2122,13 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( const auto *MP = P->castAs(); const auto *MA = A->getAs(); if (!MA) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; // Check the element type of the matrixes. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, MP->getElementType(), MA->getElementType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Try to deduce a matrix dimension. @@ -2132,26 +2143,26 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( std::optional ParamConst = ParamExpr->getIntegerConstantExpr(S.Context); if (!ParamConst) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; if (ACM) { if ((ACM->*GetArgDimension)() == *ParamConst) - return Sema::TDK_Success; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::Success; + return TemplateDeductionResult::NonDeducedMismatch; } Expr *ArgExpr = (ADM->*GetArgDimensionExpr)(); if (std::optional ArgConst = ArgExpr->getIntegerConstantExpr(S.Context)) if (*ArgConst == *ParamConst) - return Sema::TDK_Success; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::Success; + return TemplateDeductionResult::NonDeducedMismatch; } const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, ParamExpr); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (ACM) { llvm::APSInt ArgConst( @@ -2169,7 +2180,8 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (auto Result = DeduceMatrixArg(MP->getRowExpr(), MA, &ConstantMatrixType::getNumRows, - &DependentSizedMatrixType::getRowExpr)) + &DependentSizedMatrixType::getRowExpr); + Result != TemplateDeductionResult::Success) return Result; return DeduceMatrixArg(MP->getColumnExpr(), MA, @@ -2187,14 +2199,15 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the pointer type. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), ASA->getPointeeType(), - Info, Deduced, TDF)) + Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the address space, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; return DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, ASA->getAddrSpaceExpr(), Info, Deduced); @@ -2208,33 +2221,34 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( // Perform deduction on the pointer types. if (auto Result = DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, ASP->getPointeeType(), - S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF)) + S.Context.removeAddrSpaceQualType(A), Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Perform deduction on the address space, if we can. const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, ASP->getAddrSpaceExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgAddressSpace, S.Context.IntTy, true, Info, Deduced); } - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } case Type::DependentBitInt: { const auto *IP = P->castAs(); if (const auto *IA = A->getAs()) { if (IP->isUnsigned() != IA->isUnsigned()) - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; const NonTypeTemplateParmDecl *NTTP = getDeducedParameterFromExpr(Info, IP->getNumBitsExpr()); if (!NTTP) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = IA->getNumBits(); @@ -2246,11 +2260,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( if (const auto *IA = A->getAs()) { if (IP->isUnsigned() != IA->isUnsigned()) - return Sema::TDK_NonDeducedMismatch; - return Sema::TDK_Success; + return TemplateDeductionResult::NonDeducedMismatch; + return TemplateDeductionResult::Success; } - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } case Type::TypeOfExpr: @@ -2264,7 +2278,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( case Type::PackExpansion: case Type::Pipe: // No template argument deduction for these types - return Sema::TDK_Success; + return TemplateDeductionResult::Success; case Type::PackIndexing: { const PackIndexingType *PIT = P->getAs(); @@ -2272,14 +2286,14 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch( return DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, PIT->getSelectedType(), A, Info, Deduced, TDF); } - return Sema::TDK_IncompletePack; + return TemplateDeductionResult::IncompletePack; } } llvm_unreachable("Invalid Type Class!"); } -static Sema::TemplateDeductionResult +static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument &P, TemplateArgument A, TemplateDeductionInfo &Info, @@ -2300,7 +2314,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, S, TemplateParams, P.getAsType(), A.getAsType(), Info, Deduced, 0); Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Template: if (A.getKind() == TemplateArgument::Template) @@ -2308,7 +2322,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, A.getAsTemplate(), Info, Deduced); Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::TemplateExpansion: llvm_unreachable("caller should handle pack expansions"); @@ -2316,38 +2330,38 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, case TemplateArgument::Declaration: if (A.getKind() == TemplateArgument::Declaration && isSameDeclaration(P.getAsDecl(), A.getAsDecl())) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::NullPtr: if (A.getKind() == TemplateArgument::NullPtr && S.Context.hasSameType(P.getNullPtrType(), A.getNullPtrType())) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Integral: if (A.getKind() == TemplateArgument::Integral) { if (hasSameExtendedValue(P.getAsIntegral(), A.getAsIntegral())) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::StructuralValue: if (A.getKind() == TemplateArgument::StructuralValue && A.structurallyEquals(P)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; case TemplateArgument::Expression: if (const NonTypeTemplateParmDecl *NTTP = @@ -2376,13 +2390,13 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, case TemplateArgument::Pack: Info.FirstArg = P; Info.SecondArg = A; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } llvm_unreachable("Unknown template argument kind"); } // Can't deduce anything, but that's okay. - return Sema::TDK_Success; + return TemplateDeductionResult::Success; case TemplateArgument::Pack: llvm_unreachable("Argument packs should be expanded by the caller!"); } @@ -2433,7 +2447,7 @@ static bool hasPackExpansionBeforeEnd(ArrayRef Args) { return false; } -static Sema::TemplateDeductionResult +static TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ArrayRef Ps, ArrayRef As, @@ -2445,7 +2459,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // the last template argument, the entire template argument list is a // non-deduced context. if (hasPackExpansionBeforeEnd(Ps)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // C++0x [temp.deduct.type]p9: // If P has a form that contains or , then each argument Pi of the @@ -2460,18 +2474,19 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Check whether we have enough arguments. if (!hasTemplateArgumentForDeduction(As, ArgIdx)) return NumberOfArgumentsMustMatch - ? Sema::TDK_MiscellaneousDeductionFailure - : Sema::TDK_Success; + ? TemplateDeductionResult::MiscellaneousDeductionFailure + : TemplateDeductionResult::Success; // C++1z [temp.deduct.type]p9: // During partial ordering, if Ai was originally a pack expansion [and] // Pi is not a pack expansion, template argument deduction fails. if (As[ArgIdx].isPackExpansion()) - return Sema::TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; // Perform deduction for this Pi/Ai pair. if (auto Result = DeduceTemplateArguments(S, TemplateParams, P, - As[ArgIdx], Info, Deduced)) + As[ArgIdx], Info, Deduced); + Result != TemplateDeductionResult::Success) return Result; // Move to the next argument. @@ -2499,7 +2514,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, ++ArgIdx) { // Deduce template arguments from the pattern. if (auto Result = DeduceTemplateArguments(S, TemplateParams, Pattern, - As[ArgIdx], Info, Deduced)) + As[ArgIdx], Info, Deduced); + Result != TemplateDeductionResult::Success) return Result; PackScope.nextPackElement(); @@ -2507,11 +2523,12 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // Build argument packs for each of the parameter packs expanded by this // pack expansion. - if (auto Result = PackScope.finish()) + if (auto Result = PackScope.finish(); + Result != TemplateDeductionResult::Success) return Result; } - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Determine whether two template arguments are the same. @@ -2773,7 +2790,7 @@ static bool ConvertDeducedTemplateArgument( // ClassTemplatePartialSpecializationDecl sadly does not derive from // TemplateDecl. template -static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( +static TemplateDeductionResult ConvertDeducedTemplateArguments( Sema &S, TemplateDeclT *Template, bool IsDeduced, SmallVectorImpl &Deduced, TemplateDeductionInfo &Info, @@ -2792,7 +2809,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // FIXME: Where did the word "trailing" come from? if (Deduced[I].isNull() && Param->isTemplateParameterPack()) { if (auto Result = - PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish()) + PackDeductionScope(S, TemplateParams, Deduced, Info, I).finish(); + Result != TemplateDeductionResult::Success) return Result; } @@ -2829,7 +2847,7 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( Info.reset( TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } continue; @@ -2841,7 +2859,7 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( if (!TD) { assert(isa(Template) || isa(Template)); - return Sema::TDK_Incomplete; + return TemplateDeductionResult::Incomplete; } TemplateArgumentLoc DefArg; @@ -2871,8 +2889,8 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); if (PartialOverloading) break; - return HasDefaultArg ? Sema::TDK_SubstitutionFailure - : Sema::TDK_Incomplete; + return HasDefaultArg ? TemplateDeductionResult::SubstitutionFailure + : TemplateDeductionResult::Incomplete; } // Check whether we can actually use the default argument. @@ -2884,13 +2902,13 @@ static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( // FIXME: These template arguments are temporary. Free them! Info.reset(TemplateArgumentList::CreateCopy(S.Context, SugaredBuilder), TemplateArgumentList::CreateCopy(S.Context, CanonicalBuilder)); - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } // If we get here, we successfully used the default template argument. } - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } static DeclContext *getAsDeclContextOrEnclosing(Decl *D) { @@ -2926,7 +2944,7 @@ bool DeducedArgsNeedReplacement( } template -static Sema::TemplateDeductionResult +static TemplateDeductionResult CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, ArrayRef SugaredDeducedArgs, ArrayRef CanonicalDeducedArgs, @@ -2959,15 +2977,15 @@ CheckDeducedArgumentConstraints(Sema &S, TemplateDeclT *Template, Info.reset( TemplateArgumentList::CreateCopy(S.Context, SugaredDeducedArgs), TemplateArgumentList::CreateCopy(S.Context, CanonicalDeducedArgs)); - return Sema::TDK_ConstraintsNotSatisfied; + return TemplateDeductionResult::ConstraintsNotSatisfied; } - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Complete template argument deduction for a partial specialization. template static std::enable_if_t::value, - Sema::TemplateDeductionResult> + TemplateDeductionResult> FinishTemplateArgumentDeduction( Sema &S, T *Partial, bool IsPartialOrdering, ArrayRef TemplateArgs, @@ -2986,7 +3004,8 @@ FinishTemplateArgumentDeduction( SmallVector SugaredBuilder, CanonicalBuilder; if (auto Result = ConvertDeducedTemplateArguments( S, Partial, IsPartialOrdering, Deduced, Info, SugaredBuilder, - CanonicalBuilder)) + CanonicalBuilder); + Result != TemplateDeductionResult::Success) return Result; // Form the template argument list from the deduced template arguments. @@ -3023,7 +3042,7 @@ FinishTemplateArgumentDeduction( Partial->getTemplateParameters()->getParam(ParamIdx)); Info.Param = makeTemplateParameter(Param); Info.FirstArg = (*PartialTemplArgInfo)[ArgIdx].getArgument(); - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } bool ConstraintsNotSatisfied; @@ -3033,8 +3052,9 @@ FinishTemplateArgumentDeduction( Template, Partial->getLocation(), InstArgs, false, SugaredConvertedInstArgs, CanonicalConvertedInstArgs, /*UpdateArgsWithConversions=*/true, &ConstraintsNotSatisfied)) - return ConstraintsNotSatisfied ? Sema::TDK_ConstraintsNotSatisfied - : Sema::TDK_SubstitutionFailure; + return ConstraintsNotSatisfied + ? TemplateDeductionResult::ConstraintsNotSatisfied + : TemplateDeductionResult::SubstitutionFailure; TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { @@ -3044,24 +3064,25 @@ FinishTemplateArgumentDeduction( Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } } if (Trap.hasErrorOccurred()) - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; if (auto Result = CheckDeducedArgumentConstraints(S, Partial, SugaredBuilder, - CanonicalBuilder, Info)) + CanonicalBuilder, Info); + Result != TemplateDeductionResult::Success) return Result; - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Complete template argument deduction for a class or variable template, /// when partial ordering against a partial specialization. // FIXME: Factor out duplication with partial specialization version above. -static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( +static TemplateDeductionResult FinishTemplateArgumentDeduction( Sema &S, TemplateDecl *Template, bool PartialOrdering, ArrayRef TemplateArgs, SmallVectorImpl &Deduced, @@ -3081,7 +3102,8 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( S, Template, /*IsDeduced*/ PartialOrdering, Deduced, Info, SugaredBuilder, CanonicalBuilder, /*CurrentInstantiationScope=*/nullptr, - /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false)) + /*NumAlreadyConverted=*/0U, /*PartialOverloading=*/false); + Result != TemplateDeductionResult::Success) return Result; // Check that we produced the correct argument list. @@ -3093,29 +3115,30 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); Info.FirstArg = TemplateArgs[I]; Info.SecondArg = InstArg; - return Sema::TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } } if (Trap.hasErrorOccurred()) - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; if (auto Result = CheckDeducedArgumentConstraints(S, Template, SugaredBuilder, - CanonicalBuilder, Info)) + CanonicalBuilder, Info); + Result != TemplateDeductionResult::Success) return Result; - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. -Sema::TemplateDeductionResult +TemplateDeductionResult Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, ArrayRef TemplateArgs, TemplateDeductionInfo &Info) { if (Partial->isInvalidDecl()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; // C++ [temp.class.spec.match]p2: // A partial specialization matches a given actual template @@ -3137,17 +3160,18 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, if (TemplateDeductionResult Result = ::DeduceTemplateArguments( *this, Partial->getTemplateParameters(), Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false)) + /*NumberOfArgumentsMustMatch=*/false); + Result != TemplateDeductionResult::Success) return Result; SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs, Info); if (Inst.isInvalid()) - return TDK_InstantiationDepth; + return TemplateDeductionResult::InstantiationDepth; if (Trap.hasErrorOccurred()) - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { @@ -3161,12 +3185,12 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, /// Perform template argument deduction to determine whether /// the given template arguments match the given variable template /// partial specialization per C++ [temp.class.spec.match]. -Sema::TemplateDeductionResult +TemplateDeductionResult Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, ArrayRef TemplateArgs, TemplateDeductionInfo &Info) { if (Partial->isInvalidDecl()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; // C++ [temp.class.spec.match]p2: // A partial specialization matches a given actual template @@ -3188,17 +3212,18 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, if (TemplateDeductionResult Result = ::DeduceTemplateArguments( *this, Partial->getTemplateParameters(), Partial->getTemplateArgs().asArray(), TemplateArgs, Info, Deduced, - /*NumberOfArgumentsMustMatch=*/false)) + /*NumberOfArgumentsMustMatch=*/false); + Result != TemplateDeductionResult::Success) return Result; SmallVector DeducedArgs(Deduced.begin(), Deduced.end()); InstantiatingTemplate Inst(*this, Info.getLocation(), Partial, DeducedArgs, Info); if (Inst.isInvalid()) - return TDK_InstantiationDepth; + return TemplateDeductionResult::InstantiationDepth; if (Trap.hasErrorOccurred()) - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; TemplateDeductionResult Result; runWithSufficientStackSpace(Info.getLocation(), [&] { @@ -3251,9 +3276,9 @@ static bool isSimpleTemplateIdType(QualType T) { /// \param Info if substitution fails for any reason, this object will be /// populated with more information about the failure. /// -/// \returns TDK_Success if substitution was successful, or some failure -/// condition. -Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( +/// \returns TemplateDeductionResult::Success if substitution was successful, or +/// some failure condition. +TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo &ExplicitTemplateArgs, SmallVectorImpl &Deduced, @@ -3271,7 +3296,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( if (FunctionType) *FunctionType = Function->getType(); - return TDK_Success; + return TemplateDeductionResult::Success; } // Unevaluated SFINAE context. @@ -3294,7 +3319,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( *this, Info.getLocation(), FunctionTemplate, DeducedArgs, CodeSynthesisContext::ExplicitTemplateArgumentSubstitution, Info); if (Inst.isInvalid()) - return TDK_InstantiationDepth; + return TemplateDeductionResult::InstantiationDepth; if (CheckTemplateArgumentList(FunctionTemplate, SourceLocation(), ExplicitTemplateArgs, true, SugaredBuilder, @@ -3303,9 +3328,9 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( Trap.hasErrorOccurred()) { unsigned Index = SugaredBuilder.size(); if (Index >= TemplateParams->size()) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; Info.Param = makeTemplateParameter(TemplateParams->getParam(Index)); - return TDK_InvalidExplicitArguments; + return TemplateDeductionResult::InvalidExplicitArguments; } // Form the template argument list from the explicitly-specified @@ -3364,7 +3389,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( if (SubstParmTypes(Function->getLocation(), Function->parameters(), Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, /*params=*/nullptr, ExtParamInfos)) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } // Instantiate the return type. @@ -3390,13 +3415,13 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( SubstType(Proto->getReturnType(), MLTAL, Function->getTypeSpecStartLoc(), Function->getDeclName()); if (ResultType.isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; // CUDA: Kernel function must have 'void' return type. if (getLangOpts().CUDA) if (Function->hasAttr() && !ResultType->isVoidType()) { Diag(Function->getLocation(), diag::err_kern_type_not_void_return) << Function->getType() << Function->getSourceRange(); - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } } @@ -3406,7 +3431,7 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( SubstParmTypes(Function->getLocation(), Function->parameters(), Proto->getExtParameterInfosOrNull(), MLTAL, ParamTypes, /*params*/ nullptr, ExtParamInfos)) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; if (FunctionType) { auto EPI = Proto->getExtProtoInfo(); @@ -3426,14 +3451,14 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( /*Pattern=*/nullptr, /*ForConstraintInstantiation=*/false, /*SkipForSpecialization=*/true))) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; *FunctionType = BuildFunctionType(ResultType, ParamTypes, Function->getLocation(), Function->getDeclName(), EPI); if (FunctionType->isNull() || Trap.hasErrorOccurred()) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } // C++ [temp.arg.explicit]p2: @@ -3455,23 +3480,24 @@ Sema::TemplateDeductionResult Sema::SubstituteExplicitTemplateArguments( Deduced.push_back(Arg); } - return TDK_Success; + return TemplateDeductionResult::Success; } /// Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. -static Sema::TemplateDeductionResult +static TemplateDeductionResult CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, Sema::OriginalCallArg OriginalArg, QualType DeducedA) { ASTContext &Context = S.Context; - auto Failed = [&]() -> Sema::TemplateDeductionResult { + auto Failed = [&]() -> TemplateDeductionResult { Info.FirstArg = TemplateArgument(DeducedA); Info.SecondArg = TemplateArgument(OriginalArg.OriginalArgType); Info.CallArgIndex = OriginalArg.ArgIdx; - return OriginalArg.DecomposedParam ? Sema::TDK_DeducedMismatchNested - : Sema::TDK_DeducedMismatch; + return OriginalArg.DecomposedParam + ? TemplateDeductionResult::DeducedMismatchNested + : TemplateDeductionResult::DeducedMismatch; }; QualType A = OriginalArg.OriginalArgType; @@ -3479,7 +3505,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, // Check for type equality (top-level cv-qualifiers are ignored). if (Context.hasSameUnqualifiedType(A, DeducedA)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Strip off references on the argument types; they aren't needed for // the following checks. @@ -3503,7 +3529,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, // the deduced A can be F. QualType Tmp; if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; Qualifiers AQuals = A.getQualifiers(); Qualifiers DeducedAQuals = DeducedA.getQualifiers(); @@ -3544,7 +3570,7 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, (S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion) || S.IsFunctionConversion(A, DeducedA, ResultTy))) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. [...] @@ -3565,11 +3591,11 @@ CheckOriginalCallArgDeduction(Sema &S, TemplateDeductionInfo &Info, } if (Context.hasSameUnqualifiedType(A, DeducedA)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && S.IsDerivedFrom(Info.getLocation(), A, DeducedA)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; return Failed(); } @@ -3607,7 +3633,7 @@ static unsigned getPackIndexForParam(Sema &S, // if `Specialization` is a `CXXConstructorDecl` or `CXXConversionDecl`, // we'll try to instantiate and update its explicit specifier after constraint // checking. -static Sema::TemplateDeductionResult instantiateExplicitSpecifierDeferred( +static TemplateDeductionResult instantiateExplicitSpecifierDeferred( Sema &S, FunctionDecl *Specialization, const MultiLevelTemplateArgumentList &SubstArgs, TemplateDeductionInfo &Info, FunctionTemplateDecl *FunctionTemplate, @@ -3626,24 +3652,24 @@ static Sema::TemplateDeductionResult instantiateExplicitSpecifierDeferred( ExplicitSpecifier ES = GetExplicitSpecifier(Specialization); Expr *ExplicitExpr = ES.getExpr(); if (!ExplicitExpr) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (!ExplicitExpr->isValueDependent()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; Sema::InstantiatingTemplate Inst( S, Info.getLocation(), FunctionTemplate, DeducedArgs, Sema::CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); if (Inst.isInvalid()) - return Sema::TDK_InstantiationDepth; + return TemplateDeductionResult::InstantiationDepth; Sema::SFINAETrap Trap(S); const ExplicitSpecifier InstantiatedES = S.instantiateExplicitSpecifier(SubstArgs, ES); if (InstantiatedES.isInvalid() || Trap.hasErrorOccurred()) { Specialization->setInvalidDecl(true); - return Sema::TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } SetExplicitSpecifier(Specialization, InstantiatedES); - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Finish template argument deduction for a function template, @@ -3652,7 +3678,7 @@ static Sema::TemplateDeductionResult instantiateExplicitSpecifierDeferred( /// /// \param OriginalCallArgs If non-NULL, the original call arguments against /// which the deduced argument types should be compared. -Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( +TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( FunctionTemplateDecl *FunctionTemplate, SmallVectorImpl &Deduced, unsigned NumExplicitlySpecified, FunctionDecl *&Specialization, @@ -3671,7 +3697,7 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( *this, Info.getLocation(), FunctionTemplate, DeducedArgs, CodeSynthesisContext::DeducedTemplateArgumentSubstitution, Info); if (Inst.isInvalid()) - return TDK_InstantiationDepth; + return TemplateDeductionResult::InstantiationDepth; ContextRAII SavedContext(*this, FunctionTemplate->getTemplatedDecl()); @@ -3682,7 +3708,8 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( if (auto Result = ConvertDeducedTemplateArguments( *this, FunctionTemplate, /*IsDeduced*/ true, Deduced, Info, SugaredBuilder, CanonicalBuilder, CurrentInstantiationScope, - NumExplicitlySpecified, PartialOverloading)) + NumExplicitlySpecified, PartialOverloading); + Result != TemplateDeductionResult::Success) return Result; // C++ [temp.deduct.call]p10: [DR1391] @@ -3695,7 +3722,7 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // explicitly-specified template arguments, if the corresponding argument // A cannot be implicitly converted to P, deduction fails. if (CheckNonDependent()) - return TDK_NonDependentConversionFailure; + return TemplateDeductionResult::NonDependentConversionFailure; // Form the template argument list from the deduced template arguments. TemplateArgumentList *SugaredDeducedArgumentList = @@ -3732,7 +3759,7 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( Specialization = cast_or_null( SubstDecl(FD, Owner, SubstArgs)); if (!Specialization || Specialization->isInvalidDecl()) - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; assert(Specialization->getPrimaryTemplate()->getCanonicalDecl() == FunctionTemplate->getCanonicalDecl()); @@ -3749,7 +3776,7 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // failure. if (Trap.hasErrorOccurred()) { Specialization->setInvalidDecl(true); - return TDK_SubstitutionFailure; + return TemplateDeductionResult::SubstitutionFailure; } // C++2a [temp.deduct]p5 @@ -3766,12 +3793,12 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( if (CheckInstantiatedFunctionTemplateConstraints( Info.getLocation(), Specialization, CanonicalBuilder, Info.AssociatedConstraintsSatisfaction)) - return TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { Info.reset(Info.takeSugared(), TemplateArgumentList::CreateCopy(Context, CanonicalBuilder)); - return TDK_ConstraintsNotSatisfied; + return TemplateDeductionResult::ConstraintsNotSatisfied; } } @@ -3779,10 +3806,11 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // substitution of `FD` before. So, we try to instantiate it back if // `Specialization` is either a constructor or a conversion function. if (isa(Specialization)) { - if (TDK_Success != instantiateExplicitSpecifierDeferred( - *this, Specialization, SubstArgs, Info, - FunctionTemplate, DeducedArgs)) { - return TDK_SubstitutionFailure; + if (TemplateDeductionResult::Success != + instantiateExplicitSpecifierDeferred(*this, Specialization, SubstArgs, + Info, FunctionTemplate, + DeducedArgs)) { + return TemplateDeductionResult::SubstitutionFailure; } } @@ -3829,7 +3857,8 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( } if (auto TDK = - CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA); + TDK != TemplateDeductionResult::Success) return TDK; } } @@ -3846,7 +3875,7 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( .append(Info.diag_begin(), Info.diag_end()); } - return TDK_Success; + return TemplateDeductionResult::Success; } /// Gets the type of a function for template-argument-deducton @@ -3938,7 +3967,8 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, FunctionDecl *Specialization = nullptr; TemplateDeductionInfo Info(Ovl->getNameLoc()); if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs, - Specialization, Info)) + Specialization, + Info) != TemplateDeductionResult::Success) continue; D = Specialization; @@ -3968,10 +3998,10 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, SmallVector Deduced(TemplateParams->size()); TemplateDeductionInfo Info(Ovl->getNameLoc()); - Sema::TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, ParamType, - ArgType, Info, Deduced, TDF); - if (Result) continue; + TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, ParamType, ArgType, Info, Deduced, TDF); + if (Result != TemplateDeductionResult::Success) + continue; if (!Match.isNull()) return {}; Match = ArgType; @@ -4084,7 +4114,7 @@ static bool hasDeducibleTemplateParameters(Sema &S, FunctionTemplateDecl *FunctionTemplate, QualType T); -static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( +static TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex, QualType ParamType, QualType ArgType, Expr::Classification ArgClassification, Expr *Arg, @@ -4096,7 +4126,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( /// Attempt template argument deduction from an initializer list /// deemed to be an argument in a function call. -static Sema::TemplateDeductionResult DeduceFromInitializerList( +static TemplateDeductionResult DeduceFromInitializerList( Sema &S, TemplateParameterList *TemplateParams, QualType AdjustedParamType, InitListExpr *ILE, TemplateDeductionInfo &Info, SmallVectorImpl &Deduced, @@ -4111,7 +4141,7 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( // // We've already removed references and cv-qualifiers here. if (!ILE->getNumInits()) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; QualType ElTy; auto *ArrTy = S.Context.getAsArrayType(AdjustedParamType); @@ -4120,14 +4150,14 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( else if (!S.isStdInitializerList(AdjustedParamType, &ElTy)) { // Otherwise, an initializer list argument causes the parameter to be // considered a non-deduced context - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } // Resolving a core issue: a braced-init-list containing any designators is // a non-deduced context. for (Expr *E : ILE->inits()) if (isa(E)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // Deduction only needs to be done for dependent types. if (ElTy->isDependentType()) { @@ -4135,7 +4165,8 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( if (auto Result = DeduceTemplateArgumentsFromCallArgument( S, TemplateParams, 0, ElTy, E->getType(), E->Classify(S.getASTContext()), E, Info, Deduced, - OriginalCallArgs, true, ArgIdx, TDF)) + OriginalCallArgs, true, ArgIdx, TDF); + Result != TemplateDeductionResult::Success) return Result; } } @@ -4154,17 +4185,18 @@ static Sema::TemplateDeductionResult DeduceFromInitializerList( llvm::APInt Size(S.Context.getIntWidth(T), ILE->getNumInits()); if (auto Result = DeduceNonTypeTemplateArgument( S, TemplateParams, NTTP, llvm::APSInt(Size), T, - /*ArrayBound=*/true, Info, Deduced)) + /*ArrayBound=*/true, Info, Deduced); + Result != TemplateDeductionResult::Success) return Result; } } - return Sema::TDK_Success; + return TemplateDeductionResult::Success; } /// Perform template argument deduction per [temp.deduct.call] for a /// single parameter / argument pair. -static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( +static TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( Sema &S, TemplateParameterList *TemplateParams, unsigned FirstInnerIndex, QualType ParamType, QualType ArgType, Expr::Classification ArgClassification, Expr *Arg, @@ -4181,7 +4213,7 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( if (AdjustFunctionParmAndArgTypesForDeduction( S, TemplateParams, FirstInnerIndex, ParamType, ArgType, ArgClassification, Arg, TDF, FailedTSC)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; // If [...] the argument is a non-empty initializer list [...] if (InitListExpr *ILE = dyn_cast_if_present(Arg)) @@ -4221,11 +4253,11 @@ static Sema::TemplateDeductionResult DeduceTemplateArgumentsFromCallArgument( /// \param CheckNonDependent A callback to invoke to check conversions for /// non-dependent parameters, between deduction and substitution, per DR1391. /// If this returns true, substitution will be skipped and we return -/// TDK_NonDependentConversionFailure. The callback is passed the parameter -/// types (after substituting explicit template arguments). +/// TemplateDeductionResult::NonDependentConversionFailure. The callback is +/// passed the parameter types (after substituting explicit template arguments). /// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( +TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, ArrayRef Args, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, @@ -4233,7 +4265,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( QualType ObjectType, Expr::Classification ObjectClassification, llvm::function_ref)> CheckNonDependent) { if (FunctionTemplate->isInvalidDecl()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); unsigned NumParams = Function->getNumParams(); @@ -4252,14 +4284,14 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // of the call (call it A) as described below. if (Args.size() < Function->getMinRequiredExplicitArguments() && !PartialOverloading) - return TDK_TooFewArguments; + return TemplateDeductionResult::TooFewArguments; else if (TooManyArguments(NumParams, Args.size() + ExplicitObjectOffset, PartialOverloading)) { const auto *Proto = Function->getType()->castAs(); if (Proto->isTemplateVariadic()) /* Do nothing */; else if (!Proto->isVariadic()) - return TDK_TooManyArguments; + return TemplateDeductionResult::TooManyArguments; } // The types of the parameters from which we will perform template argument @@ -4277,7 +4309,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, nullptr, Info); }); - if (Result) + if (Result != TemplateDeductionResult::Success) return Result; NumExplicitlySpecified = Deduced.size(); @@ -4297,7 +4329,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // parameter that contains template-parameters that participate in // template argument deduction ... if (!hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - return Sema::TDK_Success; + return TemplateDeductionResult::Success; if (ExplicitObjetArgument) { // ... with the type of the corresponding argument @@ -4334,13 +4366,15 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( if (ParamIdx == 0 && HasExplicitObject) { if (auto Result = DeduceCallArgument(ParamType, 0, - /*ExplicitObjetArgument=*/true)) + /*ExplicitObjetArgument=*/true); + Result != TemplateDeductionResult::Success) return Result; continue; } if (auto Result = DeduceCallArgument(ParamType, ArgIdx++, - /*ExplicitObjetArgument=*/false)) + /*ExplicitObjetArgument=*/false); + Result != TemplateDeductionResult::Success) return Result; continue; @@ -4374,7 +4408,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( PackScope.nextPackElement(), ++ArgIdx) { ParamTypesForArgChecking.push_back(ParamPattern); if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx, - /*ExplicitObjetArgument=*/false)) + /*ExplicitObjetArgument=*/false); + Result != TemplateDeductionResult::Success) return Result; } } else { @@ -4414,7 +4449,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( for (; ArgIdx < PackArgEnd && ArgIdx < Args.size(); ArgIdx++) { ParamTypesForArgChecking.push_back(ParamPattern); if (auto Result = DeduceCallArgument(ParamPattern, ArgIdx, - /*ExplicitObjetArgument=*/false)) + /*ExplicitObjetArgument=*/false); + Result != TemplateDeductionResult::Success) return Result; PackScope.nextPackElement(); @@ -4424,7 +4460,8 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // Build argument packs for each of the parameter packs expanded by this // pack expansion. - if (auto Result = PackScope.finish()) + if (auto Result = PackScope.finish(); + Result != TemplateDeductionResult::Success) return Result; } @@ -4508,13 +4545,13 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, /// specialization based on its signature, per [temp.deduct.decl]. /// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( +TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplateDecl *FunctionTemplate, TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, FunctionDecl *&Specialization, TemplateDeductionInfo &Info, bool IsAddressOfFunction) { if (FunctionTemplate->isInvalidDecl()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; FunctionDecl *Function = FunctionTemplate->getTemplatedDecl(); TemplateParameterList *TemplateParams @@ -4533,7 +4570,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, &FunctionType, Info); }); - if (Result) + if (Result != TemplateDeductionResult::Success) return Result; NumExplicitlySpecified = Deduced.size(); @@ -4566,10 +4603,10 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( unsigned TDF = TDF_TopLevelParameterTypeList | TDF_AllowCompatibleFunctionType; // Deduce template arguments from the function type. - if (TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - FunctionType, ArgFunctionType, - Info, Deduced, TDF)) + if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( + *this, TemplateParams, FunctionType, ArgFunctionType, Info, Deduced, + TDF); + Result != TemplateDeductionResult::Success) return Result; } @@ -4579,7 +4616,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( NumExplicitlySpecified, Specialization, Info); }); - if (Result) + if (Result != TemplateDeductionResult::Success) return Result; // If the function has a deduced return type, deduce it now, so we can check @@ -4587,13 +4624,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( if (HasDeducedReturnType && IsAddressOfFunction && Specialization->getReturnType()->isUndeducedType() && DeduceReturnType(Specialization, Info.getLocation(), false)) - return TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; if (IsAddressOfFunction && getLangOpts().CPlusPlus20 && Specialization->isImmediateEscalating() && CheckIfFunctionSpecializationIsImmediate(Specialization, Info.getLocation())) - return TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; // If the function has a dependent exception specification, resolve it now, // so we can check that the exception specification matches. @@ -4602,7 +4639,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( if (getLangOpts().CPlusPlus17 && isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) && !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) - return TDK_MiscellaneousDeductionFailure; + return TemplateDeductionResult::MiscellaneousDeductionFailure; // Adjust the exception specification of the argument to match the // substituted and resolved type we just formed. (Calling convention and @@ -4632,22 +4669,22 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( : !Context.hasSameType(SpecializationType, ArgFunctionType)) { Info.FirstArg = TemplateArgument(SpecializationType); Info.SecondArg = TemplateArgument(ArgFunctionType); - return TDK_NonDeducedMismatch; + return TemplateDeductionResult::NonDeducedMismatch; } } - return TDK_Success; + return TemplateDeductionResult::Success; } /// Deduce template arguments for a templated conversion /// function (C++ [temp.deduct.conv]) and, if successful, produce a /// conversion function template specialization. -Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( +TemplateDeductionResult Sema::DeduceTemplateArguments( FunctionTemplateDecl *ConversionTemplate, QualType ObjectType, Expr::Classification ObjectClassification, QualType ToType, CXXConversionDecl *&Specialization, TemplateDeductionInfo &Info) { if (ConversionTemplate->isInvalidDecl()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; CXXConversionDecl *ConversionGeneric = cast(ConversionTemplate->getTemplatedDecl()); @@ -4749,13 +4786,14 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( *this, TemplateParams, getFirstInnerIndex(ConversionTemplate), ParamType, ObjectType, ObjectClassification, /*Arg=*/nullptr, Info, Deduced, OriginalCallArgs, - /*Decomposed*/ false, 0, /*TDF*/ 0)) + /*Decomposed*/ false, 0, /*TDF*/ 0); + Result != TemplateDeductionResult::Success) return Result; } - if (TemplateDeductionResult Result - = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, - P, A, Info, Deduced, TDF)) + if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch( + *this, TemplateParams, P, A, Info, Deduced, TDF); + Result != TemplateDeductionResult::Success) return Result; // Create an Instantiation Scope for finalizing the operator. @@ -4796,11 +4834,12 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( /// naming a function template specialization. /// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( - FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - FunctionDecl *&Specialization, TemplateDeductionInfo &Info, - bool IsAddressOfFunction) { +TemplateDeductionResult +Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, + TemplateDeductionInfo &Info, + bool IsAddressOfFunction) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, QualType(), Specialization, Info, IsAddressOfFunction); @@ -4962,14 +5001,14 @@ static bool CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, /// should be specified in the 'Info' parameter. /// \param IgnoreConstraints Set if we should not fail if the deduced type does /// not satisfy the type-constraint in the auto type. -Sema::TemplateDeductionResult +TemplateDeductionResult Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, TemplateDeductionInfo &Info, bool DependentDeduction, bool IgnoreConstraints, TemplateSpecCandidateSet *FailedTSC) { assert(DependentDeduction || Info.getDeducedDepth() == 0); if (Init->containsErrors()) - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; const AutoType *AT = Type.getType()->getContainedAutoType(); assert(AT); @@ -4977,7 +5016,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (Init->getType()->isNonOverloadPlaceholderType() || AT->isDecltypeAuto()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; Init = NonPlaceholder.get(); } @@ -4989,7 +5028,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, Init->containsUnexpandedParameterPack())) { Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return TDK_Success; + return TemplateDeductionResult::Success; } // Make sure that we treat 'char[]' equaly as 'char*' in C23 mode. @@ -4999,7 +5038,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, TypeLoc TL = TypeLoc(Init->getType(), Type.getOpaqueData()); Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(TL); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return TDK_Success; + return TemplateDeductionResult::Success; } // Emit a warning if 'auto*' is used in pedantic and in C23 mode. @@ -5011,7 +5050,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (!getLangOpts().CPlusPlus && InitList) { Diag(Init->getBeginLoc(), diag::err_auto_init_list_from_c) << (int)AT->getKeyword() << getLangOpts().C23; - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; } // Deduce type of TemplParam in Func(Init) @@ -5025,7 +5064,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, Result = SubstituteDeducedTypeTransform(*this, DependentResult).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); - return TDK_Success; + return TemplateDeductionResult::Success; } return TDK; }; @@ -5037,7 +5076,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (AT->isDecltypeAuto()) { if (InitList) { Diag(Init->getBeginLoc(), diag::err_decltype_auto_initializer_list); - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; } DeducedType = getDecltypeForExpr(Init); @@ -5060,24 +5099,25 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, // deduce against that. Such deduction only succeeds if removing // cv-qualifiers and references results in std::initializer_list. if (!Type.getType().getNonReferenceType()->getAs()) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; SourceRange DeducedFromInitRange; for (Expr *Init : InitList->inits()) { // Resolving a core issue: a braced-init-list containing any designators // is a non-deduced context. if (isa(Init)) - return TDK_Invalid; + return TemplateDeductionResult::Invalid; if (auto TDK = DeduceTemplateArgumentsFromCallArgument( *this, TemplateParamsSt.get(), 0, TemplArg, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, OriginalCallArgs, /*Decomposed=*/true, - /*ArgIdx=*/0, /*TDF=*/0)) { - if (TDK == TDK_Inconsistent) { + /*ArgIdx=*/0, /*TDF=*/0); + TDK != TemplateDeductionResult::Success) { + if (TDK == TemplateDeductionResult::Inconsistent) { Diag(Info.getLocation(), diag::err_auto_inconsistent_deduction) << Info.FirstArg << Info.SecondArg << DeducedFromInitRange << Init->getSourceRange(); - return DeductionFailed(TDK_AlreadyDiagnosed); + return DeductionFailed(TemplateDeductionResult::AlreadyDiagnosed); } return DeductionFailed(TDK); } @@ -5089,7 +5129,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, } else { if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { Diag(Loc, diag::err_auto_bitfield); - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; } QualType FuncParam = SubstituteDeducedTypeTransform(*this, TemplArg).Apply(Type); @@ -5099,19 +5139,20 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, *this, TemplateParamsSt.get(), 0, FuncParam, Init->getType(), Init->Classify(getASTContext()), Init, Info, Deduced, OriginalCallArgs, /*Decomposed=*/false, /*ArgIdx=*/0, /*TDF=*/0, - FailedTSC)) + FailedTSC); + TDK != TemplateDeductionResult::Success) return DeductionFailed(TDK); } // Could be null if somehow 'auto' appears in a non-deduced context. if (Deduced[0].getKind() != TemplateArgument::Type) - return DeductionFailed(TDK_Incomplete); + return DeductionFailed(TemplateDeductionResult::Incomplete); DeducedType = Deduced[0].getAsType(); if (InitList) { DeducedType = BuildStdInitializerList(DeducedType, Loc); if (DeducedType.isNull()) - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; } } @@ -5119,7 +5160,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (!Context.hasSameType(DeducedType, Result)) { Info.FirstArg = Result; Info.SecondArg = DeducedType; - return DeductionFailed(TDK_Inconsistent); + return DeductionFailed(TemplateDeductionResult::Inconsistent); } DeducedType = Context.getCommonSugaredType(Result, DeducedType); } @@ -5127,11 +5168,11 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, if (AT->isConstrained() && !IgnoreConstraints && CheckDeducedPlaceholderConstraints( *this, *AT, Type.getContainedAutoTypeLoc(), DeducedType)) - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return TDK_AlreadyDiagnosed; + return TemplateDeductionResult::AlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -5140,13 +5181,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *Init, QualType &Result, assert((bool)InitList == OriginalArg.DecomposedParam && "decomposed non-init-list in auto deduction?"); if (auto TDK = - CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA)) { + CheckOriginalCallArgDeduction(*this, Info, OriginalArg, DeducedA); + TDK != TemplateDeductionResult::Success) { Result = QualType(); return DeductionFailed(TDK); } } - return TDK_Success; + return TemplateDeductionResult::Success; } QualType Sema::SubstAutoType(QualType TypeWithAuto, @@ -5403,7 +5445,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, - TDF_None, /*PartialOrdering=*/true)) + TDF_None, /*PartialOrdering=*/true) != + TemplateDeductionResult::Success) return false; break; @@ -5415,17 +5458,17 @@ static bool isAtLeastAsSpecializedAs(Sema &S, if (DeduceTemplateArgumentsByTypeMatch( S, TemplateParams, Proto2->getReturnType(), Proto1->getReturnType(), Info, Deduced, TDF_None, - /*PartialOrdering=*/true)) + /*PartialOrdering=*/true) != TemplateDeductionResult::Success) return false; break; case TPOC_Other: // - In other contexts (14.6.6.2) the function template's function type // is used. - if (DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - FD2->getType(), FD1->getType(), - Info, Deduced, TDF_None, - /*PartialOrdering=*/true)) + if (DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, FD2->getType(), FD1->getType(), Info, Deduced, + TDF_None, + /*PartialOrdering=*/true) != TemplateDeductionResult::Success) return false; break; } @@ -5776,9 +5819,9 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, // Determine whether P1 is at least as specialized as P2. Deduced.resize(P2->getTemplateParameters()->size()); - if (DeduceTemplateArgumentsByTypeMatch(S, P2->getTemplateParameters(), - T2, T1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true)) + if (DeduceTemplateArgumentsByTypeMatch( + S, P2->getTemplateParameters(), T2, T1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true) != TemplateDeductionResult::Success) return false; SmallVector DeducedArgs(Deduced.begin(), @@ -5791,9 +5834,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, const auto *TST1 = cast(T1); bool AtLeastAsSpecialized; S.runWithSufficientStackSpace(Info.getLocation(), [&] { - AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( - S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), Deduced, - Info); + AtLeastAsSpecialized = + FinishTemplateArgumentDeduction( + S, P2, /*IsPartialOrdering=*/true, TST1->template_arguments(), + Deduced, Info) == TemplateDeductionResult::Success; }); return AtLeastAsSpecialized; } diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 6d59180bc446d2..371378485626c2 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -3693,9 +3693,9 @@ bool Sema::usesPartialOrExplicitSpecialization( ->getPartialSpecializations(PartialSpecs); for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { TemplateDeductionInfo Info(Loc); - if (!DeduceTemplateArguments(PartialSpecs[I], - ClassTemplateSpec->getTemplateArgs().asArray(), - Info)) + if (DeduceTemplateArguments(PartialSpecs[I], + ClassTemplateSpec->getTemplateArgs().asArray(), + Info) == TemplateDeductionResult::Success) return true; } @@ -3739,8 +3739,9 @@ getPatternForClassTemplateSpecialization( for (unsigned I = 0, N = PartialSpecs.size(); I != N; ++I) { ClassTemplatePartialSpecializationDecl *Partial = PartialSpecs[I]; TemplateDeductionInfo Info(FailedCandidates.getLocation()); - if (Sema::TemplateDeductionResult Result = S.DeduceTemplateArguments( - Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info)) { + if (TemplateDeductionResult Result = S.DeduceTemplateArguments( + Partial, ClassTemplateSpec->getTemplateArgs().asArray(), Info); + Result != TemplateDeductionResult::Success) { // Store the failed-deduction information for use in diagnostics, later. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate().set( diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp index c9217f7aac087e..eea14a66fa1818 100644 --- a/clang/lib/Serialization/ASTReader.cpp +++ b/clang/lib/Serialization/ASTReader.cpp @@ -987,9 +987,13 @@ ASTIdentifierLookupTraitBase::ReadKey(const unsigned char* d, unsigned n) { /// Whether the given identifier is "interesting". static bool isInterestingIdentifier(ASTReader &Reader, IdentifierInfo &II, bool IsModule) { + bool IsInteresting = + II.getInterestingIdentifierID() != + tok::InterestingIdentifierKind::not_interesting || + II.getBuiltinID() != Builtin::ID::NotBuiltin || + II.getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword; return II.hadMacroDefinition() || II.isPoisoned() || - (!IsModule && II.getObjCOrBuiltinID()) || - II.hasRevertedTokenIDToIdentifier() || + (!IsModule && IsInteresting) || II.hasRevertedTokenIDToIdentifier() || (!(IsModule && Reader.getPreprocessor().getLangOpts().CPlusPlus) && II.getFETokenInfo()); } diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp index 83ad4cb5b5602f..7966b3175ec9f1 100644 --- a/clang/lib/Serialization/ASTWriter.cpp +++ b/clang/lib/Serialization/ASTWriter.cpp @@ -3597,8 +3597,13 @@ class ASTIdentifierTableTrait { /// doesn't check whether the name has macros defined; use PublicMacroIterator /// to check that. bool isInterestingIdentifier(const IdentifierInfo *II, uint64_t MacroOffset) { - if (MacroOffset || II->isPoisoned() || - (!IsModule && II->getObjCOrBuiltinID()) || + II->getObjCOrBuiltinID(); + bool IsInteresting = + II->getInterestingIdentifierID() != + tok::InterestingIdentifierKind::not_interesting || + II->getBuiltinID() != Builtin::ID::NotBuiltin || + II->getObjCKeywordID() != tok::ObjCKeywordKind::objc_not_keyword; + if (MacroOffset || II->isPoisoned() || (!IsModule && IsInteresting) || II->hasRevertedTokenIDToIdentifier() || (NeedDecls && II->getFETokenInfo())) return true; diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c index afbc518e2af600..392b682afd602b 100644 --- a/clang/test/AST/Interp/c.c +++ b/clang/test/AST/Interp/c.c @@ -112,3 +112,15 @@ _Static_assert(sizeof(name2) == 0, ""); // expected-error {{failed}} \ #ifdef __SIZEOF_INT128__ void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // all-warning {{refers past the last possible element}} #endif + +extern float global_float; +struct XX { int a, *b; }; +struct XY { int before; struct XX xx, *xp; float* after; } xy[] = { + 0, 0, &xy[0].xx.a, &xy[0].xx, &global_float, + [1].xx = 0, &xy[1].xx.a, &xy[1].xx, &global_float, + 0, // all-note {{previous initialization is here}} + 0, // all-note {{previous initialization is here}} + [2].before = 0, // all-warning {{initializer overrides prior initialization of this subobject}} + 0, // all-warning {{initializer overrides prior initialization of this subobject}} + &xy[2].xx.a, &xy[2].xx, &global_float +}; diff --git a/clang/test/CXX/drs/dr124.cpp b/clang/test/CXX/drs/dr124.cpp new file mode 100644 index 00000000000000..c07beb11709c71 --- /dev/null +++ b/clang/test/CXX/drs/dr124.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -disable-llvm-passes -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK + +#if __cplusplus == 199711L +#define NOTHROW throw() +#else +#define NOTHROW noexcept(true) +#endif + +namespace dr124 { // dr124: 2.7 + +extern void full_expr_fence() NOTHROW; + +struct A { + A() NOTHROW {} + ~A() NOTHROW {} +}; + +struct B { + B(A = A()) NOTHROW {} + ~B() NOTHROW {} +}; + +void f() { + full_expr_fence(); + B b[2]; + full_expr_fence(); +} + +// CHECK-LABEL: define {{.*}} void @dr124::f()() +// CHECK: call void @dr124::full_expr_fence() +// CHECK: br label %arrayctor.loop +// CHECK-LABEL: arrayctor.loop: +// CHECK: call void @dr124::A::A() +// CHECK: call void @dr124::B::B(dr124::A) +// CHECK: call void @dr124::A::~A() +// CHECK: br {{.*}}, label %arrayctor.cont, label %arrayctor.loop +// CHECK-LABEL: arrayctor.cont: +// CHECK: call void @dr124::full_expr_fence() +// CHECK: br label %arraydestroy.body +// CHECK-LABEL: arraydestroy.body: +// CHECK: call void @dr124::B::~B() +// CHECK-LABEL: } + + +} // namespace dr124 diff --git a/clang/test/CXX/drs/dr185.cpp b/clang/test/CXX/drs/dr185.cpp new file mode 100644 index 00000000000000..aff00f1a8764ab --- /dev/null +++ b/clang/test/CXX/drs/dr185.cpp @@ -0,0 +1,30 @@ +// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK + +namespace dr185 { // dr185: 2.7 +struct A { + mutable int value; + explicit A(int i) : value(i) {} + void mutate(int i) const { value = i; } +}; + +int foo() { + A const& t = A(1); + A n(t); + t.mutate(2); + return n.value; +} + +// CHECK-LABEL: define {{.*}} i32 @dr185::foo() +// CHECK: call void @dr185::A::A(int)(ptr {{[^,]*}} %ref.tmp, {{.*}}) +// CHECK: store ptr %ref.tmp, ptr %t +// CHECK-NOT: %t = +// CHECK: [[DR185_T:%.+]] = load ptr, ptr %t +// CHECK: call void @llvm.memcpy.p0.p0.i64(ptr {{[^,]*}} %n, ptr {{[^,]*}} [[DR185_T]], {{.*}}) +// CHECK-LABEL: } +} // namespace dr185 diff --git a/clang/test/CXX/drs/dr193.cpp b/clang/test/CXX/drs/dr193.cpp new file mode 100644 index 00000000000000..c010dad50e4035 --- /dev/null +++ b/clang/test/CXX/drs/dr193.cpp @@ -0,0 +1,46 @@ +// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK + +#if __cplusplus == 199711L +#define NOTHROW throw() +#else +#define NOTHROW noexcept(true) +#endif + +namespace dr193 { // dr193: 2.7 +struct A { + ~A() NOTHROW {} +}; + +struct B { + ~B() NOTHROW {} +}; + +struct C { + ~C() NOTHROW {} +}; + +struct D : A { + B b; + ~D() NOTHROW { C c; } +}; + +void foo() { + D d; +} + +// skipping over D1 (complete object destructor) +// CHECK-LABEL: define {{.*}} void @dr193::D::~D(){{.*}} +// CHECK-LABEL: define {{.*}} void @dr193::D::~D(){{.*}} +// CHECK-NOT: call void @dr193::A::~A() +// CHECK-NOT: call void @dr193::B::~B() +// CHECK: call void @dr193::C::~C() +// CHECK: call void @dr193::B::~B() +// CHECK: call void @dr193::A::~A() +// CHECK-LABEL: } +} // namespace dr193 diff --git a/clang/test/CXX/drs/dr199.cpp b/clang/test/CXX/drs/dr199.cpp new file mode 100644 index 00000000000000..7517d79680c6fd --- /dev/null +++ b/clang/test/CXX/drs/dr199.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -std=c++98 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++11 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++14 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++17 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++20 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++23 %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK +// RUN: %clang_cc1 -std=c++2c %s -triple x86_64-linux-gnu -emit-llvm -o - -fexceptions -fcxx-exceptions -pedantic-errors | llvm-cxxfilt -n | FileCheck %s --check-prefixes CHECK + +#if __cplusplus == 199711L +#define NOTHROW throw() +#else +#define NOTHROW noexcept(true) +#endif + +namespace dr199 { // dr199: 2.8 +struct A { + ~A() NOTHROW {} +}; + +struct B { + ~B() NOTHROW {} +}; + +void foo() { + A(), B(); +} + +// CHECK-LABEL: define {{.*}} void @dr199::foo() +// CHECK-NOT: call void @dr199::A::~A() +// CHECK: call void @dr199::B::~B() +// CHECK: call void @dr199::A::~A() +// CHECK-LABEL: } +} // namespace dr199 diff --git a/clang/test/CXX/drs/dr1xx.cpp b/clang/test/CXX/drs/dr1xx.cpp index 1930de2f070a7a..d55033cef1b645 100644 --- a/clang/test/CXX/drs/dr1xx.cpp +++ b/clang/test/CXX/drs/dr1xx.cpp @@ -306,7 +306,7 @@ namespace dr122 { // dr122: yes } // dr123: na -// dr124: dup 201 +// dr124 is in dr124.cpp // dr125: yes struct dr125_A { struct dr125_B {}; }; // #dr125_B @@ -1169,7 +1169,7 @@ namespace dr184 { // dr184: yes void h() { A().g(); } } -// dr185 FIXME: add codegen test +// dr185 is in dr185.cpp namespace dr187 { // dr187: sup 481 const int Z = 1; @@ -1184,6 +1184,7 @@ namespace dr188 { // dr188: yes } // dr190 FIXME: add codegen test for tbaa +// or implement C++20 std::is_layout_compatible and test it this way int dr191_j; namespace dr191 { // dr191: yes @@ -1215,7 +1216,7 @@ namespace dr191 { // dr191: yes } } -// dr193 FIXME: add codegen test +// dr193 is in dr193.cpp namespace dr194 { // dr194: yes struct A { @@ -1290,4 +1291,4 @@ namespace dr198 { // dr198: yes }; } -// dr199 FIXME: add codegen test +// dr199 is in dr199.cpp diff --git a/clang/test/CodeGen/LoongArch/atomics.c b/clang/test/CodeGen/LoongArch/atomics.c index edc58d30db186d..bd51fea661be1f 100644 --- a/clang/test/CodeGen/LoongArch/atomics.c +++ b/clang/test/CodeGen/LoongArch/atomics.c @@ -11,10 +11,10 @@ void test_i8_atomics(_Atomic(int8_t) * a, int8_t b) { // LA32: load atomic i8, ptr %a seq_cst, align 1 // LA32: store atomic i8 %b, ptr %a seq_cst, align 1 - // LA32: atomicrmw add ptr %a, i8 %b seq_cst + // LA32: atomicrmw add ptr %a, i8 %b seq_cst, align 1 // LA64: load atomic i8, ptr %a seq_cst, align 1 // LA64: store atomic i8 %b, ptr %a seq_cst, align 1 - // LA64: atomicrmw add ptr %a, i8 %b seq_cst + // LA64: atomicrmw add ptr %a, i8 %b seq_cst, align 1 __c11_atomic_load(a, memory_order_seq_cst); __c11_atomic_store(a, b, memory_order_seq_cst); __c11_atomic_fetch_add(a, b, memory_order_seq_cst); @@ -23,22 +23,22 @@ void test_i8_atomics(_Atomic(int8_t) * a, int8_t b) { void test_i32_atomics(_Atomic(int32_t) * a, int32_t b) { // LA32: load atomic i32, ptr %a seq_cst, align 4 // LA32: store atomic i32 %b, ptr %a seq_cst, align 4 - // LA32: atomicrmw add ptr %a, i32 %b seq_cst + // LA32: atomicrmw add ptr %a, i32 %b seq_cst, align 4 // LA64: load atomic i32, ptr %a seq_cst, align 4 // LA64: store atomic i32 %b, ptr %a seq_cst, align 4 - // LA64: atomicrmw add ptr %a, i32 %b seq_cst + // LA64: atomicrmw add ptr %a, i32 %b seq_cst, align 4 __c11_atomic_load(a, memory_order_seq_cst); __c11_atomic_store(a, b, memory_order_seq_cst); __c11_atomic_fetch_add(a, b, memory_order_seq_cst); } void test_i64_atomics(_Atomic(int64_t) * a, int64_t b) { - // LA32: call i64 @__atomic_load_8 - // LA32: call void @__atomic_store_8 - // LA32: call i64 @__atomic_fetch_add_8 + // LA32: load atomic i64, ptr %a seq_cst, align 8 + // LA32: store atomic i64 %b, ptr %a seq_cst, align 8 + // LA32: atomicrmw add ptr %a, i64 %b seq_cst, align 8 // LA64: load atomic i64, ptr %a seq_cst, align 8 // LA64: store atomic i64 %b, ptr %a seq_cst, align 8 - // LA64: atomicrmw add ptr %a, i64 %b seq_cst + // LA64: atomicrmw add ptr %a, i64 %b seq_cst, align 8 __c11_atomic_load(a, memory_order_seq_cst); __c11_atomic_store(a, b, memory_order_seq_cst); __c11_atomic_fetch_add(a, b, memory_order_seq_cst); diff --git a/clang/test/CodeGen/PowerPC/quadword-atomics.c b/clang/test/CodeGen/PowerPC/quadword-atomics.c index bff03b25d27ee9..dc04423060a03b 100644 --- a/clang/test/CodeGen/PowerPC/quadword-atomics.c +++ b/clang/test/CodeGen/PowerPC/quadword-atomics.c @@ -1,14 +1,18 @@ // RUN: %clang_cc1 -Werror -Wno-atomic-alignment -triple powerpc64le-linux-gnu \ -// RUN: -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64-QUADWORD-ATOMICS +// RUN: -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s \ +// RUN: --check-prefixes=PPC64,PPC64-QUADWORD-ATOMICS // RUN: %clang_cc1 -Werror -Wno-atomic-alignment -triple powerpc64le-linux-gnu \ -// RUN: -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64 +// RUN: -emit-llvm -o - %s | FileCheck %s \ +// RUN: --check-prefixes=PPC64,PPC64-NO-QUADWORD-ATOMICS // RUN: %clang_cc1 -Werror -Wno-atomic-alignment -triple powerpc64-unknown-aix \ -// RUN: -target-cpu pwr7 -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64 +// RUN: -target-cpu pwr7 -emit-llvm -o - %s | FileCheck %s \ +// RUN: --check-prefixes=PPC64,PPC64-NO-QUADWORD-ATOMICS // RUN: %clang_cc1 -Werror -Wno-atomic-alignment -triple powerpc64-unknown-aix \ -// RUN: -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s --check-prefix=PPC64 +// RUN: -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s \ +// RUN: --check-prefixes=PPC64,PPC64-NO-QUADWORD-ATOMICS // RUN: %clang_cc1 -Werror -Wno-atomic-alignment -triple powerpc64-unknown-aix \ -// RUN: -mabi=quadword-atomics -target-cpu pwr8 -emit-llvm -o - %s | FileCheck %s \ -// RUN: --check-prefix=PPC64-QUADWORD-ATOMICS +// RUN: -mabi=quadword-atomics -target-cpu pwr8 -emit-llvm -o - %s | \ +// RUN: FileCheck %s --check-prefixes=PPC64,PPC64-QUADWORD-ATOMICS typedef struct { @@ -19,66 +23,48 @@ typedef _Atomic(Q) AtomicQ; typedef __int128_t int128_t; -// PPC64-QUADWORD-ATOMICS-LABEL: @test_load( -// PPC64-QUADWORD-ATOMICS: [[TMP3:%.*]] = load atomic i128, ptr [[TMP1:%.*]] acquire, align 16 -// // PPC64-LABEL: @test_load( -// PPC64: call void @__atomic_load(i64 noundef 16, ptr noundef [[TMP3:%.*]], ptr noundef [[TMP4:%.*]], i32 noundef signext 2) +// PPC64: [[TMP3:%.*]] = load atomic i128, ptr [[TMP1:%.*]] acquire, align 16 // Q test_load(AtomicQ *ptr) { // expected-no-diagnostics return __c11_atomic_load(ptr, __ATOMIC_ACQUIRE); } -// PPC64-QUADWORD-ATOMICS-LABEL: @test_store( -// PPC64-QUADWORD-ATOMICS: store atomic i128 [[TMP6:%.*]], ptr [[TMP4:%.*]] release, align 16 -// // PPC64-LABEL: @test_store( -// PPC64: call void @__atomic_store(i64 noundef 16, ptr noundef [[TMP6:%.*]], ptr noundef [[TMP7:%.*]], i32 noundef signext 3) +// PPC64: store atomic i128 [[TMP6:%.*]], ptr [[TMP4:%.*]] release, align 16 // void test_store(Q val, AtomicQ *ptr) { // expected-no-diagnostics __c11_atomic_store(ptr, val, __ATOMIC_RELEASE); } -// PPC64-QUADWORD-ATOMICS-LABEL: @test_add( -// PPC64-QUADWORD-ATOMICS: [[TMP3:%.*]] = atomicrmw add ptr [[TMP0:%.*]], i128 [[TMP2:%.*]] monotonic, align 16 -// // PPC64-LABEL: @test_add( -// PPC64: [[CALL:%.*]] = call i128 @__atomic_fetch_add_16(ptr noundef [[TMP2:%.*]], i128 noundef [[TMP3:%.*]], i32 noundef signext 0) +// PPC64: [[ATOMICRMW:%.*]] = atomicrmw add ptr [[TMP0:%.*]], i128 [[TMP2:%.*]] monotonic, align 16 // void test_add(_Atomic(int128_t) *ptr, int128_t x) { // expected-no-diagnostics __c11_atomic_fetch_add(ptr, x, __ATOMIC_RELAXED); } -// PPC64-QUADWORD-ATOMICS-LABEL: @test_xchg( -// PPC64-QUADWORD-ATOMICS: [[TMP8:%.*]] = atomicrmw xchg ptr [[TMP4:%.*]], i128 [[TMP7:%.*]] seq_cst, align 16 -// // PPC64-LABEL: @test_xchg( -// PPC64: call void @__atomic_exchange(i64 noundef 16, ptr noundef [[TMP7:%.*]], ptr noundef [[TMP8:%.*]], ptr noundef [[TMP9:%.*]], i32 noundef signext 5) +// PPC64: [[TMP8:%.*]] = atomicrmw xchg ptr [[TMP4:%.*]], i128 [[TMP7:%.*]] seq_cst, align 16 // Q test_xchg(AtomicQ *ptr, Q new) { // expected-no-diagnostics return __c11_atomic_exchange(ptr, new, __ATOMIC_SEQ_CST); } -// PPC64-QUADWORD-ATOMICS-LABEL: @test_cmpxchg( -// PPC64-QUADWORD-ATOMICS: [[TMP10:%.*]] = cmpxchg ptr [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 -// // PPC64-LABEL: @test_cmpxchg( -// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef [[TMP8:%.*]], ptr noundef [[TMP9:%.*]], ptr noundef [[TMP10:%.*]], i32 noundef signext 5, i32 noundef signext 0) +// PPC64: [[TMP10:%.*]] = cmpxchg ptr [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 // int test_cmpxchg(AtomicQ *ptr, Q *cmp, Q new) { // expected-no-diagnostics return __c11_atomic_compare_exchange_strong(ptr, cmp, new, __ATOMIC_SEQ_CST, __ATOMIC_RELAXED); } -// PPC64-QUADWORD-ATOMICS-LABEL: @test_cmpxchg_weak( -// PPC64-QUADWORD-ATOMICS: [[TMP10:%.*]] = cmpxchg weak ptr [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 -// // PPC64-LABEL: @test_cmpxchg_weak( -// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef [[TMP8:%.*]], ptr noundef [[TMP9:%.*]], ptr noundef [[TMP10:%.*]], i32 noundef signext 5, i32 noundef signext 0) +// PPC64: [[TMP10:%.*]] = cmpxchg weak ptr [[TMP5:%.*]], i128 [[TMP8:%.*]], i128 [[TMP9:%.*]] seq_cst monotonic, align 16 // int test_cmpxchg_weak(AtomicQ *ptr, Q *cmp, Q new) { // expected-no-diagnostics @@ -88,8 +74,8 @@ int test_cmpxchg_weak(AtomicQ *ptr, Q *cmp, Q new) { // PPC64-QUADWORD-ATOMICS-LABEL: @is_lock_free( // PPC64-QUADWORD-ATOMICS: ret i32 1 // -// PPC64-LABEL: @is_lock_free( -// PPC64: [[CALL:%.*]] = call zeroext i1 @__atomic_is_lock_free(i64 noundef 16, ptr noundef null) +// PPC64-NO-QUADWORD-ATOMICS-LABEL: @is_lock_free( +// PPC64-NO-QUADWORD-ATOMICS: [[CALL:%.*]] = call zeroext i1 @__atomic_is_lock_free(i64 noundef 16, ptr noundef null) // int is_lock_free() { AtomicQ q; diff --git a/clang/test/CodeGen/RISCV/riscv-atomics.c b/clang/test/CodeGen/RISCV/riscv-atomics.c index f629ad7d72ea82..437cb949bbb0fe 100644 --- a/clang/test/CodeGen/RISCV/riscv-atomics.c +++ b/clang/test/CodeGen/RISCV/riscv-atomics.c @@ -1,68 +1,34 @@ // RUN: %clang_cc1 -triple riscv32 -O1 -emit-llvm %s -o - \ -// RUN: | FileCheck %s -check-prefix=RV32I +// RUN: -verify=no-atomics // RUN: %clang_cc1 -triple riscv32 -target-feature +a -O1 -emit-llvm %s -o - \ -// RUN: | FileCheck %s -check-prefix=RV32IA +// RUN: -verify=small-atomics // RUN: %clang_cc1 -triple riscv64 -O1 -emit-llvm %s -o - \ -// RUN: | FileCheck %s -check-prefix=RV64I +// RUN: -verify=no-atomics // RUN: %clang_cc1 -triple riscv64 -target-feature +a -O1 -emit-llvm %s -o - \ -// RUN: | FileCheck %s -check-prefix=RV64IA +// RUN: -verify=all-atomics -// This test demonstrates that MaxAtomicInlineWidth is set appropriately when -// the atomics instruction set extension is enabled. +// all-atomics-no-diagnostics #include #include void test_i8_atomics(_Atomic(int8_t) * a, int8_t b) { - // RV32I: call zeroext i8 @__atomic_load_1 - // RV32I: call void @__atomic_store_1 - // RV32I: call zeroext i8 @__atomic_fetch_add_1 - // RV32IA: load atomic i8, ptr %a seq_cst, align 1 - // RV32IA: store atomic i8 %b, ptr %a seq_cst, align 1 - // RV32IA: atomicrmw add ptr %a, i8 %b seq_cst, align 1 - // RV64I: call zeroext i8 @__atomic_load_1 - // RV64I: call void @__atomic_store_1 - // RV64I: call zeroext i8 @__atomic_fetch_add_1 - // RV64IA: load atomic i8, ptr %a seq_cst, align 1 - // RV64IA: store atomic i8 %b, ptr %a seq_cst, align 1 - // RV64IA: atomicrmw add ptr %a, i8 %b seq_cst, align 1 - __c11_atomic_load(a, memory_order_seq_cst); - __c11_atomic_store(a, b, memory_order_seq_cst); - __c11_atomic_fetch_add(a, b, memory_order_seq_cst); + __c11_atomic_load(a, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (1 bytes) exceeds the max lock-free size (0 bytes)}} + __c11_atomic_store(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (1 bytes) exceeds the max lock-free size (0 bytes)}} + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (1 bytes) exceeds the max lock-free size (0 bytes)}} } void test_i32_atomics(_Atomic(int32_t) * a, int32_t b) { - // RV32I: call i32 @__atomic_load_4 - // RV32I: call void @__atomic_store_4 - // RV32I: call i32 @__atomic_fetch_add_4 - // RV32IA: load atomic i32, ptr %a seq_cst, align 4 - // RV32IA: store atomic i32 %b, ptr %a seq_cst, align 4 - // RV32IA: atomicrmw add ptr %a, i32 %b seq_cst, align 4 - // RV64I: call signext i32 @__atomic_load_4 - // RV64I: call void @__atomic_store_4 - // RV64I: call signext i32 @__atomic_fetch_add_4 - // RV64IA: load atomic i32, ptr %a seq_cst, align 4 - // RV64IA: store atomic i32 %b, ptr %a seq_cst, align 4 - // RV64IA: atomicrmw add ptr %a, i32 %b seq_cst, align 4 - __c11_atomic_load(a, memory_order_seq_cst); - __c11_atomic_store(a, b, memory_order_seq_cst); - __c11_atomic_fetch_add(a, b, memory_order_seq_cst); + __c11_atomic_load(a, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0 bytes)}} + __c11_atomic_store(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0 bytes)}} + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (4 bytes) exceeds the max lock-free size (0 bytes)}} } void test_i64_atomics(_Atomic(int64_t) * a, int64_t b) { - // RV32I: call i64 @__atomic_load_8 - // RV32I: call void @__atomic_store_8 - // RV32I: call i64 @__atomic_fetch_add_8 - // RV32IA: call i64 @__atomic_load_8 - // RV32IA: call void @__atomic_store_8 - // RV32IA: call i64 @__atomic_fetch_add_8 - // RV64I: call i64 @__atomic_load_8 - // RV64I: call void @__atomic_store_8 - // RV64I: call i64 @__atomic_fetch_add_8 - // RV64IA: load atomic i64, ptr %a seq_cst, align 8 - // RV64IA: store atomic i64 %b, ptr %a seq_cst, align 8 - // RV64IA: atomicrmw add ptr %a, i64 %b seq_cst, align 8 - __c11_atomic_load(a, memory_order_seq_cst); - __c11_atomic_store(a, b, memory_order_seq_cst); - __c11_atomic_fetch_add(a, b, memory_order_seq_cst); + __c11_atomic_load(a, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (0 bytes)}} + // small-atomics-warning@28 {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (4 bytes)}} + __c11_atomic_store(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (0 bytes)}} + // small-atomics-warning@30 {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (4 bytes)}} + __c11_atomic_fetch_add(a, b, memory_order_seq_cst); // no-atomics-warning {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (0 bytes)}} + // small-atomics-warning@32 {{large atomic operation may incur significant performance penalty; the access size (8 bytes) exceeds the max lock-free size (4 bytes)}} } diff --git a/clang/test/CodeGen/SystemZ/gnu-atomic-builtins-i128-8Al.c b/clang/test/CodeGen/SystemZ/gnu-atomic-builtins-i128-8Al.c index 4f6dcbc2c01ec8..8759df7b19c638 100644 --- a/clang/test/CodeGen/SystemZ/gnu-atomic-builtins-i128-8Al.c +++ b/clang/test/CodeGen/SystemZ/gnu-atomic-builtins-i128-8Al.c @@ -20,7 +20,8 @@ __int128 Des; // CHECK-LABEL: @f1( // CHECK-NEXT: entry: -// CHECK-NEXT: tail call void @__atomic_load(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull [[AGG_RESULT:%.*]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP0:%.*]] = load atomic i128, ptr @Ptr seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP0]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2:![0-9]+]] // CHECK-NEXT: ret void // __int128 f1() { @@ -29,8 +30,8 @@ __int128 f1() { // CHECK-LABEL: @f2( // CHECK-NEXT: entry: -// CHECK-NEXT: tail call void @__atomic_load(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull @Ret, i32 noundef signext 5) -// CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Ret, align 8, !tbaa [[TBAA2:![0-9]+]] +// CHECK-NEXT: [[TMP0:%.*]] = load atomic i128, ptr @Ptr seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP0]], ptr @Ret, align 8 // CHECK-NEXT: store i128 [[TMP0]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // @@ -41,10 +42,8 @@ __int128 f2() { // CHECK-LABEL: @f3( // CHECK-NEXT: entry: -// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[DOTATOMICTMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_store(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull [[DOTATOMICTMP]], i32 noundef signext 5) +// CHECK-NEXT: store atomic i128 [[TMP0]], ptr @Ptr seq_cst, align 8 // CHECK-NEXT: ret void // void f3() { @@ -53,7 +52,8 @@ void f3() { // CHECK-LABEL: @f4( // CHECK-NEXT: entry: -// CHECK-NEXT: tail call void @__atomic_store(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull @Val, i32 noundef signext 5) +// CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8 +// CHECK-NEXT: store atomic i128 [[TMP0]], ptr @Ptr seq_cst, align 8 // CHECK-NEXT: ret void // void f4() { @@ -62,10 +62,9 @@ void f4() { // CHECK-LABEL: @f5( // CHECK-NEXT: entry: -// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[DOTATOMICTMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_exchange(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull [[DOTATOMICTMP]], ptr noundef nonnull [[AGG_RESULT:%.*]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f5() { @@ -74,9 +73,10 @@ __int128 f5() { // CHECK-LABEL: @f6( // CHECK-NEXT: entry: -// CHECK-NEXT: tail call void @__atomic_exchange(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull @Val, ptr noundef nonnull @Ret, i32 noundef signext 5) -// CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Ret, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr @Ret, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f6() { @@ -86,11 +86,17 @@ __int128 f6() { // CHECK-LABEL: @f7( // CHECK-NEXT: entry: -// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Des, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[DOTATOMICTMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull @Exp, ptr noundef nonnull [[DOTATOMICTMP]], i32 noundef signext 5, i32 noundef signext 5) -// CHECK-NEXT: ret i1 [[CALL]] +// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr @Exp, align 8 +// CHECK-NEXT: [[TMP2:%.*]] = cmpxchg ptr @Ptr, i128 [[TMP1]], i128 [[TMP0]] seq_cst seq_cst, align 8 +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i128, i1 } [[TMP2]], 1 +// CHECK-NEXT: br i1 [[TMP3]], label [[CMPXCHG_CONTINUE:%.*]], label [[CMPXCHG_STORE_EXPECTED:%.*]] +// CHECK: cmpxchg.store_expected: +// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i128, i1 } [[TMP2]], 0 +// CHECK-NEXT: store i128 [[TMP4]], ptr @Exp, align 8 +// CHECK-NEXT: br label [[CMPXCHG_CONTINUE]] +// CHECK: cmpxchg.continue: +// CHECK-NEXT: ret i1 [[TMP3]] // _Bool f7() { return __atomic_compare_exchange_n(&Ptr, &Exp, Des, 0, @@ -99,8 +105,17 @@ _Bool f7() { // CHECK-LABEL: @f8( // CHECK-NEXT: entry: -// CHECK-NEXT: [[CALL:%.*]] = tail call zeroext i1 @__atomic_compare_exchange(i64 noundef 16, ptr noundef nonnull @Ptr, ptr noundef nonnull @Exp, ptr noundef nonnull @Des, i32 noundef signext 5, i32 noundef signext 5) -// CHECK-NEXT: ret i1 [[CALL]] +// CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Exp, align 8 +// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr @Des, align 8 +// CHECK-NEXT: [[TMP2:%.*]] = cmpxchg ptr @Ptr, i128 [[TMP0]], i128 [[TMP1]] seq_cst seq_cst, align 8 +// CHECK-NEXT: [[TMP3:%.*]] = extractvalue { i128, i1 } [[TMP2]], 1 +// CHECK-NEXT: br i1 [[TMP3]], label [[CMPXCHG_CONTINUE:%.*]], label [[CMPXCHG_STORE_EXPECTED:%.*]] +// CHECK: cmpxchg.store_expected: +// CHECK-NEXT: [[TMP4:%.*]] = extractvalue { i128, i1 } [[TMP2]], 0 +// CHECK-NEXT: store i128 [[TMP4]], ptr @Exp, align 8 +// CHECK-NEXT: br label [[CMPXCHG_CONTINUE]] +// CHECK: cmpxchg.continue: +// CHECK-NEXT: ret i1 [[TMP3]] // _Bool f8() { return __atomic_compare_exchange(&Ptr, &Exp, &Des, 0, @@ -109,12 +124,8 @@ _Bool f8() { // CHECK-LABEL: @f9( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_add_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = add i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: store i128 [[TMP2]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void @@ -125,12 +136,8 @@ __int128 f9() { // CHECK-LABEL: @f10( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_sub_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw sub ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = sub i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: store i128 [[TMP2]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void @@ -141,12 +148,8 @@ __int128 f10() { // CHECK-LABEL: @f11( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_and_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw and ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = and i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: store i128 [[TMP2]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void @@ -157,12 +160,8 @@ __int128 f11() { // CHECK-LABEL: @f12( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_xor_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xor ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = xor i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: store i128 [[TMP2]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void @@ -173,12 +172,8 @@ __int128 f12() { // CHECK-LABEL: @f13( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_or_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw or ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = or i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: store i128 [[TMP2]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void @@ -189,12 +184,8 @@ __int128 f13() { // CHECK-LABEL: @f14( // CHECK-NEXT: entry: -// CHECK-NEXT: [[TMP:%.*]] = alloca i128, align 8 -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_nand_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[TMP]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) -// CHECK-NEXT: [[TMP1:%.*]] = load i128, ptr [[TMP]], align 8, !tbaa [[TBAA2]] +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw nand ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 // CHECK-NEXT: [[TMP2:%.*]] = and i128 [[TMP1]], [[TMP0]] // CHECK-NEXT: [[TMP3:%.*]] = xor i128 [[TMP2]], -1 // CHECK-NEXT: store i128 [[TMP3]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] @@ -206,10 +197,9 @@ __int128 f14() { // CHECK-LABEL: @f15( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_add_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw add ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f15() { @@ -218,10 +208,9 @@ __int128 f15() { // CHECK-LABEL: @f16( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_sub_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw sub ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f16() { @@ -230,10 +219,9 @@ __int128 f16() { // CHECK-LABEL: @f17( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_and_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw and ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f17() { @@ -242,10 +230,9 @@ __int128 f17() { // CHECK-LABEL: @f18( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_xor_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xor ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f18() { @@ -254,10 +241,9 @@ __int128 f18() { // CHECK-LABEL: @f19( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_or_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw or ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f19() { @@ -266,10 +252,9 @@ __int128 f19() { // CHECK-LABEL: @f20( // CHECK-NEXT: entry: -// CHECK-NEXT: [[INDIRECT_ARG_TEMP:%.*]] = alloca i128, align 8 // CHECK-NEXT: [[TMP0:%.*]] = load i128, ptr @Val, align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: store i128 [[TMP0]], ptr [[INDIRECT_ARG_TEMP]], align 8, !tbaa [[TBAA2]] -// CHECK-NEXT: call void @__atomic_fetch_nand_16(ptr dead_on_unwind nonnull writable sret(i128) align 8 [[AGG_RESULT:%.*]], ptr noundef nonnull @Ptr, ptr noundef nonnull [[INDIRECT_ARG_TEMP]], i32 noundef signext 5) +// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw nand ptr @Ptr, i128 [[TMP0]] seq_cst, align 8 +// CHECK-NEXT: store i128 [[TMP1]], ptr [[AGG_RESULT:%.*]], align 8, !tbaa [[TBAA2]] // CHECK-NEXT: ret void // __int128 f20() { diff --git a/clang/test/CodeGen/arm-atomics-m.c b/clang/test/CodeGen/arm-atomics-m.c index b9cc72bc6b98ab..6087fd9d6a66ae 100644 --- a/clang/test/CodeGen/arm-atomics-m.c +++ b/clang/test/CodeGen/arm-atomics-m.c @@ -22,14 +22,14 @@ void test_presence(void) r = 0; __atomic_store(&i, &r, memory_order_seq_cst); - // CHECK: __atomic_fetch_add_8 + // CHECK: atomicrmw add ptr {{.*}} seq_cst, align 8 __atomic_fetch_add(&l, 1, memory_order_seq_cst); - // CHECK: __atomic_fetch_sub_8 + // CHECK: atomicrmw sub ptr {{.*}} seq_cst, align 8 __atomic_fetch_sub(&l, 1, memory_order_seq_cst); - // CHECK: __atomic_load_8 + // CHECK: load atomic i64, ptr {{.*}} seq_cst, align 8 long long rl; __atomic_load(&l, &rl, memory_order_seq_cst); - // CHECK: __atomic_store_8 + // CHECK: store atomic i64 {{.*}}, ptr {{.*}} seq_cst, align 8 rl = 0; __atomic_store(&l, &rl, memory_order_seq_cst); } diff --git a/clang/test/CodeGen/arm-atomics-m0.c b/clang/test/CodeGen/arm-atomics-m0.c index 335a1d2711f808..94e344cf608df4 100644 --- a/clang/test/CodeGen/arm-atomics-m0.c +++ b/clang/test/CodeGen/arm-atomics-m0.c @@ -11,25 +11,25 @@ typedef enum memory_order { void test_presence(void) { // CHECK-LABEL: @test_presence - // CHECK: __atomic_fetch_add_4 + // CHECK: atomicrmw add ptr {{.*}} seq_cst, align 4 __atomic_fetch_add(&i, 1, memory_order_seq_cst); - // CHECK: __atomic_fetch_sub_4 + // CHECK: atomicrmw sub {{.*}} seq_cst, align 4 __atomic_fetch_sub(&i, 1, memory_order_seq_cst); - // CHECK: __atomic_load_4 + // CHECK: load atomic i32, ptr {{.*}} seq_cst, align 4 int r; __atomic_load(&i, &r, memory_order_seq_cst); - // CHECK: __atomic_store_4 + // CHECK: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 r = 0; __atomic_store(&i, &r, memory_order_seq_cst); - // CHECK: __atomic_fetch_add_8 + // CHECK: atomicrmw add {{.*}} seq_cst, align 8 __atomic_fetch_add(&l, 1, memory_order_seq_cst); - // CHECK: __atomic_fetch_sub_8 + // CHECK: atomicrmw sub {{.*}} seq_cst, align 8 __atomic_fetch_sub(&l, 1, memory_order_seq_cst); - // CHECK: __atomic_load_8 + // CHECK: load atomic i64, ptr {{.*}} seq_cst, align 8 long long rl; __atomic_load(&l, &rl, memory_order_seq_cst); - // CHECK: __atomic_store_8 + // CHECK: store atomic i64 {{.*}}, ptr {{.*}} seq_cst, align 8 rl = 0; __atomic_store(&l, &rl, memory_order_seq_cst); } diff --git a/clang/test/CodeGen/atomic-ops-libcall.c b/clang/test/CodeGen/atomic-ops-libcall.c index 745ccd22bf33f0..38a23f7236ce72 100644 --- a/clang/test/CodeGen/atomic-ops-libcall.c +++ b/clang/test/CodeGen/atomic-ops-libcall.c @@ -1,120 +1,338 @@ -// RUN: %clang_cc1 < %s -triple armv5e-none-linux-gnueabi -emit-llvm -O1 | FileCheck %s - -// FIXME: This file should not be checking -O1 output. -// Ie, it is testing many IR optimizer passes as part of front-end verification. +// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 4 +// RUN: %clang_cc1 -triple armv5e-none-linux-gnueabi -emit-llvm %s -o - | FileCheck %s enum memory_order { memory_order_relaxed, memory_order_consume, memory_order_acquire, memory_order_release, memory_order_acq_rel, memory_order_seq_cst }; +// CHECK-LABEL: define dso_local ptr @test_c11_atomic_fetch_add_int_ptr( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0:[0-9]+]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 12, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret ptr [[TMP3]] +// int *test_c11_atomic_fetch_add_int_ptr(_Atomic(int *) *p) { - // CHECK: test_c11_atomic_fetch_add_int_ptr - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_add_4(ptr noundef %p, i32 noundef 12, i32 noundef 5) return __c11_atomic_fetch_add(p, 3, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local ptr @test_c11_atomic_fetch_sub_int_ptr( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 20, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw sub ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret ptr [[TMP3]] +// int *test_c11_atomic_fetch_sub_int_ptr(_Atomic(int *) *p) { - // CHECK: test_c11_atomic_fetch_sub_int_ptr - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(ptr noundef %p, i32 noundef 20, i32 noundef 5) return __c11_atomic_fetch_sub(p, 5, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_c11_atomic_fetch_add_int( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 3, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_c11_atomic_fetch_add_int(_Atomic(int) *p) { - // CHECK: test_c11_atomic_fetch_add_int - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_add_4(ptr noundef %p, i32 noundef 3, i32 noundef 5) return __c11_atomic_fetch_add(p, 3, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_c11_atomic_fetch_sub_int( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 5, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw sub ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_c11_atomic_fetch_sub_int(_Atomic(int) *p) { - // CHECK: test_c11_atomic_fetch_sub_int - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(ptr noundef %p, i32 noundef 5, i32 noundef 5) return __c11_atomic_fetch_sub(p, 5, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local ptr @fp2a( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 4, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw sub ptr [[TMP0]], i32 [[TMP1]] monotonic, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret ptr [[TMP3]] +// int *fp2a(int **p) { - // CHECK: @fp2a - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(ptr noundef %p, i32 noundef 4, i32 noundef 0) // Note, the GNU builtins do not multiply by sizeof(T)! return __atomic_fetch_sub(p, 4, memory_order_relaxed); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_add( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_add(int *p) { - // CHECK: test_atomic_fetch_add - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_add_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_add(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_sub( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw sub ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_sub(int *p) { - // CHECK: test_atomic_fetch_sub - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_sub_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_sub(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_and( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw and ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_and(int *p) { - // CHECK: test_atomic_fetch_and - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_and_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_and(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_or( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw or ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_or(int *p) { - // CHECK: test_atomic_fetch_or - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_or_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_or(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_xor( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw xor ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_xor(int *p) { - // CHECK: test_atomic_fetch_xor - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_xor_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_xor(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_fetch_nand( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw nand ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: store i32 [[TMP2]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP3]] +// int test_atomic_fetch_nand(int *p) { - // CHECK: test_atomic_fetch_nand - // CHECK: {{%[^ ]*}} = tail call i32 @__atomic_fetch_nand_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) return __atomic_fetch_nand(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_add_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = add i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[TMP3]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP4]] +// int test_atomic_add_fetch(int *p) { - // CHECK: test_atomic_add_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_add_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // CHECK: {{%[^ ]*}} = add i32 [[CALL]], 55 return __atomic_add_fetch(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_sub_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw sub ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = sub i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[TMP3]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP4]] +// int test_atomic_sub_fetch(int *p) { - // CHECK: test_atomic_sub_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_sub_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // CHECK: {{%[^ ]*}} = add i32 [[CALL]], -55 return __atomic_sub_fetch(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_and_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw and ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[TMP3]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP4]] +// int test_atomic_and_fetch(int *p) { - // CHECK: test_atomic_and_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_and_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // CHECK: {{%[^ ]*}} = and i32 [[CALL]], 55 return __atomic_and_fetch(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_or_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw or ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = or i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[TMP3]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP4]] +// int test_atomic_or_fetch(int *p) { - // CHECK: test_atomic_or_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_or_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // CHECK: {{%[^ ]*}} = or i32 [[CALL]], 55 return __atomic_or_fetch(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_xor_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw xor ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = xor i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: store i32 [[TMP3]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP4]] +// int test_atomic_xor_fetch(int *p) { - // CHECK: test_atomic_xor_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_xor_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // CHECK: {{%[^ ]*}} = xor i32 [[CALL]], 55 return __atomic_xor_fetch(p, 55, memory_order_seq_cst); } +// CHECK-LABEL: define dso_local i32 @test_atomic_nand_fetch( +// CHECK-SAME: ptr noundef [[P:%.*]]) #[[ATTR0]] { +// CHECK-NEXT: entry: +// CHECK-NEXT: [[P_ADDR:%.*]] = alloca ptr, align 4 +// CHECK-NEXT: [[DOTATOMICTMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i32, align 4 +// CHECK-NEXT: store ptr [[P]], ptr [[P_ADDR]], align 4 +// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[P_ADDR]], align 4 +// CHECK-NEXT: store i32 55, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTATOMICTMP]], align 4 +// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw nand ptr [[TMP0]], i32 [[TMP1]] seq_cst, align 4 +// CHECK-NEXT: [[TMP3:%.*]] = and i32 [[TMP2]], [[TMP1]] +// CHECK-NEXT: [[TMP4:%.*]] = xor i32 [[TMP3]], -1 +// CHECK-NEXT: store i32 [[TMP4]], ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[ATOMIC_TEMP]], align 4 +// CHECK-NEXT: ret i32 [[TMP5]] +// int test_atomic_nand_fetch(int *p) { - // CHECK: test_atomic_nand_fetch - // CHECK: [[CALL:%[^ ]*]] = tail call i32 @__atomic_fetch_nand_4(ptr noundef %p, i32 noundef 55, i32 noundef 5) - // FIXME: We should not be checking optimized IR. It changes independently of clang. - // FIXME-CHECK: [[AND:%[^ ]*]] = and i32 [[CALL]], 55 - // FIXME-CHECK: {{%[^ ]*}} = xor i32 [[AND]], -1 return __atomic_nand_fetch(p, 55, memory_order_seq_cst); } diff --git a/clang/test/CodeGen/atomic-ops.c b/clang/test/CodeGen/atomic-ops.c index 9ac05d270b97c5..b6060dcc540f90 100644 --- a/clang/test/CodeGen/atomic-ops.c +++ b/clang/test/CodeGen/atomic-ops.c @@ -198,7 +198,8 @@ struct S implicit_load(_Atomic(struct S) *a) { struct S fd1(struct S *a) { // CHECK-LABEL: @fd1 // CHECK: [[RETVAL:%.*]] = alloca %struct.S, align 4 - // CHECK: call void @__atomic_load(i32 noundef 8, ptr noundef {{.*}}, ptr noundef [[RETVAL]], i32 noundef 5) + // CHECK: [[TMP1:%.*]] = load atomic i64, ptr {{%.*}} seq_cst, align 4 + // CHECK-NEXT: store i64 [[TMP1]], ptr [[RETVAL]], align 4 // CHECK: ret struct S ret; __atomic_load(a, &ret, memory_order_seq_cst); @@ -213,7 +214,8 @@ void fd2(struct S *a, struct S *b) { // CHECK-NEXT: store ptr %b, ptr [[B_ADDR]], align 4 // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load ptr, ptr [[A_ADDR]], align 4 // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load ptr, ptr [[B_ADDR]], align 4 - // CHECK-NEXT: call void @__atomic_store(i32 noundef 8, ptr noundef [[LOAD_A_PTR]], ptr noundef [[LOAD_B_PTR]], + // CHECK-NEXT: [[LOAD_B:%.*]] = load i64, ptr [[LOAD_B_PTR]], align 4 + // CHECK-NEXT: store atomic i64 [[LOAD_B]], ptr [[LOAD_A_PTR]] seq_cst, align 4 // CHECK-NEXT: ret void __atomic_store(a, b, memory_order_seq_cst); } @@ -229,7 +231,9 @@ void fd3(struct S *a, struct S *b, struct S *c) { // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load ptr, ptr [[A_ADDR]], align 4 // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load ptr, ptr [[B_ADDR]], align 4 // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load ptr, ptr [[C_ADDR]], align 4 - // CHECK-NEXT: call void @__atomic_exchange(i32 noundef 8, ptr noundef [[LOAD_A_PTR]], ptr noundef [[LOAD_B_PTR]], ptr noundef [[LOAD_C_PTR]], + // CHECK-NEXT: [[LOAD_B:%.*]] = load i64, ptr [[LOAD_B_PTR]], align 4 + // CHECK-NEXT: [[RESULT:%.*]] = atomicrmw xchg ptr [[LOAD_A_PTR]], i64 [[LOAD_B]] seq_cst, align 4 + // CHECK-NEXT: store i64 [[RESULT]], ptr [[LOAD_C_PTR]], align 4 __atomic_exchange(a, b, c, memory_order_seq_cst); } @@ -245,8 +249,9 @@ _Bool fd4(struct S *a, struct S *b, struct S *c) { // CHECK-NEXT: [[LOAD_A_PTR:%.*]] = load ptr, ptr [[A_ADDR]], align 4 // CHECK-NEXT: [[LOAD_B_PTR:%.*]] = load ptr, ptr [[B_ADDR]], align 4 // CHECK-NEXT: [[LOAD_C_PTR:%.*]] = load ptr, ptr [[C_ADDR]], align 4 - // CHECK-NEXT: [[CALL:%.*]] = call zeroext i1 @__atomic_compare_exchange(i32 noundef 8, ptr noundef [[LOAD_A_PTR]], ptr noundef [[LOAD_B_PTR]], ptr noundef [[LOAD_C_PTR]], - // CHECK-NEXT: ret i1 [[CALL]] + // CHECK-NEXT: [[LOAD_B:%.*]] = load i64, ptr [[LOAD_B_PTR]], align 4 + // CHECK-NEXT: [[LOAD_C:%.*]] = load i64, ptr [[LOAD_C_PTR]], align 4 + // CHECK-NEXT: {{.*}} = cmpxchg weak ptr [[LOAD_A_PTR]], i64 [[LOAD_B]], i64 [[LOAD_C]] seq_cst seq_cst, align 4 return __atomic_compare_exchange(a, b, c, 1, 5, 5); } @@ -682,13 +687,13 @@ void test_underaligned(void) { // CHECK-LABEL: @test_underaligned struct Underaligned { char c[8]; } underaligned_a, underaligned_b, underaligned_c; - // CHECK: call void @__atomic_load(i32 noundef 8, + // CHECK: load atomic i64, {{.*}}, align 1 __atomic_load(&underaligned_a, &underaligned_b, memory_order_seq_cst); - // CHECK: call void @__atomic_store(i32 noundef 8, + // CHECK: store atomic i64 {{.*}}, align 1 __atomic_store(&underaligned_a, &underaligned_b, memory_order_seq_cst); - // CHECK: call void @__atomic_exchange(i32 noundef 8, + // CHECK: atomicrmw xchg ptr {{.*}}, align 1 __atomic_exchange(&underaligned_a, &underaligned_b, &underaligned_c, memory_order_seq_cst); - // CHECK: call {{.*}} @__atomic_compare_exchange(i32 noundef 8, + // CHECK: cmpxchg weak ptr {{.*}}, align 1 __atomic_compare_exchange(&underaligned_a, &underaligned_b, &underaligned_c, 1, memory_order_seq_cst, memory_order_seq_cst); __attribute__((aligned)) struct Underaligned aligned_a, aligned_b, aligned_c; @@ -747,7 +752,7 @@ void test_minmax_postop(int *si, unsigned *ui, unsigned short *us, signed char * // CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]] // CHECK: store i32 [[NEW]], ptr *si = __atomic_min_fetch(si, 42, memory_order_release); - + // CHECK: [[OLD:%.*]] = atomicrmw umax ptr [[PTR:%.*]], i32 [[RHS:%.*]] release, align 4 // CHECK: [[TST:%.*]] = icmp ugt i32 [[OLD]], [[RHS]] // CHECK: [[NEW:%.*]] = select i1 [[TST]], i32 [[OLD]], i32 [[RHS]] @@ -772,7 +777,7 @@ void test_minmax_postop(int *si, unsigned *ui, unsigned short *us, signed char * // CHECK: store i8 [[NEW]], ptr *sc = __atomic_min_fetch(sc, 42, memory_order_release); - // CHECK: [[OLD:%.*]] = call i64 @__atomic_fetch_umin_8(ptr noundef {{%.*}}, i64 noundef [[RHS:%.*]], + // CHECK: [[OLD:%.*]] = atomicrmw umin ptr {{%.*}}, i64 [[RHS:%.*]] release, align 4 // CHECK: [[TST:%.*]] = icmp ult i64 [[OLD]], [[RHS]] // CHECK: [[NEW:%.*]] = select i1 [[TST]], i64 [[OLD]], i64 [[RHS]] // CHECK: store i64 [[NEW]], ptr diff --git a/clang/test/CodeGen/atomics-inlining.c b/clang/test/CodeGen/atomics-inlining.c index 862c63076b2dc0..217a294ee84abc 100644 --- a/clang/test/CodeGen/atomics-inlining.c +++ b/clang/test/CodeGen/atomics-inlining.c @@ -38,14 +38,14 @@ void test1(void) { (void)__atomic_store(&a1, &a2, memory_order_seq_cst); // ARM-LABEL: define{{.*}} void @test1 -// ARM: = call{{.*}} zeroext i8 @__atomic_load_1(ptr noundef @c1 -// ARM: call{{.*}} void @__atomic_store_1(ptr noundef @c1, i8 noundef zeroext -// ARM: = call{{.*}} zeroext i16 @__atomic_load_2(ptr noundef @s1 -// ARM: call{{.*}} void @__atomic_store_2(ptr noundef @s1, i16 noundef zeroext -// ARM: = call{{.*}} i32 @__atomic_load_4(ptr noundef @i1 -// ARM: call{{.*}} void @__atomic_store_4(ptr noundef @i1, i32 noundef -// ARM: = call{{.*}} i64 @__atomic_load_8(ptr noundef @ll1 -// ARM: call{{.*}} void @__atomic_store_8(ptr noundef @ll1, i64 noundef +// ARM: = load atomic i8, ptr @c1 seq_cst, align 1 +// ARM: store atomic i8 {{.*}}, ptr @c1 seq_cst, align 1 +// ARM: = load atomic i16, ptr @s1 seq_cst, align 2 +// ARM: store atomic i16 {{.*}}, ptr @s1 seq_cst, align 2 +// ARM: = load atomic i32, ptr @i1 seq_cst, align 4 +// ARM: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 +// ARM: = load atomic i64, ptr @ll1 seq_cst, align 8 +// ARM: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 // ARM: call{{.*}} void @__atomic_load(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 // ARM: call{{.*}} void @__atomic_store(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 @@ -56,8 +56,8 @@ void test1(void) { // PPC32: store atomic i16 {{.*}}, ptr @s1 seq_cst, align 2 // PPC32: = load atomic i32, ptr @i1 seq_cst, align 4 // PPC32: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 -// PPC32: = call i64 @__atomic_load_8(ptr noundef @ll1 -// PPC32: call void @__atomic_store_8(ptr noundef @ll1, i64 +// PPC32: = load atomic i64, ptr @ll1 seq_cst, align 8 +// PPC32: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 // PPC32: call void @__atomic_load(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 // PPC32: call void @__atomic_store(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 @@ -80,8 +80,8 @@ void test1(void) { // MIPS32: store atomic i16 {{.*}}, ptr @s1 seq_cst, align 2 // MIPS32: = load atomic i32, ptr @i1 seq_cst, align 4 // MIPS32: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 -// MIPS32: call i64 @__atomic_load_8(ptr noundef @ll1 -// MIPS32: call void @__atomic_store_8(ptr noundef @ll1, i64 +// MIPS32: = load atomic i64, ptr @ll1 seq_cst, align 8 +// MIPS32: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 // MIPS32: call void @__atomic_load(i32 noundef signext 100, ptr noundef @a1, ptr noundef @a2 // MIPS32: call void @__atomic_store(i32 noundef signext 100, ptr noundef @a1, ptr noundef @a2 @@ -94,7 +94,7 @@ void test1(void) { // MIPS64: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 // MIPS64: = load atomic i64, ptr @ll1 seq_cst, align 8 // MIPS64: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 -// MIPS64: call void @__atomic_load(i64 noundef zeroext 100, ptr noundef @a1 +// MIPS64: call void @__atomic_load(i64 noundef zeroext 100, ptr noundef @a1, ptr noundef @a2 // MIPS64: call void @__atomic_store(i64 noundef zeroext 100, ptr noundef @a1, ptr noundef @a2 // SPARC-LABEL: define{{.*}} void @test1 @@ -104,12 +104,12 @@ void test1(void) { // SPARC: store atomic i16 {{.*}}, ptr @s1 seq_cst, align 2 // SPARC: = load atomic i32, ptr @i1 seq_cst, align 4 // SPARC: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 -// SPARCV8: call i64 @__atomic_load_8(ptr noundef @ll1 -// SPARCV8: call void @__atomic_store_8(ptr noundef @ll1, i64 -// SPARCV9: load atomic i64, ptr @ll1 seq_cst, align 8 -// SPARCV9: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 +// SPARC: load atomic i64, ptr @ll1 seq_cst, align 8 +// SPARC: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 // SPARCV8: call void @__atomic_load(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 // SPARCV8: call void @__atomic_store(i32 noundef 100, ptr noundef @a1, ptr noundef @a2 +// SPARCV9: call void @__atomic_load(i64 noundef 100, ptr noundef @a1, ptr noundef @a2 +// SPARCV9: call void @__atomic_store(i64 noundef 100, ptr noundef @a1, ptr noundef @a2 // NVPTX-LABEL: define{{.*}} void @test1 // NVPTX: = load atomic i8, ptr @c1 seq_cst, align 1 @@ -120,7 +120,7 @@ void test1(void) { // NVPTX: store atomic i32 {{.*}}, ptr @i1 seq_cst, align 4 // NVPTX: = load atomic i64, ptr @ll1 seq_cst, align 8 // NVPTX: store atomic i64 {{.*}}, ptr @ll1 seq_cst, align 8 -// NVPTX: call void @__atomic_load(i64 noundef 100, ptr noundef @a1, ptr noundef @a2, i32 noundef 5) -// NVPTX: call void @__atomic_store(i64 noundef 100, ptr noundef @a1, ptr noundef @a2, i32 noundef 5) +// NVPTX: call void @__atomic_load(i64 noundef 100, ptr noundef @a1, ptr noundef @a2 +// NVPTX: call void @__atomic_store(i64 noundef 100, ptr noundef @a1, ptr noundef @a2 } diff --git a/clang/test/CodeGen/c11atomics.c b/clang/test/CodeGen/c11atomics.c index dd1f52f70ae09f..4da36ad4da0f92 100644 --- a/clang/test/CodeGen/c11atomics.c +++ b/clang/test/CodeGen/c11atomics.c @@ -343,10 +343,9 @@ PS test_promoted_load(_Atomic(PS) *addr) { // CHECK: [[ATOMIC_RES:%.*]] = alloca { %struct.PS, [2 x i8] }, align 8 // CHECK: store ptr %addr, ptr [[ADDR_ARG]], align 4 // CHECK: [[ADDR:%.*]] = load ptr, ptr [[ADDR_ARG]], align 4 - // CHECK: [[RES:%.*]] = call arm_aapcscc i64 @__atomic_load_8(ptr noundef [[ADDR]], i32 noundef 5) - // CHECK: store i64 [[RES]], ptr [[ATOMIC_RES]], align 8 - // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 8 [[ATOMIC_RES]], i32 6, i1 false) - + // CHECK: [[ATOMIC_RES:%.*]] = load atomic i64, ptr [[ADDR]] seq_cst, align 8 + // CHECK: store i64 [[ATOMIC_RES]], ptr [[ATOMIC_RES_ADDR:%.*]], align 8 + // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 8 [[ATOMIC_RES_ADDR]], i32 6, i1 false) return __c11_atomic_load(addr, 5); } @@ -362,8 +361,8 @@ void test_promoted_store(_Atomic(PS) *addr, PS *val) { // CHECK: [[VAL:%.*]] = load ptr, ptr [[VAL_ARG]], align 4 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[NONATOMIC_TMP]], ptr align 2 [[VAL]], i32 6, i1 false) // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ATOMIC_VAL]], ptr align 2 [[NONATOMIC_TMP]], i64 6, i1 false) - // CHECK: [[VAL64:%.*]] = load i64, ptr [[ATOMIC_VAL]], align 2 - // CHECK: call arm_aapcscc void @__atomic_store_8(ptr noundef [[ADDR]], i64 noundef [[VAL64]], i32 noundef 5) + // CHECK: [[ATOMIC:%.*]] = load i64, ptr [[ATOMIC_VAL]], align 8 + // CHECK: store atomic i64 [[ATOMIC]], ptr [[ADDR]] seq_cst, align 8 __c11_atomic_store(addr, *val, 5); } @@ -380,10 +379,10 @@ PS test_promoted_exchange(_Atomic(PS) *addr, PS *val) { // CHECK: [[VAL:%.*]] = load ptr, ptr [[VAL_ARG]], align 4 // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[NONATOMIC_TMP]], ptr align 2 [[VAL]], i32 6, i1 false) // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ATOMIC_VAL]], ptr align 2 [[NONATOMIC_TMP]], i64 6, i1 false) - // CHECK: [[VAL64:%.*]] = load i64, ptr [[ATOMIC_VAL]], align 2 - // CHECK: [[RES:%.*]] = call arm_aapcscc i64 @__atomic_exchange_8(ptr noundef [[ADDR]], i64 noundef [[VAL64]], i32 noundef 5) - // CHECK: store i64 [[RES]], ptr [[ATOMIC_RES]], align 8 - // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 8 [[ATOMIC_RES]], i32 6, i1 false) + // CHECK: [[ATOMIC:%.*]] = load i64, ptr [[ATOMIC_VAL]], align 8 + // CHECK: [[ATOMIC_RES:%.*]] = atomicrmw xchg ptr [[ADDR]], i64 [[ATOMIC]] seq_cst, align 8 + // CHECK: store i64 [[ATOMIC_RES]], ptr [[ATOMIC_RES_PTR:%.*]], align 8 + // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 %agg.result, ptr align 8 [[ATOMIC_RES_PTR]], i32 6, i1 false) return __c11_atomic_exchange(addr, *val, 5); } @@ -404,9 +403,10 @@ _Bool test_promoted_cmpxchg(_Atomic(PS) *addr, PS *desired, PS *new) { // CHECK: call void @llvm.memcpy.p0.p0.i32(ptr align 2 [[NONATOMIC_TMP]], ptr align 2 [[NEW]], i32 6, i1 false) // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ATOMIC_DESIRED]], ptr align 2 [[DESIRED]], i64 6, i1 false) // CHECK: call void @llvm.memcpy.p0.p0.i64(ptr align 8 [[ATOMIC_NEW]], ptr align 2 [[NONATOMIC_TMP]], i64 6, i1 false) - // CHECK: [[NEW64:%.*]] = load i64, ptr [[ATOMIC_NEW]], align 2 - // CHECK: [[RES:%.*]] = call arm_aapcscc zeroext i1 @__atomic_compare_exchange_8(ptr noundef [[ADDR]], ptr noundef [[ATOMIC_DESIRED]], i64 noundef [[NEW64]], i32 noundef 5, i32 noundef 5) - // CHECK: ret i1 [[RES]] + // CHECK: [[VAL1:%.*]] = load i64, ptr [[ATOMIC_DESIRED]], align 8 + // CHECK: [[VAL2:%.*]] = load i64, ptr [[ATOMIC_NEW]], align 8 + // CHECK: [[RES_PAIR:%.*]] = cmpxchg ptr [[ADDR]], i64 [[VAL1]], i64 [[VAL2]] seq_cst seq_cst, align 8 + // CHECK: [[RES:%.*]] = extractvalue { i64, i1 } [[RES_PAIR]], 1 return __c11_atomic_compare_exchange_strong(addr, desired, *new, 5, 5); } @@ -414,12 +414,12 @@ struct Empty {}; struct Empty test_empty_struct_load(_Atomic(struct Empty)* empty) { // CHECK-LABEL: @test_empty_struct_load( - // CHECK: call arm_aapcscc zeroext i8 @__atomic_load_1(ptr noundef %{{.*}}, i32 noundef 5) + // CHECK: load atomic i8, ptr {{.*}}, align 1 return __c11_atomic_load(empty, 5); } void test_empty_struct_store(_Atomic(struct Empty)* empty, struct Empty value) { // CHECK-LABEL: @test_empty_struct_store( - // CHECK: call arm_aapcscc void @__atomic_store_1(ptr noundef %{{.*}}, i8 noundef zeroext %{{.*}}, i32 noundef 5) + // CHECK: store atomic i8 {{.*}}, ptr {{.*}}, align 1 __c11_atomic_store(empty, value, 5); } diff --git a/clang/test/CodeGenCXX/atomic-inline.cpp b/clang/test/CodeGenCXX/atomic-inline.cpp index 701bbd57b485c7..c8fa877a37beb5 100644 --- a/clang/test/CodeGenCXX/atomic-inline.cpp +++ b/clang/test/CodeGenCXX/atomic-inline.cpp @@ -42,7 +42,7 @@ AM16 m16; AM16 load16() { AM16 am; // CHECK-LABEL: @_Z6load16v - // CHECK: call void @__atomic_load + // CHECK: load atomic i128, {{.*}} monotonic, align 16 // CORE2-LABEL: @_Z6load16v // CORE2: load atomic i128, {{.*}} monotonic, align 16 __atomic_load(&m16, &am, 0); @@ -52,7 +52,7 @@ AM16 load16() { AM16 s16; void store16() { // CHECK-LABEL: @_Z7store16v - // CHECK: call void @__atomic_store + // CHECK: store atomic i128 {{.*}} monotonic, align 16 // CORE2-LABEL: @_Z7store16v // CORE2: store atomic i128 {{.*}} monotonic, align 16 __atomic_store(&m16, &s16, 0); @@ -61,7 +61,7 @@ void store16() { bool cmpxchg16() { AM16 am; // CHECK-LABEL: @_Z9cmpxchg16v - // CHECK: call noundef zeroext i1 @__atomic_compare_exchange + // CHECK: cmpxchg ptr {{.*}} monotonic monotonic, align 16 // CORE2-LABEL: @_Z9cmpxchg16v // CORE2: cmpxchg ptr {{.*}} monotonic monotonic, align 16 return __atomic_compare_exchange(&m16, &s16, &am, 0, 0, 0); diff --git a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl index 2f020c21082124..d615ff6bec4140 100644 --- a/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl +++ b/clang/test/CodeGenOpenCL/atomic-ops-libcall.cl @@ -20,63 +20,60 @@ typedef enum memory_scope { void f(atomic_int *i, global atomic_int *gi, local atomic_int *li, private atomic_int *pi, atomic_uint *ui, int cmp, int order, int scope) { int x; - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_load_4(ptr noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: load atomic i32, ptr addrspace(4) {{.*}} seq_cst, align 4 + // ARM: load atomic i32, ptr {{.*}} seq_cst, align 4 x = __opencl_atomic_load(i, memory_order_seq_cst, memory_scope_work_group); - // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: store atomic i32 {{.*}}, ptr addrspace(4) {{.*}} seq_cst, align 4 + // ARM: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 __opencl_atomic_store(i, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr addrspace(1) {{%[0-9]+}} to ptr addrspace(4) - // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: store atomic i32 {{.*}}, ptr addrspace(1) {{.*}} seq_cst, align 4 + // ARM: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 __opencl_atomic_store(gi, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr addrspace(3) {{%[0-9]+}} to ptr addrspace(4) - // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: store atomic i32 {{.*}}, ptr addrspace(3) {{.*}} seq_cst, align 4 + // ARM: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 __opencl_atomic_store(li, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: %[[GP:[0-9]+]] = addrspacecast ptr {{%[0-9]+}} to ptr addrspace(4) - // SPIR: call void @__opencl_atomic_store_4(ptr addrspace(4) noundef %[[GP]], i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: call void @__opencl_atomic_store_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 + // ARM: store atomic i32 {{.*}}, ptr {{.*}} seq_cst, align 4 __opencl_atomic_store(pi, 1, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_add_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: atomicrmw add ptr addrspace(4) {{.*}}, i32 {{.*}} seq_cst, align 4 + // ARM: atomicrmw add ptr {{.*}}, i32 {{.*}} seq_cst, align 4 x = __opencl_atomic_fetch_add(i, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_min_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: atomicrmw min ptr addrspace(4) {{.*}}, i32 {{.*}} seq_cst, align 4 + // ARM: atomicrmw min ptr {{.*}}, i32 {{.*}} seq_cst, align 4 x = __opencl_atomic_fetch_min(i, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(ptr addrspace(4) noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call i32 @__opencl_atomic_fetch_umin_4(ptr noundef {{%[0-9]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 1) + // SPIR: atomicrmw umin ptr addrspace(4) {{.*}}, i32 {{.*}} seq_cst, align 4 + // ARM: atomicrmw umin ptr {{.*}}, i32 {{.*}} seq_cst, align 4 x = __opencl_atomic_fetch_min(ui, 3, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // SPIR: cmpxchg ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 + // ARM: cmpxchg ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_strong(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 1) + // SPIR: cmpxchg weak ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 + // ARM: cmpxchg weak ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_work_group); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 2) + // SPIR: cmpxchg weak ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 + // ARM: cmpxchg weak ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_device); - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 3) + // SPIR: cmpxchg weak ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 + // ARM: cmpxchg weak ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_all_svm_devices); #ifdef cl_khr_subgroups - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef 5, i32 noundef 5, i32 noundef 4) + // SPIR: cmpxchg weak ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, memory_order_seq_cst, memory_order_seq_cst, memory_scope_sub_group); #endif - // SPIR: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr addrspace(4) noundef {{%[0-9]+}}, ptr addrspace(4) noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) - // ARM: {{%[^ ]*}} = call zeroext i1 @__opencl_atomic_compare_exchange_4(ptr noundef {{%[0-9]+}}, ptr noundef {{%[^,]+}}, i32 noundef {{%[0-9]+}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}, i32 noundef %{{.*}}) + // SPIR: cmpxchg weak ptr addrspace(4) {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 + // ARM: cmpxchg weak ptr {{.*}}, i32 {{.*}}, i32 {{.*}} seq_cst seq_cst, align 4 x = __opencl_atomic_compare_exchange_weak(i, &cmp, 1, order, order, scope); } diff --git a/clang/test/Driver/hlsl-lang-targets.hlsl b/clang/test/Driver/hlsl-lang-targets.hlsl index f2f4bba8196bc9..7ce490a66df5f5 100644 --- a/clang/test/Driver/hlsl-lang-targets.hlsl +++ b/clang/test/Driver/hlsl-lang-targets.hlsl @@ -32,7 +32,7 @@ // Invalid shader stages // // RUN: not %clang -target dxil--shadermodel6.2-unknown %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s -// RUN: not %clang -target dxil--shadermodel6.2-invalidenvironment %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s +// RUN: not %clang --target=dxil--shadermodel6.2-invalidenvironment %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV-DRV %s // RUN: not %clang -target dxil--shadermodel6.2-eabi %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s // RUN: not %clang -target dxil--shadermodel6.2-msvc %s -S -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-BAD-ENV %s @@ -47,6 +47,7 @@ // CHECK-BAD-OS: error: shader model '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation // CHECK-NO-ENV: error: shader stage is required as environment in target '{{.*}}' for HLSL code generation // CHECK-BAD-ENV: error: shader stage '{{.*}}' in target '{{.*}}' is invalid for HLSL code generation +// CHECK-BAD-ENV-DRV: error: version '{{.*}}' in target triple '{{.*}}' is invalid // CHECK-BAD-TARGET: error: HLSL code generation is unsupported for target '{{.*}}' [shader("pixel")] diff --git a/clang/test/Driver/linker-wrapper.c b/clang/test/Driver/linker-wrapper.c index 93e4525c998750..9eaed0b9221159 100644 --- a/clang/test/Driver/linker-wrapper.c +++ b/clang/test/Driver/linker-wrapper.c @@ -172,7 +172,7 @@ __attribute__((visibility("protected"), used)) int x; // AMD-TARGET-ID: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa -mcpu=gfx90a:xnack- -O2 -Wl,--no-undefined {{.*}}.o {{.*}}.o // RUN: clang-offload-packager -o %t-lib.out \ -// RUN: --image=file=%t.elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=all +// RUN: --image=file=%t.elf.o,kind=openmp,triple=amdgcn-amd-amdhsa,arch=generic // RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t-lib.out // RUN: llvm-ar rcs %t.a %t.o // RUN: clang-offload-packager -o %t1.out \ diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c index 2bf1886951f1f7..47dbeca206a94e 100644 --- a/clang/test/Sema/aarch64-sme-func-attrs.c +++ b/clang/test/Sema/aarch64-sme-func-attrs.c @@ -454,3 +454,43 @@ void unimplemented_spill_fill_za(void (*share_zt0_only)(void) __arm_inout("zt0") // expected-note@+1 {{add '__arm_preserves("za")' to the callee if it preserves ZA}} share_zt0_only(); } + +// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} +// expected-error@+1 {{streaming function cannot be multi-versioned}} +__attribute__((target_version("sme2"))) +void cannot_work_version(void) __arm_streaming {} +// expected-cpp-error@+5 {{function declared 'void ()' was previously declared 'void () __arm_streaming', which has different SME function attributes}} +// expected-cpp-note@-2 {{previous declaration is here}} +// expected-error@+3 {{function declared 'void (void)' was previously declared 'void (void) __arm_streaming', which has different SME function attributes}} +// expected-note@-4 {{previous declaration is here}} +__attribute__((target_version("default"))) +void cannot_work_version(void) {} + + +// expected-cpp-error@+2 {{streaming function cannot be multi-versioned}} +// expected-error@+1 {{streaming function cannot be multi-versioned}} +__attribute__((target_clones("sme2"))) +void cannot_work_clones(void) __arm_streaming {} + + +__attribute__((target("sme2"))) +void just_fine_streaming(void) __arm_streaming {} +__attribute__((target_version("sme2"))) +void just_fine(void) { just_fine_streaming(); } +__attribute__((target_version("default"))) +void just_fine(void) {} + + +__arm_locally_streaming +__attribute__((target_version("sme2"))) +void just_fine_locally_streaming(void) {} +__attribute__((target_version("default"))) +void just_fine_locally_streaming(void) {} + + +void fmv_caller() { + cannot_work_version(); + cannot_work_clones(); + just_fine(); + just_fine_locally_streaming(); +} diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp index 52a00c8a1a35da..3b36e407228195 100644 --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/clang/unittests/Format/TokenAnnotatorTest.cpp @@ -2287,6 +2287,51 @@ TEST_F(TokenAnnotatorTest, UnderstandTableGenTokens) { EXPECT_TOKEN(Tokens[0], tok::identifier, TT_TableGenBangOperator); Tokens = Annotate("!cond"); EXPECT_TOKEN(Tokens[0], tok::identifier, TT_TableGenCondOperator); + + auto AnnotateValue = [this, &Style](llvm::StringRef Code) { + // Values are annotated only in specific context. + auto Result = annotate(("def X { let V = " + Code + "; }").str(), Style); + return decltype(Result){Result.begin() + 6, Result.end() - 3}; + }; + // Both of bang/cond operators. + Tokens = AnnotateValue("!cond(!eq(x, 0): 1, true: x)"); + ASSERT_EQ(Tokens.size(), 15u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::identifier, TT_TableGenCondOperator); + EXPECT_TOKEN(Tokens[2], tok::identifier, TT_TableGenBangOperator); + EXPECT_TOKEN(Tokens[8], tok::colon, TT_TableGenCondOperatorColon); + EXPECT_TOKEN(Tokens[10], tok::comma, TT_TableGenCondOperatorComma); + EXPECT_TOKEN(Tokens[12], tok::colon, TT_TableGenCondOperatorColon); + // DAGArg values with operator identifier + Tokens = AnnotateValue("(ins type1:$src1, type2:$src2)"); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_paren, TT_TableGenDAGArgOpener); + EXPECT_TOKEN(Tokens[3], tok::colon, TT_TableGenDAGArgListColon); + EXPECT_TOKEN(Tokens[4], tok::identifier, TT_Unknown); // $src1 + EXPECT_TOKEN(Tokens[5], tok::comma, TT_TableGenDAGArgListComma); + EXPECT_TOKEN(Tokens[7], tok::colon, TT_TableGenDAGArgListColon); + EXPECT_TOKEN(Tokens[9], tok::r_paren, TT_TableGenDAGArgCloser); + // List literal + Tokens = AnnotateValue("[1, 2, 3]"); + ASSERT_EQ(Tokens.size(), 7u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::l_square, TT_TableGenListOpener); + EXPECT_TOKEN(Tokens[6], tok::r_square, TT_TableGenListCloser); + // Suffixes of values + Tokens = AnnotateValue("valid.field"); + ASSERT_EQ(Tokens.size(), 3u) << Tokens; + EXPECT_TOKEN(Tokens[1], tok::period, TT_TableGenValueSuffix); + // Code + Tokens = AnnotateValue("[{ code is multiline string }]"); + ASSERT_EQ(Tokens.size(), 1u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::string_literal, TT_TableGenMultiLineString); + + // The definition + Tokens = annotate("def Def : Parent {}", Style); + ASSERT_EQ(Tokens.size(), 10u) << Tokens; // This contains eof. + // We use inheritance colon and function brace. They are enough. + EXPECT_TOKEN(Tokens[2], tok::colon, TT_InheritanceColon); + EXPECT_TOKEN(Tokens[4], tok::less, TT_TemplateOpener); + EXPECT_TOKEN(Tokens[6], tok::greater, TT_TemplateCloser); + EXPECT_TOKEN(Tokens[7], tok::l_brace, TT_FunctionLBrace); } TEST_F(TokenAnnotatorTest, UnderstandConstructors) { diff --git a/clang/www/analyzer/alpha_checks.html b/clang/www/analyzer/alpha_checks.html index 11ef7d405dd4c8..7bbe4a20288f23 100644 --- a/clang/www/analyzer/alpha_checks.html +++ b/clang/www/analyzer/alpha_checks.html @@ -87,29 +87,6 @@

Core Alpha Checkers

- - - -