diff options
Diffstat (limited to 'clang/lib/Sema')
43 files changed, 16405 insertions, 6973 deletions
diff --git a/clang/lib/Sema/AnalysisBasedWarnings.cpp b/clang/lib/Sema/AnalysisBasedWarnings.cpp index 04611dadde66..3b7356893833 100644 --- a/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -974,6 +974,14 @@ static void DiagUninitUse(Sema &S, const VarDecl *VD, const UninitUse &Use, << Use.getUser()->getSourceRange(); } +/// Diagnose uninitialized const reference usages. +static bool DiagnoseUninitializedConstRefUse(Sema &S, const VarDecl *VD, + const UninitUse &Use) { + S.Diag(Use.getUser()->getBeginLoc(), diag::warn_uninit_const_reference) + << VD->getDeclName() << Use.getUser()->getSourceRange(); + return true; +} + /// DiagnoseUninitializedUse -- Helper function for diagnosing uses of an /// uninitialized variable. This manages the different forms of diagnostic /// emitted for particular types of uses. Returns true if the use was diagnosed @@ -1506,13 +1514,14 @@ class UninitValsDiagReporter : public UninitVariablesHandler { // order of diagnostics when calling flushDiagnostics(). typedef llvm::MapVector<const VarDecl *, MappedType> UsesMap; UsesMap uses; + UsesMap constRefUses; public: UninitValsDiagReporter(Sema &S) : S(S) {} ~UninitValsDiagReporter() override { flushDiagnostics(); } - MappedType &getUses(const VarDecl *vd) { - MappedType &V = uses[vd]; + MappedType &getUses(UsesMap &um, const VarDecl *vd) { + MappedType &V = um[vd]; if (!V.getPointer()) V.setPointer(new UsesVec()); return V; @@ -1520,11 +1529,17 @@ public: void handleUseOfUninitVariable(const VarDecl *vd, const UninitUse &use) override { - getUses(vd).getPointer()->push_back(use); + getUses(uses, vd).getPointer()->push_back(use); + } + + void handleConstRefUseOfUninitVariable(const VarDecl *vd, + const UninitUse &use) override { + getUses(constRefUses, vd).getPointer()->push_back(use); } void handleSelfInit(const VarDecl *vd) override { - getUses(vd).setInt(true); + getUses(uses, vd).setInt(true); + getUses(constRefUses, vd).setInt(true); } void flushDiagnostics() { @@ -1571,6 +1586,32 @@ public: } uses.clear(); + + // Flush all const reference uses diags. + for (const auto &P : constRefUses) { + const VarDecl *vd = P.first; + const MappedType &V = P.second; + + UsesVec *vec = V.getPointer(); + bool hasSelfInit = V.getInt(); + + if (!vec->empty() && hasSelfInit && hasAlwaysUninitializedUse(vec)) + DiagnoseUninitializedUse(S, vd, + UninitUse(vd->getInit()->IgnoreParenCasts(), + /* isAlwaysUninit */ true), + /* alwaysReportSelfInit */ true); + else { + for (const auto &U : *vec) { + if (DiagnoseUninitializedConstRefUse(S, vd, U)) + break; + } + } + + // Release the uses vector. + delete vec; + } + + constRefUses.clear(); } private: @@ -1659,6 +1700,14 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { : getNotes(); } + OptionalNotes makeUnlockedHereNote(SourceLocation LocUnlocked, + StringRef Kind) { + return LocUnlocked.isValid() + ? getNotes(PartialDiagnosticAt( + LocUnlocked, S.PDiag(diag::note_unlocked_here) << Kind)) + : getNotes(); + } + public: ThreadSafetyReporter(Sema &S, SourceLocation FL, SourceLocation FEL) : S(S), FunLocation(FL), FunEndLocation(FEL), @@ -1685,13 +1734,14 @@ class ThreadSafetyReporter : public clang::threadSafety::ThreadSafetyHandler { Warnings.emplace_back(std::move(Warning), getNotes()); } - void handleUnmatchedUnlock(StringRef Kind, Name LockName, - SourceLocation Loc) override { + void handleUnmatchedUnlock(StringRef Kind, Name LockName, SourceLocation Loc, + SourceLocation LocPreviousUnlock) override { if (Loc.isInvalid()) Loc = FunLocation; PartialDiagnosticAt Warning(Loc, S.PDiag(diag::warn_unlock_but_no_lock) << Kind << LockName); - Warnings.emplace_back(std::move(Warning), getNotes()); + Warnings.emplace_back(std::move(Warning), + makeUnlockedHereNote(LocPreviousUnlock, Kind)); } void handleIncorrectUnlockKind(StringRef Kind, Name LockName, @@ -2184,7 +2234,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (!Diags.isIgnored(diag::warn_uninit_var, D->getBeginLoc()) || !Diags.isIgnored(diag::warn_sometimes_uninit_var, D->getBeginLoc()) || - !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc())) { + !Diags.isIgnored(diag::warn_maybe_uninit_var, D->getBeginLoc()) || + !Diags.isIgnored(diag::warn_uninit_const_reference, D->getBeginLoc())) { if (CFG *cfg = AC.getCFG()) { UninitValsDiagReporter reporter(S); UninitVariablesAnalysisStats stats; diff --git a/clang/lib/Sema/CodeCompleteConsumer.cpp b/clang/lib/Sema/CodeCompleteConsumer.cpp index b88ff9dd64cd..f1ad8aeaacbb 100644 --- a/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -23,6 +23,7 @@ #include "clang/Sema/Sema.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringExtras.h" #include "llvm/ADT/StringRef.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Casting.h" @@ -570,29 +571,10 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults( if (const char *BriefComment = CCS->getBriefComment()) OS << " : " << BriefComment; } - for (const FixItHint &FixIt : Results[I].FixIts) { - const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); - const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); - - SourceManager &SM = SemaRef.SourceMgr; - std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); - std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); - // Adjust for token ranges. - if (FixIt.RemoveRange.isTokenRange()) - EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts); - - OS << " (requires fix-it:" - << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':' - << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' - << SM.getLineNumber(EInfo.first, EInfo.second) << ':' - << SM.getColumnNumber(EInfo.first, EInfo.second) << "}" - << " to \"" << FixIt.CodeToInsert << "\")"; - } - OS << '\n'; break; case CodeCompletionResult::RK_Keyword: - OS << Results[I].Keyword << '\n'; + OS << Results[I].Keyword; break; case CodeCompletionResult::RK_Macro: @@ -602,13 +584,31 @@ void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults( includeBriefComments())) { OS << " : " << CCS->getAsString(); } - OS << '\n'; break; case CodeCompletionResult::RK_Pattern: - OS << "Pattern : " << Results[I].Pattern->getAsString() << '\n'; + OS << "Pattern : " << Results[I].Pattern->getAsString(); break; } + for (const FixItHint &FixIt : Results[I].FixIts) { + const SourceLocation BLoc = FixIt.RemoveRange.getBegin(); + const SourceLocation ELoc = FixIt.RemoveRange.getEnd(); + + SourceManager &SM = SemaRef.SourceMgr; + std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(BLoc); + std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(ELoc); + // Adjust for token ranges. + if (FixIt.RemoveRange.isTokenRange()) + EInfo.second += Lexer::MeasureTokenLength(ELoc, SM, SemaRef.LangOpts); + + OS << " (requires fix-it:" + << " {" << SM.getLineNumber(BInfo.first, BInfo.second) << ':' + << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' + << SM.getLineNumber(EInfo.first, EInfo.second) << ':' + << SM.getColumnNumber(EInfo.first, EInfo.second) << "}" + << " to \"" << FixIt.CodeToInsert << "\")"; + } + OS << '\n'; } } diff --git a/clang/lib/Sema/DeclSpec.cpp b/clang/lib/Sema/DeclSpec.cpp index 639231c87232..f4c30c90ad27 100644 --- a/clang/lib/Sema/DeclSpec.cpp +++ b/clang/lib/Sema/DeclSpec.cpp @@ -17,6 +17,7 @@ #include "clang/AST/LocInfoType.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LangOptions.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Sema.h" @@ -29,6 +30,9 @@ using namespace clang; void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); + assert(!TemplateId->isInvalid() && + "should not convert invalid template-ids to unqualified-ids"); + Kind = UnqualifiedIdKind::IK_TemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; @@ -37,6 +41,9 @@ void UnqualifiedId::setTemplateId(TemplateIdAnnotation *TemplateId) { void UnqualifiedId::setConstructorTemplateId(TemplateIdAnnotation *TemplateId) { assert(TemplateId && "NULL template-id annotation?"); + assert(!TemplateId->isInvalid() && + "should not convert invalid template-ids to unqualified-ids"); + Kind = UnqualifiedIdKind::IK_ConstructorTemplateId; this->TemplateId = TemplateId; StartLocation = TemplateId->TemplateNameLoc; @@ -130,6 +137,8 @@ void CXXScopeSpec::Adopt(NestedNameSpecifierLoc Other) { Range = Other.getSourceRange(); Builder.Adopt(Other); + assert(Range == Builder.getSourceRange() && + "NestedNameSpecifierLoc range computation incorrect"); } SourceLocation CXXScopeSpec::getLastQualifierNameLoc() const { @@ -351,6 +360,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_half: case TST_int: case TST_int128: + case TST_extint: case TST_struct: case TST_interface: case TST_union: @@ -358,6 +368,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_unspecified: case TST_void: case TST_wchar: + case TST_BFloat16: #define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" return false; @@ -529,6 +540,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_char32: return "char32_t"; case DeclSpec::TST_int: return "int"; case DeclSpec::TST_int128: return "__int128"; + case DeclSpec::TST_extint: return "_ExtInt"; case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; @@ -555,6 +567,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; + case DeclSpec::TST_BFloat16: return "__bf16"; #define GENERIC_IMAGE_TYPE(ImgType, Id) \ case DeclSpec::TST_##ImgType##_t: \ return #ImgType "_t"; @@ -784,6 +797,15 @@ bool DeclSpec::SetTypeSpecType(TST T, SourceLocation TagKwLoc, return false; } +bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, + unsigned &DiagID, TemplateIdAnnotation *Rep, + const PrintingPolicy &Policy) { + assert(T == TST_auto || T == TST_decltype_auto); + ConstrainedAuto = true; + TemplateIdRep = Rep; + return SetTypeSpecType(T, Loc, PrevSpec, DiagID, Policy); +} + bool DeclSpec::SetTypeSpecType(TST T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, @@ -895,6 +917,27 @@ bool DeclSpec::SetTypeSpecError() { return false; } +bool DeclSpec::SetExtIntType(SourceLocation KWLoc, Expr *BitsExpr, + const char *&PrevSpec, unsigned &DiagID, + const PrintingPolicy &Policy) { + assert(BitsExpr && "no expression provided!"); + if (TypeSpecType == TST_error) + return false; + + if (TypeSpecType != TST_unspecified) { + PrevSpec = DeclSpec::getSpecifierName((TST) TypeSpecType, Policy); + DiagID = diag::err_invalid_decl_spec_combination; + return true; + } + + TypeSpecType = TST_extint; + ExprRep = BitsExpr; + TSTLoc = KWLoc; + TSTNameLoc = KWLoc; + TypeSpecOwned = false; + return false; +} + bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const LangOptions &Lang) { // Duplicates are permitted in C99 onwards, but are not permitted in C89 or @@ -1107,14 +1150,20 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { S.Diag(TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } - - // Only char/int are valid with vector bool. (PIM 2.1) + // Only char/int are valid with vector bool prior to Power10. + // Power10 adds instructions that produce vector bool data + // for quadwords as well so allow vector bool __int128. if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && - (TypeSpecType != TST_int)) || TypeAltiVecPixel) { + (TypeSpecType != TST_int) && (TypeSpecType != TST_int128)) || + TypeAltiVecPixel) { S.Diag(TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType, Policy)); } + // vector bool __int128 requires Power10. + if ((TypeSpecType == TST_int128) && + (!S.Context.getTargetInfo().hasFeature("power10-vector"))) + S.Diag(TSTLoc, diag::err_invalid_vector_bool_int128_decl_spec); // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) && @@ -1131,7 +1180,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || - (TypeSpecWidth != TSW_unspecified)) + (TypeSpecType == TST_int128) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } else if (TypeSpecType == TST_double) { // vector long double and vector long long double are never allowed. @@ -1176,7 +1225,7 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && TypeSpecType != TST_char && TypeSpecType != TST_wchar && - !IsFixedPointType) { + !IsFixedPointType && TypeSpecType != TST_extint) { S.Diag(TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType, Policy); // signed double -> double. @@ -1223,11 +1272,13 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { S.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. - } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { + } else if (TypeSpecType == TST_int || TypeSpecType == TST_char || + TypeSpecType == TST_extint) { // Note that this intentionally doesn't include _Complex _Bool. if (!S.getLangOpts().CPlusPlus) S.Diag(TSTLoc, diag::ext_integer_complex); - } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { + } else if (TypeSpecType != TST_float && TypeSpecType != TST_double && + TypeSpecType != TST_float128) { S.Diag(TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecComplex = TSC_unspecified; diff --git a/clang/lib/Sema/JumpDiagnostics.cpp b/clang/lib/Sema/JumpDiagnostics.cpp index 960e62d4a2db..b34243edea35 100644 --- a/clang/lib/Sema/JumpDiagnostics.cpp +++ b/clang/lib/Sema/JumpDiagnostics.cpp @@ -75,6 +75,7 @@ private: void BuildScopeInformation(Decl *D, unsigned &ParentScope); void BuildScopeInformation(VarDecl *D, const BlockDecl *BDecl, unsigned &ParentScope); + void BuildScopeInformation(CompoundLiteralExpr *CLE, unsigned &ParentScope); void BuildScopeInformation(Stmt *S, unsigned &origParentScope); void VerifyJumps(); @@ -276,6 +277,16 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D, } } +/// Build scope information for compound literals of C struct types that are +/// non-trivial to destruct. +void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE, + unsigned &ParentScope) { + unsigned InDiag = diag::note_enters_compound_literal_scope; + unsigned OutDiag = diag::note_exits_compound_literal_scope; + Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc())); + ParentScope = Scopes.size() - 1; +} + /// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively @@ -529,11 +540,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // implementable but a lot of work which we haven't felt up to doing. ExprWithCleanups *EWC = cast<ExprWithCleanups>(S); for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { - const BlockDecl *BDecl = EWC->getObject(i); - for (const auto &CI : BDecl->captures()) { - VarDecl *variable = CI.getVariable(); - BuildScopeInformation(variable, BDecl, origParentScope); - } + if (auto *BDecl = EWC->getObject(i).dyn_cast<BlockDecl *>()) + for (const auto &CI : BDecl->captures()) { + VarDecl *variable = CI.getVariable(); + BuildScopeInformation(variable, BDecl, origParentScope); + } + else if (auto *CLE = EWC->getObject(i).dyn_cast<CompoundLiteralExpr *>()) + BuildScopeInformation(CLE, origParentScope); + else + llvm_unreachable("unexpected cleanup object type"); } break; } diff --git a/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 2b0cd6b8c4fc..80333e63127e 100644 --- a/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -275,6 +275,12 @@ void MultiplexExternalSemaSource::ReadExtVectorDecls( Sources[i]->ReadExtVectorDecls(Decls); } +void MultiplexExternalSemaSource::ReadDeclsToCheckForDeferredDiags( + llvm::SmallVector<Decl *, 4> &Decls) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->ReadDeclsToCheckForDeferredDiags(Decls); +} + void MultiplexExternalSemaSource::ReadUnusedLocalTypedefNameCandidates( llvm::SmallSetVector<const TypedefNameDecl *, 4> &Decls) { for(size_t i = 0; i < Sources.size(); ++i) diff --git a/clang/lib/Sema/OpenCLBuiltins.td b/clang/lib/Sema/OpenCLBuiltins.td index 9d6bb411eff8..745363a6b43f 100644 --- a/clang/lib/Sema/OpenCLBuiltins.td +++ b/clang/lib/Sema/OpenCLBuiltins.td @@ -60,10 +60,17 @@ def FuncExtKhrLocalInt32ExtendedAtomics : FunctionExtension<"cl_khr_local_int32 def FuncExtKhrInt64BaseAtomics : FunctionExtension<"cl_khr_int64_base_atomics">; def FuncExtKhrInt64ExtendedAtomics : FunctionExtension<"cl_khr_int64_extended_atomics">; def FuncExtKhrMipmapImage : FunctionExtension<"cl_khr_mipmap_image">; +def FuncExtKhrMipmapImageWrites : FunctionExtension<"cl_khr_mipmap_image_writes">; def FuncExtKhrGlMsaaSharing : FunctionExtension<"cl_khr_gl_msaa_sharing">; // Multiple extensions -def FuncExtKhrMipmapAndWrite3d : FunctionExtension<"cl_khr_mipmap_image cl_khr_3d_image_writes">; +def FuncExtKhrMipmapWritesAndWrite3d : FunctionExtension<"cl_khr_mipmap_image_writes cl_khr_3d_image_writes">; + +// Arm extensions. +def ArmIntegerDotProductInt8 : FunctionExtension<"cl_arm_integer_dot_product_int8">; +def ArmIntegerDotProductAccumulateInt8 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_int8">; +def ArmIntegerDotProductAccumulateInt16 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_int16">; +def ArmIntegerDotProductAccumulateSaturateInt8 : FunctionExtension<"cl_arm_integer_dot_product_accumulate_saturate_int8">; // Qualified Type. These map to ASTContext::QualType. class QualType<string _Name, bit _IsAbstract=0> { @@ -120,7 +127,7 @@ class VectorType<Type _Ty, int _VecWidth> : Type<_Ty.Name, _Ty.QTName> { // OpenCL pointer types (e.g. int*, float*, ...). class PointerType<Type _Ty, AddressSpace _AS = DefaultAS> : - Type<_Ty.Name, _Ty.QTName> { + Type<_Ty.Name, _Ty.QTName> { let AddrSpace = _AS.Name; // Inherited fields let VecWidth = _Ty.VecWidth; @@ -154,7 +161,7 @@ class VolatileType<Type _Ty> : Type<_Ty.Name, _Ty.QTName> { // OpenCL image types (e.g. image2d). class ImageType<Type _Ty, string _AccessQualifier> : - Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> { + Type<_Ty.Name, QualType<_Ty.QTName.Name#_AccessQualifier#"Ty", 0>> { let VecWidth = 0; let AccessQualifier = _AccessQualifier; // Inherited fields @@ -165,8 +172,7 @@ class ImageType<Type _Ty, string _AccessQualifier> : } // List of Types. -class TypeList<string _Name, list<Type> _Type> { - string Name = _Name; +class TypeList<list<Type> _Type> { list<Type> List = _Type; } @@ -195,7 +201,7 @@ class TypeList<string _Name, list<Type> _Type> { // A declaration f(GenT, SGenT) results in the combinations // f(half, half), f(half2, half), f(int, int), f(int2, int) . class GenericType<string _Ty, TypeList _TypeList, IntList _VectorList> : - Type<_Ty, QualType<"null", 1>> { + Type<_Ty, QualType<"null", 1>> { // Possible element types of the generic type. TypeList TypeList = _TypeList; // Possible vector sizes of the types in the TypeList. @@ -259,8 +265,8 @@ def Half : Type<"half", QualType<"HalfTy">>; def Size : Type<"size_t", QualType<"getSizeType()">>; def PtrDiff : Type<"ptrdiff_t", QualType<"getPointerDiffType()">>; def IntPtr : Type<"intptr_t", QualType<"getIntPtrType()">>; -def UIntPtr : Type<"uintPtr_t", QualType<"getUIntPtrType()">>; -def Void : Type<"void_t", QualType<"VoidTy">>; +def UIntPtr : Type<"uintptr_t", QualType<"getUIntPtrType()">>; +def Void : Type<"void", QualType<"VoidTy">>; // OpenCL v1.0/1.2/2.0 s6.1.2: Built-in Vector Data Types. // Built-in vector data types are created by TableGen's OpenCLBuiltinEmitter. @@ -268,21 +274,36 @@ def Void : Type<"void_t", QualType<"VoidTy">>; // OpenCL v1.0/1.2/2.0 s6.1.3: Other Built-in Data Types. // The image definitions are "abstract". They should not be used without // specifying an access qualifier (RO/WO/RW). -def Image1d : Type<"Image1d", QualType<"OCLImage1d", 1>>; -def Image2d : Type<"Image2d", QualType<"OCLImage2d", 1>>; -def Image3d : Type<"Image3d", QualType<"OCLImage3d", 1>>; -def Image1dArray : Type<"Image1dArray", QualType<"OCLImage1dArray", 1>>; -def Image1dBuffer : Type<"Image1dBuffer", QualType<"OCLImage1dBuffer", 1>>; -def Image2dArray : Type<"Image2dArray", QualType<"OCLImage2dArray", 1>>; -def Image2dDepth : Type<"Image2dDepth", QualType<"OCLImage2dDepth", 1>>; -def Image2dArrayDepth : Type<"Image2dArrayDepth", QualType<"OCLImage2dArrayDepth", 1>>; -def Image2dMsaa : Type<"Image2dMsaa", QualType<"OCLImage2dMSAA", 1>>; -def Image2dArrayMsaa : Type<"Image2dArrayMsaa", QualType<"OCLImage2dArrayMSAA", 1>>; -def Image2dMsaaDepth : Type<"Image2dMsaaDepth", QualType<"OCLImage2dMSAADepth", 1>>; -def Image2dArrayMsaaDepth : Type<"Image2dArrayMsaaDepth", QualType<"OCLImage2dArrayMSAADepth", 1>>; - -def Sampler : Type<"Sampler", QualType<"OCLSamplerTy">>; -def Event : Type<"Event", QualType<"OCLEventTy">>; +def Image1d : Type<"image1d_t", QualType<"OCLImage1d", 1>>; +def Image2d : Type<"image2d_t", QualType<"OCLImage2d", 1>>; +def Image3d : Type<"image3d_t", QualType<"OCLImage3d", 1>>; +def Image1dArray : Type<"image1d_array_t", QualType<"OCLImage1dArray", 1>>; +def Image1dBuffer : Type<"image1d_buffer_t", QualType<"OCLImage1dBuffer", 1>>; +def Image2dArray : Type<"image2d_array_t", QualType<"OCLImage2dArray", 1>>; +def Image2dDepth : Type<"image2d_depth_t", QualType<"OCLImage2dDepth", 1>>; +def Image2dArrayDepth : Type<"image2d_array_depth_t", QualType<"OCLImage2dArrayDepth", 1>>; +def Image2dMsaa : Type<"image2d_msaa_t", QualType<"OCLImage2dMSAA", 1>>; +def Image2dArrayMsaa : Type<"image2d_array_msaa_t", QualType<"OCLImage2dArrayMSAA", 1>>; +def Image2dMsaaDepth : Type<"image2d_msaa_depth_t", QualType<"OCLImage2dMSAADepth", 1>>; +def Image2dArrayMsaaDepth : Type<"image2d_array_msaa_depth_t", QualType<"OCLImage2dArrayMSAADepth", 1>>; + +def Sampler : Type<"sampler_t", QualType<"OCLSamplerTy">>; +def ClkEvent : Type<"clk_event_t", QualType<"OCLClkEventTy">>; +def Event : Type<"event_t", QualType<"OCLEventTy">>; +def Queue : Type<"queue_t", QualType<"OCLQueueTy">>; +def ReserveId : Type<"reserve_id_t", QualType<"OCLReserveIDTy">>; + +// OpenCL v2.0 s6.13.11: Atomic integer and floating-point types. +def AtomicInt : Type<"atomic_int", QualType<"getAtomicType(Context.IntTy)">>; +def AtomicUInt : Type<"atomic_uint", QualType<"getAtomicType(Context.UnsignedIntTy)">>; +def AtomicLong : Type<"atomic_long", QualType<"getAtomicType(Context.LongTy)">>; +def AtomicULong : Type<"atomic_ulong", QualType<"getAtomicType(Context.UnsignedLongTy)">>; +def AtomicFloat : Type<"atomic_float", QualType<"getAtomicType(Context.FloatTy)">>; +def AtomicDouble : Type<"atomic_double", QualType<"getAtomicType(Context.DoubleTy)">>; +def AtomicIntPtr : Type<"atomic_intptr_t", QualType<"getAtomicType(Context.getIntPtrType())">>; +def AtomicUIntPtr : Type<"atomic_uintptr_t", QualType<"getAtomicType(Context.getUIntPtrType())">>; +def AtomicSize : Type<"atomic_size_t", QualType<"getAtomicType(Context.getSizeType())">>; +def AtomicPtrDiff : Type<"atomic_ptrdiff_t", QualType<"getAtomicType(Context.getPointerDiffType())">>; //===----------------------------------------------------------------------===// // Definitions of OpenCL gentype variants @@ -305,20 +326,20 @@ def Vec16 : IntList<"Vec16", [16]>; def Vec1234 : IntList<"Vec1234", [1, 2, 3, 4]>; // Type lists. -def TLAll : TypeList<"TLAll", [Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; -def TLAllUnsigned : TypeList<"TLAllUnsigned", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>; -def TLFloat : TypeList<"TLFloat", [Float, Double, Half]>; -def TLSignedInts : TypeList<"TLSignedInts", [Char, Short, Int, Long]>; -def TLUnsignedInts : TypeList<"TLUnsignedInts", [UChar, UShort, UInt, ULong]>; +def TLAll : TypeList<[Char, UChar, Short, UShort, Int, UInt, Long, ULong, Float, Double, Half]>; +def TLAllUnsigned : TypeList<[UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong, UInt, ULong, UShort]>; +def TLFloat : TypeList<[Float, Double, Half]>; +def TLSignedInts : TypeList<[Char, Short, Int, Long]>; +def TLUnsignedInts : TypeList<[UChar, UShort, UInt, ULong]>; -def TLIntLongFloats : TypeList<"TLIntLongFloats", [Int, UInt, Long, ULong, Float, Double, Half]>; +def TLIntLongFloats : TypeList<[Int, UInt, Long, ULong, Float, Double, Half]>; // All unsigned integer types twice, to facilitate unsigned return types for e.g. // uchar abs(char) and // uchar abs(uchar). -def TLAllUIntsTwice : TypeList<"TLAllUIntsTwice", [UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>; +def TLAllUIntsTwice : TypeList<[UChar, UChar, UShort, UShort, UInt, UInt, ULong, ULong]>; -def TLAllInts : TypeList<"TLAllInts", [Char, UChar, Short, UShort, Int, UInt, Long, ULong]>; +def TLAllInts : TypeList<[Char, UChar, Short, UShort, Int, UInt, Long, ULong]>; // GenType definitions for multiple base types (e.g. all floating point types, // or all integer types). @@ -348,8 +369,7 @@ foreach Type = [Char, UChar, Short, UShort, foreach VecSizes = [VecAndScalar, VecNoScalar] in { def "GenType" # Type # VecSizes : GenericType<"GenType" # Type # VecSizes, - TypeList<"GL" # Type.Name, [Type]>, - VecSizes>; + TypeList<[Type]>, VecSizes>; } } @@ -357,8 +377,7 @@ foreach Type = [Char, UChar, Short, UShort, foreach Type = [Float, Double, Half] in { def "GenType" # Type # Vec1234 : GenericType<"GenType" # Type # Vec1234, - TypeList<"GL" # Type.Name, [Type]>, - Vec1234>; + TypeList<[Type]>, Vec1234>; } @@ -374,7 +393,11 @@ foreach RType = [Float, Double, Half, Char, UChar, Short, UShort, Int, UInt, Long, ULong] in { foreach IType = [Float, Double, Half, Char, UChar, Short, UShort, Int, UInt, Long, ULong] in { - foreach sat = ["", "_sat"] in { + // Conversions to integer type have a sat and non-sat variant. + foreach sat = !cond(!eq(RType.Name, "float") : [""], + !eq(RType.Name, "double") : [""], + !eq(RType.Name, "half") : [""], + 1 : ["", "_sat"]) in { foreach rnd = ["", "_rte", "_rtn", "_rtp", "_rtz"] in { def : Builtin<"convert_" # RType.Name # sat # rnd, [RType, IType], Attr.Const>; @@ -667,7 +690,7 @@ foreach name = ["isfinite", "isinf", "isnan", "isnormal", "signbit"] in { def : Builtin<name, [GenTypeShortVecNoScalar, GenTypeHalfVecNoScalar], Attr.Const>; } foreach name = ["any", "all"] in { - def : Builtin<name, [Int, AIGenTypeN], Attr.Const>; + def : Builtin<name, [Int, SGenTypeN], Attr.Const>; } // --- 2 arguments --- @@ -722,17 +745,17 @@ let MaxVersion = CL20 in { def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>; } foreach name = ["vstore" # VSize] in { - def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, AS>]>; - def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, AS>]>; - def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, AS>]>; - def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, AS>]>; - def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, AS>]>; - def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, AS>]>; - def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, AS>]>; - def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, AS>]>; - def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, AS>]>; - def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, AS>]>; - def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, AS>]>; + def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<Char, AS>]>; + def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<UChar, AS>]>; + def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<Short, AS>]>; + def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<UShort, AS>]>; + def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<Int, AS>]>; + def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<UInt, AS>]>; + def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<Long, AS>]>; + def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ULong, AS>]>; + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Float, AS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Double, AS>]>; + def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<Half, AS>]>; } foreach name = ["vloada_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; @@ -764,17 +787,17 @@ let MinVersion = CL20 in { def : Builtin<name, [VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; } foreach name = ["vstore" # VSize] in { - def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<ConstType<Char>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<ConstType<UChar>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<ConstType<Short>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<ConstType<UShort>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<ConstType<Int>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<ConstType<UInt>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<ConstType<Long>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ConstType<ULong>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<ConstType<Float>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<ConstType<Double>, GenericAS>]>; - def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Char, VSize>, Size, PointerType<Char, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UChar, VSize>, Size, PointerType<UChar, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Short, VSize>, Size, PointerType<Short, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UShort, VSize>, Size, PointerType<UShort, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Int, VSize>, Size, PointerType<Int, GenericAS>]>; + def : Builtin<name, [Void, VectorType<UInt, VSize>, Size, PointerType<UInt, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Long, VSize>, Size, PointerType<Long, GenericAS>]>; + def : Builtin<name, [Void, VectorType<ULong, VSize>, Size, PointerType<ULong, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Float, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Double, GenericAS>]>; + def : Builtin<name, [Void, VectorType<Half, VSize>, Size, PointerType<Half, GenericAS>]>; } foreach name = ["vloada_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, GenericAS>]>; @@ -805,24 +828,21 @@ foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vloada_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, ConstantAS>]>; } - foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - foreach name = ["vstorea_half" # VSize # rnd] in { - def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, ConstantAS>]>; - def : Builtin<name, [Void, VectorType<Double, VSize>, Size, PointerType<Half, ConstantAS>]>; - } - } } let MaxVersion = CL20 in { foreach AS = [GlobalAS, LocalAS, PrivateAS] in { def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vload_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; } } foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>; - def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>; + foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in { + def : Builtin<name, [Void, Float, Size, PointerType<Half, AS>]>; + def : Builtin<name, [Void, Double, Size, PointerType<Half, AS>]>; + } foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vstore_half" # VSize # rnd] in { def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>; @@ -835,14 +855,17 @@ let MaxVersion = CL20 in { let MinVersion = CL20 in { foreach AS = [GenericAS] in { def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vload_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; } } foreach rnd = ["", "_rte", "_rtz", "_rtp", "_rtn"] in { - def : Builtin<"vstore_half" # rnd, [Void, Float, Size, PointerType<Half, AS>]>; - def : Builtin<"vstore_half" # rnd, [Void, Double, Size, PointerType<Half, AS>]>; + foreach name = ["vstore_half" # rnd, "vstorea_half" # rnd] in { + def : Builtin<name, [Void, Float, Size, PointerType<Half, AS>]>; + def : Builtin<name, [Void, Double, Size, PointerType<Half, AS>]>; + } foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vstore_half" # VSize # rnd] in { def : Builtin<name, [Void, VectorType<Float, VSize>, Size, PointerType<Half, AS>]>; @@ -855,6 +878,7 @@ let MinVersion = CL20 in { foreach AS = [ConstantAS] in { def : Builtin<"vload_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; + def : Builtin<"vloada_half", [Float, Size, PointerType<ConstType<Half>, AS>]>; foreach VSize = [2, 3, 4, 8, 16] in { foreach name = ["vload_half" # VSize] in { def : Builtin<name, [VectorType<Float, VSize>, Size, PointerType<ConstType<Half>, AS>]>; @@ -976,6 +1000,45 @@ foreach AS = [GlobalAS, LocalAS] in { } } } +// OpenCL v2.0 s6.13.11 - Atomic Functions. +let MinVersion = CL20 in { + foreach TypePair = [[AtomicInt, Int], [AtomicUInt, UInt], + [AtomicLong, Long], [AtomicULong, ULong], + [AtomicFloat, Float], [AtomicDouble, Double]] in { + def : Builtin<"atomic_init", + [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>; + def : Builtin<"atomic_store", + [Void, PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>; + def : Builtin<"atomic_load", + [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>]>; + def : Builtin<"atomic_exchange", + [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[1]]>; + foreach Variant = ["weak", "strong"] in { + def : Builtin<"atomic_compare_exchange_" # Variant, + [Bool, PointerType<VolatileType<TypePair[0]>, GenericAS>, + PointerType<TypePair[1], GenericAS>, TypePair[1]]>; + } + } + + foreach TypePair = [[AtomicInt, Int, Int], [AtomicUInt, UInt, UInt], + [AtomicLong, Long, Long], [AtomicULong, ULong, ULong], + [AtomicIntPtr, IntPtr, PtrDiff], + [AtomicUIntPtr, UIntPtr, PtrDiff]] in { + foreach ModOp = ["add", "sub"] in { + def : Builtin<"atomic_fetch_" # ModOp, + [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>; + } + } + foreach TypePair = [[AtomicInt, Int, Int], [AtomicUInt, UInt, UInt], + [AtomicLong, Long, Long], [AtomicULong, ULong, ULong], + [AtomicIntPtr, IntPtr, IntPtr], + [AtomicUIntPtr, UIntPtr, UIntPtr]] in { + foreach ModOp = ["or", "xor", "and", "min", "max"] in { + def : Builtin<"atomic_fetch_" # ModOp, + [TypePair[1], PointerType<VolatileType<TypePair[0]>, GenericAS>, TypePair[2]]>; + } + } +} //-------------------------------------------------------------------- // OpenCL v1.1 s6.11.12, v1.2 s6.12.12, v2.0 s6.13.12 - Miscellaneous Vector Functions @@ -1172,14 +1235,43 @@ let MinVersion = CL20 in { } -// OpenCL v2.0 s9.17.3: Additions to section 6.13.1: Work-Item Functions -let MinVersion = CL20 in { - let Extension = FuncExtKhrSubgroups in { - def get_sub_group_size : Builtin<"get_sub_group_size", [UInt]>; - def get_max_sub_group_size : Builtin<"get_max_sub_group_size", [UInt]>; - def get_num_sub_groups : Builtin<"get_num_sub_groups", [UInt]>; - } -} +//-------------------------------------------------------------------- +// OpenCL2.0 : 6.13.16 : Pipe Functions +// --- Table 27 --- +// Defined in Builtins.def + +// --- Table 28 --- +// Builtins taking pipe arguments are defined in Builtins.def +def : Builtin<"is_valid_reserve_id", [Bool, ReserveId]>; + +// --- Table 29 --- +// Defined in Builtins.def + + +//-------------------------------------------------------------------- +// OpenCL2.0 : 6.13.17 : Enqueuing Kernels +// --- Table 30 --- +// Defined in Builtins.def + +// --- Table 32 --- +// Defined in Builtins.def + +// --- Table 33 --- +def : Builtin<"enqueue_marker", + [Int, Queue, UInt, PointerType<ConstType<ClkEvent>, GenericAS>, PointerType<ClkEvent, GenericAS>]>; + +// --- Table 34 --- +def : Builtin<"retain_event", [Void, ClkEvent]>; +def : Builtin<"release_event", [Void, ClkEvent]>; +def : Builtin<"create_user_event", [ClkEvent]>; +def : Builtin<"is_valid_event", [Bool, ClkEvent]>; +def : Builtin<"set_user_event_status", [Void, ClkEvent, Int]>; +// TODO: capture_event_profiling_info + +// --- Table 35 --- +def : Builtin<"get_default_queue", [Queue]>; +// TODO: ndrange functions + //-------------------------------------------------------------------- // End of the builtin functions defined in the OpenCL C specification. @@ -1274,6 +1366,16 @@ let Extension = FuncExtKhrMipmapImage in { } } } + // Added to section 6.13.14.5 + foreach aQual = ["RO", "WO", "RW"] in { + foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { + def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>; + } + } +} + +// Write functions are enabled using a separate extension. +let Extension = FuncExtKhrMipmapImageWrites in { // Added to section 6.13.14.4. foreach aQual = ["WO"] in { foreach imgTy = [Image2d] in { @@ -1298,7 +1400,7 @@ let Extension = FuncExtKhrMipmapImage in { def : Builtin<"write_imageui", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<UInt, 4>]>; } def : Builtin<"write_imagef", [Void, ImageType<Image2dArrayDepth, aQual>, VectorType<Int, 4>, Int, Float]>; - let Extension = FuncExtKhrMipmapAndWrite3d in { + let Extension = FuncExtKhrMipmapWritesAndWrite3d in { foreach imgTy = [Image3d] in { def : Builtin<"write_imagef", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Float, 4>]>; def : Builtin<"write_imagei", [Void, ImageType<imgTy, aQual>, VectorType<Int, 4>, Int, VectorType<Int, 4>]>; @@ -1306,15 +1408,8 @@ let Extension = FuncExtKhrMipmapImage in { } } } - // Added to section 6.13.14.5 - foreach aQual = ["RO", "WO", "RW"] in { - foreach imgTy = [Image1d, Image2d, Image3d, Image1dArray, Image2dArray, Image2dDepth, Image2dArrayDepth] in { - def : Builtin<"get_image_num_mip_levels", [Int, ImageType<imgTy, aQual>]>; - } - } } - //-------------------------------------------------------------------- // OpenCL Extension v2.0 s18.3 - Creating OpenCL Memory Objects from OpenGL MSAA Textures let Extension = FuncExtKhrGlMsaaSharing in { @@ -1346,6 +1441,70 @@ let Extension = FuncExtKhrGlMsaaSharing in { } def : Builtin<"get_image_dim", [VectorType<Int, 2>, ImageType<imgTy, aQual>], Attr.Const>; } - def : Builtin<"get_image_array_size", [Size, ImageType<Image2dArrayMsaaDepth, aQual>], Attr.Const>; + foreach imgTy = [Image2dArrayMsaa, Image2dArrayMsaaDepth] in { + def : Builtin<"get_image_array_size", [Size, ImageType<imgTy, aQual>], Attr.Const>; + } + } +} + +//-------------------------------------------------------------------- +// OpenCL Extension v2.0 s28 - Subgroups +// --- Table 28.2.1 --- +let Extension = FuncExtKhrSubgroups in { + foreach name = ["get_sub_group_size", "get_max_sub_group_size", + "get_num_sub_groups", "get_sub_group_id", + "get_sub_group_local_id"] in { + def : Builtin<name, [UInt]>; + } + let MinVersion = CL20 in { + foreach name = ["get_enqueued_num_sub_groups"] in { + def : Builtin<name, [UInt]>; + } + } +} + +// --- Table 28.2.2 --- +// TODO: sub_group_barrier + +// --- Table 28.2.4 --- +let Extension = FuncExtKhrSubgroups in { + foreach name = ["sub_group_all", "sub_group_any"] in { + def : Builtin<name, [Int, Int], Attr.Convergent>; + } + foreach name = ["sub_group_broadcast"] in { + def : Builtin<name, [IntLongFloatGenType1, IntLongFloatGenType1, UInt], Attr.Convergent>; + } + foreach name = ["sub_group_reduce_", "sub_group_scan_exclusive_", + "sub_group_scan_inclusive_"] in { + foreach op = ["add", "min", "max"] in { + def : Builtin<name # op, [IntLongFloatGenType1, IntLongFloatGenType1], Attr.Convergent>; + } + } +} + +//-------------------------------------------------------------------- +// Arm extensions. +let Extension = ArmIntegerDotProductInt8 in { + foreach name = ["arm_dot"] in { + def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>]>; + def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>]>; + } +} +let Extension = ArmIntegerDotProductAccumulateInt8 in { + foreach name = ["arm_dot_acc"] in { + def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>, UInt]>; + def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>, Int]>; + } +} +let Extension = ArmIntegerDotProductAccumulateInt16 in { + foreach name = ["arm_dot_acc"] in { + def : Builtin<name, [UInt, VectorType<UShort, 2>, VectorType<UShort, 2>, UInt]>; + def : Builtin<name, [Int, VectorType<Short, 2>, VectorType<Short, 2>, Int]>; + } +} +let Extension = ArmIntegerDotProductAccumulateSaturateInt8 in { + foreach name = ["arm_dot_acc_sat"] in { + def : Builtin<name, [UInt, VectorType<UChar, 4>, VectorType<UChar, 4>, UInt]>; + def : Builtin<name, [Int, VectorType<Char, 4>, VectorType<Char, 4>, Int]>; } } diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 5d0a734f237a..3ef8498baffd 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -19,12 +19,15 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" +#include "llvm/Support/ManagedStatic.h" #include <cassert> #include <cstddef> #include <utility> using namespace clang; +LLVM_INSTANTIATE_REGISTRY(ParsedAttrInfoRegistry) + IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, IdentifierInfo *Ident) { IdentifierLoc *Result = new (Ctx) IdentifierLoc; @@ -100,47 +103,60 @@ void AttributePool::takePool(AttributePool &pool) { pool.Attrs.clear(); } -struct ParsedAttrInfo { - unsigned NumArgs : 4; - unsigned OptArgs : 4; - unsigned HasCustomParsing : 1; - unsigned IsTargetSpecific : 1; - unsigned IsType : 1; - unsigned IsStmt : 1; - unsigned IsKnownToGCC : 1; - unsigned IsSupportedByPragmaAttribute : 1; - - bool (*DiagAppertainsToDecl)(Sema &S, const ParsedAttr &Attr, const Decl *); - bool (*DiagLangOpts)(Sema &S, const ParsedAttr &Attr); - bool (*ExistsInTarget)(const TargetInfo &Target); - unsigned (*SpellingIndexToSemanticSpelling)(const ParsedAttr &Attr); - void (*GetPragmaAttributeMatchRules)( - llvm::SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &Rules, - const LangOptions &LangOpts); -}; - namespace { #include "clang/Sema/AttrParsedAttrImpl.inc" } // namespace -static const ParsedAttrInfo &getInfo(const ParsedAttr &A) { - return AttrInfoMap[A.getKind()]; +const ParsedAttrInfo &ParsedAttrInfo::get(const AttributeCommonInfo &A) { + // If we have a ParsedAttrInfo for this ParsedAttr then return that. + if ((size_t)A.getParsedKind() < llvm::array_lengthof(AttrInfoMap)) + return *AttrInfoMap[A.getParsedKind()]; + + // If this is an ignored attribute then return an appropriate ParsedAttrInfo. + static const ParsedAttrInfo IgnoredParsedAttrInfo( + AttributeCommonInfo::IgnoredAttribute); + if (A.getParsedKind() == AttributeCommonInfo::IgnoredAttribute) + return IgnoredParsedAttrInfo; + + // Otherwise this may be an attribute defined by a plugin. First instantiate + // all plugin attributes if we haven't already done so. + static llvm::ManagedStatic<std::list<std::unique_ptr<ParsedAttrInfo>>> + PluginAttrInstances; + if (PluginAttrInstances->empty()) + for (auto It : ParsedAttrInfoRegistry::entries()) + PluginAttrInstances->emplace_back(It.instantiate()); + + // Search for a ParsedAttrInfo whose name and syntax match. + std::string FullName = A.getNormalizedFullName(); + AttributeCommonInfo::Syntax SyntaxUsed = A.getSyntax(); + if (SyntaxUsed == AttributeCommonInfo::AS_ContextSensitiveKeyword) + SyntaxUsed = AttributeCommonInfo::AS_Keyword; + + for (auto &Ptr : *PluginAttrInstances) + for (auto &S : Ptr->Spellings) + if (S.Syntax == SyntaxUsed && S.NormalizedFullName == FullName) + return *Ptr; + + // If we failed to find a match then return a default ParsedAttrInfo. + static const ParsedAttrInfo DefaultParsedAttrInfo( + AttributeCommonInfo::UnknownAttribute); + return DefaultParsedAttrInfo; } -unsigned ParsedAttr::getMinArgs() const { return getInfo(*this).NumArgs; } +unsigned ParsedAttr::getMinArgs() const { return getInfo().NumArgs; } unsigned ParsedAttr::getMaxArgs() const { - return getMinArgs() + getInfo(*this).OptArgs; + return getMinArgs() + getInfo().OptArgs; } bool ParsedAttr::hasCustomParsing() const { - return getInfo(*this).HasCustomParsing; + return getInfo().HasCustomParsing; } bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Decl *D) const { - return getInfo(*this).DiagAppertainsToDecl(S, *this, D); + return getInfo().diagAppertainsToDecl(S, *this, D); } bool ParsedAttr::appliesToDecl(const Decl *D, @@ -152,33 +168,33 @@ void ParsedAttr::getMatchRules( const LangOptions &LangOpts, SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> &MatchRules) const { - return getInfo(*this).GetPragmaAttributeMatchRules(MatchRules, LangOpts); + return getInfo().getPragmaAttributeMatchRules(MatchRules, LangOpts); } bool ParsedAttr::diagnoseLangOpts(Sema &S) const { - return getInfo(*this).DiagLangOpts(S, *this); + return getInfo().diagLangOpts(S, *this); } bool ParsedAttr::isTargetSpecificAttr() const { - return getInfo(*this).IsTargetSpecific; + return getInfo().IsTargetSpecific; } -bool ParsedAttr::isTypeAttr() const { return getInfo(*this).IsType; } +bool ParsedAttr::isTypeAttr() const { return getInfo().IsType; } -bool ParsedAttr::isStmtAttr() const { return getInfo(*this).IsStmt; } +bool ParsedAttr::isStmtAttr() const { return getInfo().IsStmt; } bool ParsedAttr::existsInTarget(const TargetInfo &Target) const { - return getInfo(*this).ExistsInTarget(Target); + return getInfo().existsInTarget(Target); } -bool ParsedAttr::isKnownToGCC() const { return getInfo(*this).IsKnownToGCC; } +bool ParsedAttr::isKnownToGCC() const { return getInfo().IsKnownToGCC; } bool ParsedAttr::isSupportedByPragmaAttribute() const { - return getInfo(*this).IsSupportedByPragmaAttribute; + return getInfo().IsSupportedByPragmaAttribute; } unsigned ParsedAttr::getSemanticSpelling() const { - return getInfo(*this).SpellingIndexToSemanticSpelling(*this); + return getInfo().spellingIndexToSemanticSpelling(*this); } bool ParsedAttr::hasVariadicArg() const { @@ -186,5 +202,5 @@ bool ParsedAttr::hasVariadicArg() const { // claim that as being variadic. If we someday get an attribute that // legitimately bumps up against that maximum, we can use another bit to track // whether it's truly variadic or not. - return getInfo(*this).OptArgs == 15; + return getInfo().OptArgs == 15; } diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 2cd158a8b43c..2f2b52106f3d 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "UsedDeclVisitor.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" @@ -22,6 +23,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/Stack.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" @@ -52,6 +54,21 @@ SourceLocation Sema::getLocForEndOfToken(SourceLocation Loc, unsigned Offset) { ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } +IdentifierInfo * +Sema::InventAbbreviatedTemplateParameterTypeName(IdentifierInfo *ParamName, + unsigned int Index) { + std::string InventedName; + llvm::raw_string_ostream OS(InventedName); + + if (!ParamName) + OS << "auto:" << Index + 1; + else + OS << ParamName->getName() << ":auto"; + + OS.flush(); + return &Context.Idents.get(OS.str()); +} + PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); @@ -127,10 +144,13 @@ public: } // end namespace sema } // end namespace clang +const unsigned Sema::MaxAlignmentExponent; +const unsigned Sema::MaximumAlignment; + Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TranslationUnitKind TUKind, CodeCompleteConsumer *CodeCompleter) : ExternalSource(nullptr), isMultiplexExternalSource(false), - FPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), + CurFPFeatures(pp.getLangOpts()), LangOpts(pp.getLangOpts()), PP(pp), Context(ctxt), Consumer(consumer), Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr), @@ -139,8 +159,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, LangOpts.getMSPointerToMemberRepresentationMethod()), VtorDispStack(LangOpts.getVtorDispMode()), PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), - CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), - PragmaAttributeCurrentTargetDecl(nullptr), + CodeSegStack(nullptr), FpPragmaStack(0xffffffff), CurInitSeg(nullptr), + VisContext(nullptr), PragmaAttributeCurrentTargetDecl(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), @@ -153,10 +173,10 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, TUKind(TUKind), NumSFINAEErrors(0), FullyCheckedComparisonCategories( static_cast<unsigned>(ComparisonCategoryType::Last) + 1), - AccessCheckingSFINAE(false), InNonInstantiationSFINAEContext(false), - NonInstantiationEntries(0), ArgumentPackSubstitutionIndex(-1), - CurrentInstantiationScope(nullptr), DisableTypoCorrection(false), - TyposCorrected(0), AnalysisWarnings(*this), + SatisfactionCache(Context), AccessCheckingSFINAE(false), + InNonInstantiationSFINAEContext(false), NonInstantiationEntries(0), + ArgumentPackSubstitutionIndex(-1), CurrentInstantiationScope(nullptr), + DisableTypoCorrection(false), TyposCorrected(0), AnalysisWarnings(*this), ThreadSafetyDeclCache(nullptr), VarDataSharingAttributesStack(nullptr), CurScope(nullptr), Ident_super(nullptr), Ident___float128(nullptr) { TUScope = nullptr; @@ -379,6 +399,14 @@ Sema::~Sema() { if (isMultiplexExternalSource) delete ExternalSource; + // Delete cached satisfactions. + std::vector<ConstraintSatisfaction *> Satisfactions; + Satisfactions.reserve(Satisfactions.size()); + for (auto &Node : SatisfactionCache) + Satisfactions.push_back(&Node); + for (auto *Node : Satisfactions) + delete Node; + threadSafety::threadSafetyCleanup(ThreadSafetyDeclCache); // Destroys data sharing attributes stack for OpenMP @@ -928,9 +956,7 @@ void Sema::ActOnEndOfTranslationUnitFragment(TUFragmentKind Kind) { PerformPendingInstantiations(); } - // Finalize analysis of OpenMP-specific constructs. - if (LangOpts.OpenMP) - finalizeOpenMPDelayedAnalysis(); + emitDeferredDiags(); assert(LateParsedInstantiations.empty() && "end of TU template instantiation should not create more " @@ -983,6 +1009,11 @@ void Sema::ActOnEndOfTranslationUnit() { LateParsedInstantiations.begin(), LateParsedInstantiations.end()); LateParsedInstantiations.clear(); + + if (LangOpts.PCHInstantiateTemplates) { + llvm::TimeTraceScope TimeScope("PerformPendingInstantiations"); + PerformPendingInstantiations(); + } } DiagnoseUnterminatedPragmaPack(); @@ -1261,7 +1292,8 @@ DeclContext *Sema::getFunctionLevelDeclContext() { DeclContext *DC = CurContext; while (true) { - if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC)) { + if (isa<BlockDecl>(DC) || isa<EnumDecl>(DC) || isa<CapturedDecl>(DC) || + isa<RequiresExprBodyDecl>(DC)) { DC = DC->getParent(); } else if (isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->getOverloadedOperator() == OO_Call && @@ -1413,38 +1445,184 @@ Sema::Diag(SourceLocation Loc, const PartialDiagnostic& PD) { static void emitCallStackNotes(Sema &S, FunctionDecl *FD) { auto FnIt = S.DeviceKnownEmittedFns.find(FD); while (FnIt != S.DeviceKnownEmittedFns.end()) { + // Respect error limit. + if (S.Diags.hasFatalErrorOccurred()) + return; DiagnosticBuilder Builder( S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); Builder << FnIt->second.FD; - Builder.setForceEmit(); - FnIt = S.DeviceKnownEmittedFns.find(FnIt->second.FD); } } -// Emit any deferred diagnostics for FD and erase them from the map in which -// they're stored. -static void emitDeferredDiags(Sema &S, FunctionDecl *FD, bool ShowCallStack) { - auto It = S.DeviceDeferredDiags.find(FD); - if (It == S.DeviceDeferredDiags.end()) - return; - bool HasWarningOrError = false; - for (PartialDiagnosticAt &PDAt : It->second) { - const SourceLocation &Loc = PDAt.first; - const PartialDiagnostic &PD = PDAt.second; - HasWarningOrError |= S.getDiagnostics().getDiagnosticLevel( - PD.getDiagID(), Loc) >= DiagnosticsEngine::Warning; - DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); - Builder.setForceEmit(); - PD.Emit(Builder); +namespace { + +/// Helper class that emits deferred diagnostic messages if an entity directly +/// or indirectly using the function that causes the deferred diagnostic +/// messages is known to be emitted. +/// +/// During parsing of AST, certain diagnostic messages are recorded as deferred +/// diagnostics since it is unknown whether the functions containing such +/// diagnostics will be emitted. A list of potentially emitted functions and +/// variables that may potentially trigger emission of functions are also +/// recorded. DeferredDiagnosticsEmitter recursively visits used functions +/// by each function to emit deferred diagnostics. +/// +/// During the visit, certain OpenMP directives or initializer of variables +/// with certain OpenMP attributes will cause subsequent visiting of any +/// functions enter a state which is called OpenMP device context in this +/// implementation. The state is exited when the directive or initializer is +/// exited. This state can change the emission states of subsequent uses +/// of functions. +/// +/// Conceptually the functions or variables to be visited form a use graph +/// where the parent node uses the child node. At any point of the visit, +/// the tree nodes traversed from the tree root to the current node form a use +/// stack. The emission state of the current node depends on two factors: +/// 1. the emission state of the root node +/// 2. whether the current node is in OpenMP device context +/// If the function is decided to be emitted, its contained deferred diagnostics +/// are emitted, together with the information about the use stack. +/// +class DeferredDiagnosticsEmitter + : public UsedDeclVisitor<DeferredDiagnosticsEmitter> { +public: + typedef UsedDeclVisitor<DeferredDiagnosticsEmitter> Inherited; + + // Whether the function is already in the current use-path. + llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> InUsePath; + + // The current use-path. + llvm::SmallVector<CanonicalDeclPtr<FunctionDecl>, 4> UsePath; + + // Whether the visiting of the function has been done. Done[0] is for the + // case not in OpenMP device context. Done[1] is for the case in OpenMP + // device context. We need two sets because diagnostics emission may be + // different depending on whether it is in OpenMP device context. + llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> DoneMap[2]; + + // Emission state of the root node of the current use graph. + bool ShouldEmitRootNode; + + // Current OpenMP device context level. It is initialized to 0 and each + // entering of device context increases it by 1 and each exit decreases + // it by 1. Non-zero value indicates it is currently in device context. + unsigned InOMPDeviceContext; + + DeferredDiagnosticsEmitter(Sema &S) + : Inherited(S), ShouldEmitRootNode(false), InOMPDeviceContext(0) {} + + void VisitOMPTargetDirective(OMPTargetDirective *Node) { + ++InOMPDeviceContext; + Inherited::VisitOMPTargetDirective(Node); + --InOMPDeviceContext; + } + + void visitUsedDecl(SourceLocation Loc, Decl *D) { + if (isa<VarDecl>(D)) + return; + if (auto *FD = dyn_cast<FunctionDecl>(D)) + checkFunc(Loc, FD); + else + Inherited::visitUsedDecl(Loc, D); + } + + void checkVar(VarDecl *VD) { + assert(VD->isFileVarDecl() && + "Should only check file-scope variables"); + if (auto *Init = VD->getInit()) { + auto DevTy = OMPDeclareTargetDeclAttr::getDeviceType(VD); + bool IsDev = DevTy && (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || + *DevTy == OMPDeclareTargetDeclAttr::DT_Any); + if (IsDev) + ++InOMPDeviceContext; + this->Visit(Init); + if (IsDev) + --InOMPDeviceContext; + } + } + + void checkFunc(SourceLocation Loc, FunctionDecl *FD) { + auto &Done = DoneMap[InOMPDeviceContext > 0 ? 1 : 0]; + FunctionDecl *Caller = UsePath.empty() ? nullptr : UsePath.back(); + if ((!ShouldEmitRootNode && !S.getLangOpts().OpenMP && !Caller) || + S.shouldIgnoreInHostDeviceCheck(FD) || InUsePath.count(FD)) + return; + // Finalize analysis of OpenMP-specific constructs. + if (Caller && S.LangOpts.OpenMP && UsePath.size() == 1) + S.finalizeOpenMPDelayedAnalysis(Caller, FD, Loc); + if (Caller) + S.DeviceKnownEmittedFns[FD] = {Caller, Loc}; + // Always emit deferred diagnostics for the direct users. This does not + // lead to explosion of diagnostics since each user is visited at most + // twice. + if (ShouldEmitRootNode || InOMPDeviceContext) + emitDeferredDiags(FD, Caller); + // Do not revisit a function if the function body has been completely + // visited before. + if (!Done.insert(FD).second) + return; + InUsePath.insert(FD); + UsePath.push_back(FD); + if (auto *S = FD->getBody()) { + this->Visit(S); + } + UsePath.pop_back(); + InUsePath.erase(FD); + } + + void checkRecordedDecl(Decl *D) { + if (auto *FD = dyn_cast<FunctionDecl>(D)) { + ShouldEmitRootNode = S.getEmissionStatus(FD, /*Final=*/true) == + Sema::FunctionEmissionStatus::Emitted; + checkFunc(SourceLocation(), FD); + } else + checkVar(cast<VarDecl>(D)); + } + + // Emit any deferred diagnostics for FD + void emitDeferredDiags(FunctionDecl *FD, bool ShowCallStack) { + auto It = S.DeviceDeferredDiags.find(FD); + if (It == S.DeviceDeferredDiags.end()) + return; + bool HasWarningOrError = false; + bool FirstDiag = true; + for (PartialDiagnosticAt &PDAt : It->second) { + // Respect error limit. + if (S.Diags.hasFatalErrorOccurred()) + return; + const SourceLocation &Loc = PDAt.first; + const PartialDiagnostic &PD = PDAt.second; + HasWarningOrError |= + S.getDiagnostics().getDiagnosticLevel(PD.getDiagID(), Loc) >= + DiagnosticsEngine::Warning; + { + DiagnosticBuilder Builder(S.Diags.Report(Loc, PD.getDiagID())); + PD.Emit(Builder); + } + // Emit the note on the first diagnostic in case too many diagnostics + // cause the note not emitted. + if (FirstDiag && HasWarningOrError && ShowCallStack) { + emitCallStackNotes(S, FD); + FirstDiag = false; + } + } } - S.DeviceDeferredDiags.erase(It); +}; +} // namespace + +void Sema::emitDeferredDiags() { + if (ExternalSource) + ExternalSource->ReadDeclsToCheckForDeferredDiags( + DeclsToCheckForDeferredDiags); + + if ((DeviceDeferredDiags.empty() && !LangOpts.OpenMP) || + DeclsToCheckForDeferredDiags.empty()) + return; - // FIXME: Should this be called after every warning/error emitted in the loop - // above, instead of just once per function? That would be consistent with - // how we handle immediate errors, but it also seems like a bit much. - if (HasWarningOrError && ShowCallStack) - emitCallStackNotes(S, FD); + DeferredDiagnosticsEmitter DDE(*this); + for (auto D : DeclsToCheckForDeferredDiags) + DDE.checkRecordedDecl(D); } // In CUDA, there are some constructs which may appear in semantically-valid @@ -1517,71 +1695,6 @@ Sema::DeviceDiagBuilder::~DeviceDiagBuilder() { } } -// Indicate that this function (and thus everything it transtively calls) will -// be codegen'ed, and emit any deferred diagnostics on this function and its -// (transitive) callees. -void Sema::markKnownEmitted( - Sema &S, FunctionDecl *OrigCaller, FunctionDecl *OrigCallee, - SourceLocation OrigLoc, - const llvm::function_ref<bool(Sema &, FunctionDecl *)> IsKnownEmitted) { - // Nothing to do if we already know that FD is emitted. - if (IsKnownEmitted(S, OrigCallee)) { - assert(!S.DeviceCallGraph.count(OrigCallee)); - return; - } - - // We've just discovered that OrigCallee is known-emitted. Walk our call - // graph to see what else we can now discover also must be emitted. - - struct CallInfo { - FunctionDecl *Caller; - FunctionDecl *Callee; - SourceLocation Loc; - }; - llvm::SmallVector<CallInfo, 4> Worklist = {{OrigCaller, OrigCallee, OrigLoc}}; - llvm::SmallSet<CanonicalDeclPtr<FunctionDecl>, 4> Seen; - Seen.insert(OrigCallee); - while (!Worklist.empty()) { - CallInfo C = Worklist.pop_back_val(); - assert(!IsKnownEmitted(S, C.Callee) && - "Worklist should not contain known-emitted functions."); - S.DeviceKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; - emitDeferredDiags(S, C.Callee, C.Caller); - - // If this is a template instantiation, explore its callgraph as well: - // Non-dependent calls are part of the template's callgraph, while dependent - // calls are part of to the instantiation's call graph. - if (auto *Templ = C.Callee->getPrimaryTemplate()) { - FunctionDecl *TemplFD = Templ->getAsFunction(); - if (!Seen.count(TemplFD) && !S.DeviceKnownEmittedFns.count(TemplFD)) { - Seen.insert(TemplFD); - Worklist.push_back( - {/* Caller = */ C.Caller, /* Callee = */ TemplFD, C.Loc}); - } - } - - // Add all functions called by Callee to our worklist. - auto CGIt = S.DeviceCallGraph.find(C.Callee); - if (CGIt == S.DeviceCallGraph.end()) - continue; - - for (std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> FDLoc : - CGIt->second) { - FunctionDecl *NewCallee = FDLoc.first; - SourceLocation CallLoc = FDLoc.second; - if (Seen.count(NewCallee) || IsKnownEmitted(S, NewCallee)) - continue; - Seen.insert(NewCallee); - Worklist.push_back( - {/* Caller = */ C.Callee, /* Callee = */ NewCallee, CallLoc}); - } - - // C.Callee is now known-emitted, so we no longer need to maintain its list - // of callees in DeviceCallGraph. - S.DeviceCallGraph.erase(CGIt); - } -} - Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { if (LangOpts.OpenMP) return LangOpts.OpenMPIsDevice ? diagIfOpenMPDeviceCode(Loc, DiagID) @@ -1589,10 +1702,59 @@ Sema::DeviceDiagBuilder Sema::targetDiag(SourceLocation Loc, unsigned DiagID) { if (getLangOpts().CUDA) return getLangOpts().CUDAIsDevice ? CUDADiagIfDeviceCode(Loc, DiagID) : CUDADiagIfHostCode(Loc, DiagID); + + if (getLangOpts().SYCLIsDevice) + return SYCLDiagIfDeviceCode(Loc, DiagID); + return DeviceDiagBuilder(DeviceDiagBuilder::K_Immediate, Loc, DiagID, getCurFunctionDecl(), *this); } +void Sema::checkDeviceDecl(const ValueDecl *D, SourceLocation Loc) { + if (isUnevaluatedContext()) + return; + + Decl *C = cast<Decl>(getCurLexicalContext()); + + // Memcpy operations for structs containing a member with unsupported type + // are ok, though. + if (const auto *MD = dyn_cast<CXXMethodDecl>(C)) { + if ((MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator()) && + MD->isTrivial()) + return; + + if (const auto *Ctor = dyn_cast<CXXConstructorDecl>(MD)) + if (Ctor->isCopyOrMoveConstructor() && Ctor->isTrivial()) + return; + } + + auto CheckType = [&](QualType Ty) { + if (Ty->isDependentType()) + return; + + if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || + ((Ty->isFloat128Type() || + (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) && + !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && + !Context.getTargetInfo().hasInt128Type())) { + targetDiag(Loc, diag::err_device_unsupported_type) + << D << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty + << Context.getTargetInfo().getTriple().str(); + targetDiag(D->getLocation(), diag::note_defined_here) << D; + } + }; + + QualType Ty = D->getType(); + CheckType(Ty); + + if (const auto *FPTy = dyn_cast<FunctionProtoType>(Ty)) { + for (const auto &ParamTy : FPTy->param_types()) + CheckType(ParamTy); + CheckType(FPTy->getReturnType()); + } +} + /// Looks through the macro-expansion chain for the given /// location, looking for a macro expansion with the given name. /// If one is found, returns true and sets the location to that @@ -1794,7 +1956,7 @@ void Sema::PopCompoundScope() { /// Determine whether any errors occurred within this function/method/ /// block. bool Sema::hasAnyUnrecoverableErrorsInThisFunction() const { - return getCurFunction()->ErrorTrap.hasUnrecoverableErrorOccurred(); + return getCurFunction()->hasUnrecoverableErrorOccurred(); } void Sema::setFunctionHasBranchIntoScope() { @@ -2246,16 +2408,8 @@ std::string Sema::getOpenCLExtensionsFromTypeExtMap(FunctionType *FT) { template <typename T, typename MapT> std::string Sema::getOpenCLExtensionsFromExtMap(T *FDT, MapT &Map) { - std::string ExtensionNames = ""; auto Loc = Map.find(FDT); - - for (auto const& I : Loc->second) { - ExtensionNames += I; - ExtensionNames += " "; - } - ExtensionNames.pop_back(); - - return ExtensionNames; + return llvm::join(Loc->second, " "); } bool Sema::isOpenCLDisabledDecl(Decl *FD) { diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index cd2a65276b09..b354e810974c 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -256,12 +256,15 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionAction Action, PragmaClangSectionKind SecKind, StringRef SecName) { PragmaClangSection *CSec; + int SectionFlags = ASTContext::PSF_Read; switch (SecKind) { case PragmaClangSectionKind::PCSK_BSS: CSec = &PragmaClangBSSSection; + SectionFlags |= ASTContext::PSF_Write | ASTContext::PSF_ZeroInit; break; case PragmaClangSectionKind::PCSK_Data: CSec = &PragmaClangDataSection; + SectionFlags |= ASTContext::PSF_Write; break; case PragmaClangSectionKind::PCSK_Rodata: CSec = &PragmaClangRodataSection; @@ -271,6 +274,7 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA break; case PragmaClangSectionKind::PCSK_Text: CSec = &PragmaClangTextSection; + SectionFlags |= ASTContext::PSF_Execute; break; default: llvm_unreachable("invalid clang section kind"); @@ -281,8 +285,11 @@ void Sema::ActOnPragmaClangSection(SourceLocation PragmaLoc, PragmaClangSectionA return; } + if (UnifySection(SecName, SectionFlags, PragmaLoc)) + return; + CSec->Valid = true; - CSec->SectionName = SecName; + CSec->SectionName = std::string(SecName); CSec->PragmaLocation = PragmaLoc; } @@ -407,6 +414,70 @@ void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD)); } +void Sema::ActOnPragmaFloatControl(SourceLocation Loc, + PragmaMsStackAction Action, + PragmaFloatControlKind Value) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + if ((Action == PSK_Push_Set || Action == PSK_Push || Action == PSK_Pop) && + !(CurContext->isTranslationUnit()) && !CurContext->isNamespace()) { + // Push and pop can only occur at file or namespace scope. + Diag(Loc, diag::err_pragma_fc_pp_scope); + return; + } + switch (Value) { + default: + llvm_unreachable("invalid pragma float_control kind"); + case PFC_Precise: + NewFPFeatures.setFPPreciseEnabled(true); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); + break; + case PFC_NoPrecise: + if (CurFPFeatures.getFPExceptionMode() == LangOptions::FPE_Strict) + Diag(Loc, diag::err_pragma_fc_noprecise_requires_noexcept); + else if (CurFPFeatures.getAllowFEnvAccess()) + Diag(Loc, diag::err_pragma_fc_noprecise_requires_nofenv); + else + NewFPFeatures.setFPPreciseEnabled(false); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); + break; + case PFC_Except: + if (!isPreciseFPEnabled()) + Diag(Loc, diag::err_pragma_fc_except_requires_precise); + else + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Strict); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); + break; + case PFC_NoExcept: + NewFPFeatures.setFPExceptionModeOverride(LangOptions::FPE_Ignore); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, Action, StringRef(), NewValue); + break; + case PFC_Push: + FpPragmaStack.Act(Loc, Sema::PSK_Push_Set, StringRef(), + NewFPFeatures.getAsOpaqueInt()); + break; + case PFC_Pop: + if (FpPragmaStack.Stack.empty()) { + Diag(Loc, diag::warn_pragma_pop_failed) << "float_control" + << "stack empty"; + return; + } + FpPragmaStack.Act(Loc, Action, StringRef(), NewFPFeatures.getAsOpaqueInt()); + NewValue = FpPragmaStack.CurrentValue; + break; + } + FPOptionsOverride NewOverrides; + if (NewValue != FpPragmaStack.DefaultValue) + NewOverrides.getFromOpaqueInt(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); +} + void Sema::ActOnPragmaMSPointersToMembers( LangOptions::PragmaMSPointersToMembersKind RepresentationMethod, SourceLocation PragmaLoc) { @@ -423,83 +494,52 @@ void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode); } -template<typename ValueType> -void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, - PragmaMsStackAction Action, - llvm::StringRef StackSlotLabel, - ValueType Value) { - if (Action == PSK_Reset) { - CurrentValue = DefaultValue; - CurrentPragmaLocation = PragmaLocation; - return; - } - if (Action & PSK_Push) - Stack.emplace_back(StackSlotLabel, CurrentValue, CurrentPragmaLocation, - PragmaLocation); - else if (Action & PSK_Pop) { - if (!StackSlotLabel.empty()) { - // If we've got a label, try to find it and jump there. - auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { - return x.StackSlotLabel == StackSlotLabel; - }); - // If we found the label so pop from there. - if (I != Stack.rend()) { - CurrentValue = I->Value; - CurrentPragmaLocation = I->PragmaLocation; - Stack.erase(std::prev(I.base()), Stack.end()); - } - } else if (!Stack.empty()) { - // We do not have a label, just pop the last entry. - CurrentValue = Stack.back().Value; - CurrentPragmaLocation = Stack.back().PragmaLocation; - Stack.pop_back(); - } - } - if (Action & PSK_Set) { - CurrentValue = Value; - CurrentPragmaLocation = PragmaLocation; - } -} - bool Sema::UnifySection(StringRef SectionName, int SectionFlags, DeclaratorDecl *Decl) { - auto Section = Context.SectionInfos.find(SectionName); - if (Section == Context.SectionInfos.end()) { + SourceLocation PragmaLocation; + if (auto A = Decl->getAttr<SectionAttr>()) + if (A->isImplicit()) + PragmaLocation = A->getLocation(); + auto SectionIt = Context.SectionInfos.find(SectionName); + if (SectionIt == Context.SectionInfos.end()) { Context.SectionInfos[SectionName] = - ASTContext::SectionInfo(Decl, SourceLocation(), SectionFlags); + ASTContext::SectionInfo(Decl, PragmaLocation, SectionFlags); return false; } // A pre-declared section takes precedence w/o diagnostic. - if (Section->second.SectionFlags == SectionFlags || - !(Section->second.SectionFlags & ASTContext::PSF_Implicit)) + const auto &Section = SectionIt->second; + if (Section.SectionFlags == SectionFlags || + ((SectionFlags & ASTContext::PSF_Implicit) && + !(Section.SectionFlags & ASTContext::PSF_Implicit))) return false; - auto OtherDecl = Section->second.Decl; - Diag(Decl->getLocation(), diag::err_section_conflict) - << Decl << OtherDecl; - Diag(OtherDecl->getLocation(), diag::note_declared_at) - << OtherDecl->getName(); - if (auto A = Decl->getAttr<SectionAttr>()) - if (A->isImplicit()) - Diag(A->getLocation(), diag::note_pragma_entered_here); - if (auto A = OtherDecl->getAttr<SectionAttr>()) - if (A->isImplicit()) - Diag(A->getLocation(), diag::note_pragma_entered_here); + Diag(Decl->getLocation(), diag::err_section_conflict) << Decl << Section; + if (Section.Decl) + Diag(Section.Decl->getLocation(), diag::note_declared_at) + << Section.Decl->getName(); + if (PragmaLocation.isValid()) + Diag(PragmaLocation, diag::note_pragma_entered_here); + if (Section.PragmaSectionLocation.isValid()) + Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here); return true; } bool Sema::UnifySection(StringRef SectionName, int SectionFlags, SourceLocation PragmaSectionLocation) { - auto Section = Context.SectionInfos.find(SectionName); - if (Section != Context.SectionInfos.end()) { - if (Section->second.SectionFlags == SectionFlags) + auto SectionIt = Context.SectionInfos.find(SectionName); + if (SectionIt != Context.SectionInfos.end()) { + const auto &Section = SectionIt->second; + if (Section.SectionFlags == SectionFlags) return false; - if (!(Section->second.SectionFlags & ASTContext::PSF_Implicit)) { + if (!(Section.SectionFlags & ASTContext::PSF_Implicit)) { Diag(PragmaSectionLocation, diag::err_section_conflict) - << "this" << "a prior #pragma section"; - Diag(Section->second.PragmaSectionLocation, - diag::note_pragma_entered_here); + << "this" << Section; + if (Section.Decl) + Diag(Section.Decl->getLocation(), diag::note_declared_at) + << Section.Decl->getName(); + if (Section.PragmaSectionLocation.isValid()) + Diag(Section.PragmaSectionLocation, diag::note_pragma_entered_here); return true; } } @@ -926,31 +966,85 @@ void Sema::ActOnPragmaVisibility(const IdentifierInfo* VisType, } } -void Sema::ActOnPragmaFPContract(LangOptions::FPContractModeKind FPC) { +void Sema::ActOnPragmaFPContract(SourceLocation Loc, + LangOptions::FPModeKind FPC) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); switch (FPC) { - case LangOptions::FPC_On: - FPFeatures.setAllowFPContractWithinStatement(); + case LangOptions::FPM_On: + NewFPFeatures.setAllowFPContractWithinStatement(); break; - case LangOptions::FPC_Fast: - FPFeatures.setAllowFPContractAcrossStatement(); + case LangOptions::FPM_Fast: + NewFPFeatures.setAllowFPContractAcrossStatement(); break; - case LangOptions::FPC_Off: - FPFeatures.setDisallowFPContract(); + case LangOptions::FPM_Off: + NewFPFeatures.setDisallowFPContract(); break; } + CurFPFeatures = NewFPFeatures.applyOverrides(getLangOpts()); + FpPragmaStack.Act(Loc, Sema::PSK_Set, StringRef(), + NewFPFeatures.getAsOpaqueInt()); } -void Sema::ActOnPragmaFEnvAccess(LangOptions::FEnvAccessModeKind FPC) { - switch (FPC) { - case LangOptions::FEA_On: - FPFeatures.setAllowFEnvAccess(); - break; - case LangOptions::FEA_Off: - FPFeatures.setDisallowFEnvAccess(); - break; - } +void Sema::ActOnPragmaFPReassociate(SourceLocation Loc, bool IsEnabled) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setAllowFPReassociateOverride(IsEnabled); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); } +void Sema::setRoundingMode(SourceLocation Loc, llvm::RoundingMode FPR) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setRoundingModeOverride(FPR); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); +} + +void Sema::setExceptionMode(SourceLocation Loc, + LangOptions::FPExceptionModeKind FPE) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + NewFPFeatures.setFPExceptionModeOverride(FPE); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); +} + +void Sema::ActOnPragmaFEnvAccess(SourceLocation Loc, bool IsEnabled) { + unsigned NewValue = FpPragmaStack.hasValue() + ? FpPragmaStack.CurrentValue + : CurFPFeatureOverrides().getAsOpaqueInt(); + FPOptionsOverride NewFPFeatures(NewValue); + if (IsEnabled) { + // Verify Microsoft restriction: + // You can't enable fenv_access unless precise semantics are enabled. + // Precise semantics can be enabled either by the float_control + // pragma, or by using the /fp:precise or /fp:strict compiler options + if (!isPreciseFPEnabled()) + Diag(Loc, diag::err_pragma_fenv_requires_precise); + NewFPFeatures.setAllowFEnvAccessOverride(true); + } else + NewFPFeatures.setAllowFEnvAccessOverride(false); + NewValue = NewFPFeatures.getAsOpaqueInt(); + FpPragmaStack.Act(Loc, PSK_Set, StringRef(), NewValue); + FPOptionsOverride NewOverrides(NewValue); + CurFPFeatures = NewOverrides.applyOverrides(getLangOpts()); +} void Sema::PushNamespaceVisibilityAttr(const VisibilityAttr *Attr, SourceLocation Loc) { diff --git a/clang/lib/Sema/SemaAvailability.cpp b/clang/lib/Sema/SemaAvailability.cpp new file mode 100644 index 000000000000..74c4b9e16f74 --- /dev/null +++ b/clang/lib/Sema/SemaAvailability.cpp @@ -0,0 +1,964 @@ +//===--- SemaAvailability.cpp - Availability attribute handling -----------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file processes the availability attribute. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/Attr.h" +#include "clang/AST/Decl.h" +#include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/DiagnosticSema.h" +#include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Sema.h" + +using namespace clang; +using namespace sema; + +static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, + const Decl *D) { + // Check each AvailabilityAttr to find the one for this platform. + for (const auto *A : D->attrs()) { + if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { + // FIXME: this is copied from CheckAvailability. We should try to + // de-duplicate. + + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef ActualPlatform = Avail->getPlatform()->getName(); + StringRef RealizedPlatform = ActualPlatform; + if (Context.getLangOpts().AppExt) { + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + RealizedPlatform = RealizedPlatform.slice(0, suffix); + } + + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + + // Match the platform name. + if (RealizedPlatform == TargetPlatform) + return Avail; + } + } + return nullptr; +} + +/// The diagnostic we should emit for \c D, and the declaration that +/// originated it, or \c AR_Available. +/// +/// \param D The declaration to check. +/// \param Message If non-null, this will be populated with the message from +/// the availability attribute that is selected. +/// \param ClassReceiver If we're checking the the method of a class message +/// send, the class. Otherwise nullptr. +static std::pair<AvailabilityResult, const NamedDecl *> +ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, + std::string *Message, + ObjCInterfaceDecl *ClassReceiver) { + AvailabilityResult Result = D->getAvailability(Message); + + // For typedefs, if the typedef declaration appears available look + // to the underlying type to see if it is more restrictive. + while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { + if (Result == AR_Available) { + if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { + D = TT->getDecl(); + Result = D->getAvailability(Message); + continue; + } + } + break; + } + + // Forward class declarations get their attributes from their definition. + if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { + if (IDecl->getDefinition()) { + D = IDecl->getDefinition(); + Result = D->getAvailability(Message); + } + } + + if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) + if (Result == AR_Available) { + const DeclContext *DC = ECD->getDeclContext(); + if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) { + Result = TheEnumDecl->getAvailability(Message); + D = TheEnumDecl; + } + } + + // For +new, infer availability from -init. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (S.NSAPIObj && ClassReceiver) { + ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( + S.NSAPIObj->getInitSelector()); + if (Init && Result == AR_Available && MD->isClassMethod() && + MD->getSelector() == S.NSAPIObj->getNewSelector() && + MD->definedInNSObject(S.getASTContext())) { + Result = Init->getAvailability(Message); + D = Init; + } + } + } + + return {Result, D}; +} + + +/// whether we should emit a diagnostic for \c K and \c DeclVersion in +/// the context of \c Ctx. For example, we should emit an unavailable diagnostic +/// in a deprecated context, but not the other way around. +static bool +ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, + VersionTuple DeclVersion, Decl *Ctx, + const NamedDecl *OffendingDecl) { + assert(K != AR_Available && "Expected an unavailable declaration here!"); + + // Checks if we should emit the availability diagnostic in the context of C. + auto CheckContext = [&](const Decl *C) { + if (K == AR_NotYetIntroduced) { + if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) + if (AA->getIntroduced() >= DeclVersion) + return true; + } else if (K == AR_Deprecated) { + if (C->isDeprecated()) + return true; + } else if (K == AR_Unavailable) { + // It is perfectly fine to refer to an 'unavailable' Objective-C method + // when it is referenced from within the @implementation itself. In this + // context, we interpret unavailable as a form of access control. + if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { + if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { + if (MD->getClassInterface() == Impl->getClassInterface()) + return true; + } + } + } + + if (C->isUnavailable()) + return true; + return false; + }; + + do { + if (CheckContext(Ctx)) + return false; + + // An implementation implicitly has the availability of the interface. + // Unless it is "+load" method. + if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) + if (MethodD->isClassMethod() && + MethodD->getSelector().getAsString() == "load") + return true; + + if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { + if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) + if (CheckContext(Interface)) + return false; + } + // A category implicitly has the availability of the interface. + else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + if (CheckContext(Interface)) + return false; + } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext()))); + + return true; +} + +static bool +shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, + const VersionTuple &DeploymentVersion, + const VersionTuple &DeclVersion) { + const auto &Triple = Context.getTargetInfo().getTriple(); + VersionTuple ForceAvailabilityFromVersion; + switch (Triple.getOS()) { + case llvm::Triple::IOS: + case llvm::Triple::TvOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11); + break; + case llvm::Triple::WatchOS: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4); + break; + case llvm::Triple::Darwin: + case llvm::Triple::MacOSX: + ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); + break; + default: + // New targets should always warn about availability. + return Triple.getVendor() == llvm::Triple::Apple; + } + return DeploymentVersion >= ForceAvailabilityFromVersion || + DeclVersion >= ForceAvailabilityFromVersion; +} + +static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { + for (Decl *Ctx = OrigCtx; Ctx; + Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) { + if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx)) + return cast<NamedDecl>(Ctx); + if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) { + if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx)) + return Imp->getClassInterface(); + return CD; + } + } + + return dyn_cast<NamedDecl>(OrigCtx); +} + +namespace { + +struct AttributeInsertion { + StringRef Prefix; + SourceLocation Loc; + StringRef Suffix; + + static AttributeInsertion createInsertionAfter(const NamedDecl *D) { + return {" ", D->getEndLoc(), ""}; + } + static AttributeInsertion createInsertionAfter(SourceLocation Loc) { + return {" ", Loc, ""}; + } + static AttributeInsertion createInsertionBefore(const NamedDecl *D) { + return {"", D->getBeginLoc(), "\n"}; + } +}; + +} // end anonymous namespace + +/// Tries to parse a string as ObjC method name. +/// +/// \param Name The string to parse. Expected to originate from availability +/// attribute argument. +/// \param SlotNames The vector that will be populated with slot names. In case +/// of unsuccessful parsing can contain invalid data. +/// \returns A number of method parameters if parsing was successful, None +/// otherwise. +static Optional<unsigned> +tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, + const LangOptions &LangOpts) { + // Accept replacements starting with - or + as valid ObjC method names. + if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) + Name = Name.drop_front(1); + if (Name.empty()) + return None; + Name.split(SlotNames, ':'); + unsigned NumParams; + if (Name.back() == ':') { + // Remove an empty string at the end that doesn't represent any slot. + SlotNames.pop_back(); + NumParams = SlotNames.size(); + } else { + if (SlotNames.size() != 1) + // Not a valid method name, just a colon-separated string. + return None; + NumParams = 0; + } + // Verify all slot names are valid. + bool AllowDollar = LangOpts.DollarIdents; + for (StringRef S : SlotNames) { + if (S.empty()) + continue; + if (!isValidIdentifier(S, AllowDollar)) + return None; + } + return NumParams; +} + +/// Returns a source location in which it's appropriate to insert a new +/// attribute for the given declaration \D. +static Optional<AttributeInsertion> +createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, + const LangOptions &LangOpts) { + if (isa<ObjCPropertyDecl>(D)) + return AttributeInsertion::createInsertionAfter(D); + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (MD->hasBody()) + return None; + return AttributeInsertion::createInsertionAfter(D); + } + if (const auto *TD = dyn_cast<TagDecl>(D)) { + SourceLocation Loc = + Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); + if (Loc.isInvalid()) + return None; + // Insert after the 'struct'/whatever keyword. + return AttributeInsertion::createInsertionAfter(Loc); + } + return AttributeInsertion::createInsertionBefore(D); +} + +/// Actually emit an availability diagnostic for a reference to an unavailable +/// decl. +/// +/// \param Ctx The context that the reference occurred in +/// \param ReferringDecl The exact declaration that was referenced. +/// \param OffendingDecl A related decl to \c ReferringDecl that has an +/// availability attribute corresponding to \c K attached to it. Note that this +/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and +/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl +/// and OffendingDecl is the EnumDecl. +static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, + Decl *Ctx, const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, + StringRef Message, + ArrayRef<SourceLocation> Locs, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess) { + // Diagnostics for deprecated or unavailable. + unsigned diag, diag_message, diag_fwdclass_message; + unsigned diag_available_here = diag::note_availability_specified_here; + SourceLocation NoteLocation = OffendingDecl->getLocation(); + + // Matches 'diag::note_property_attribute' options. + unsigned property_note_select; + + // Matches diag::note_availability_specified_here. + unsigned available_here_select_kind; + + VersionTuple DeclVersion; + if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) + DeclVersion = AA->getIntroduced(); + + if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx, + OffendingDecl)) + return; + + SourceLocation Loc = Locs.front(); + + // The declaration can have multiple availability attributes, we are looking + // at one of them. + const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); + if (A && A->isInherited()) { + for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; + Redecl = Redecl->getPreviousDecl()) { + const AvailabilityAttr *AForRedecl = + getAttrForPlatform(S.Context, Redecl); + if (AForRedecl && !AForRedecl->isInherited()) { + // If D is a declaration with inherited attributes, the note should + // point to the declaration with actual attributes. + NoteLocation = Redecl->getLocation(); + break; + } + } + } + + switch (K) { + case AR_NotYetIntroduced: { + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + const AvailabilityAttr *AA = + getAttrForPlatform(S.getASTContext(), OffendingDecl); + VersionTuple Introduced = AA->getIntroduced(); + + bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( + S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), + Introduced); + unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + std::string PlatformName(AvailabilityAttr::getPrettyPlatformName( + S.getASTContext().getTargetInfo().getPlatformName())); + + S.Diag(Loc, Warning) << OffendingDecl << PlatformName + << Introduced.getAsString(); + + S.Diag(OffendingDecl->getLocation(), + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << Introduced.getAsString() + << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); + + if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { + if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) + if (TD->getDeclName().isEmpty()) { + S.Diag(TD->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Anonymous*/ 1 << TD->getKindName(); + return; + } + auto FixitNoteDiag = + S.Diag(Enclosing->getLocation(), + diag::note_decl_unguarded_availability_silence) + << /*Named*/ 0 << Enclosing; + // Don't offer a fixit for declarations with availability attributes. + if (Enclosing->hasAttr<AvailabilityAttr>()) + return; + if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) + return; + Optional<AttributeInsertion> Insertion = createAttributeInsertion( + Enclosing, S.getSourceManager(), S.getLangOpts()); + if (!Insertion) + return; + std::string PlatformName = + AvailabilityAttr::getPlatformNameSourceSpelling( + S.getASTContext().getTargetInfo().getPlatformName()) + .lower(); + std::string Introduced = + OffendingDecl->getVersionIntroduced().getAsString(); + FixitNoteDiag << FixItHint::CreateInsertion( + Insertion->Loc, + (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + + "(" + Introduced + "))" + Insertion->Suffix) + .str()); + } + return; + } + case AR_Deprecated: + diag = !ObjCPropertyAccess ? diag::warn_deprecated + : diag::warn_property_method_deprecated; + diag_message = diag::warn_deprecated_message; + diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; + property_note_select = /* deprecated */ 0; + available_here_select_kind = /* deprecated */ 2; + if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) + NoteLocation = AL->getLocation(); + break; + + case AR_Unavailable: + diag = !ObjCPropertyAccess ? diag::err_unavailable + : diag::err_property_method_unavailable; + diag_message = diag::err_unavailable_message; + diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; + property_note_select = /* unavailable */ 1; + available_here_select_kind = /* unavailable */ 0; + + if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { + if (AL->isImplicit() && AL->getImplicitReason()) { + // Most of these failures are due to extra restrictions in ARC; + // reflect that in the primary diagnostic when applicable. + auto flagARCError = [&] { + if (S.getLangOpts().ObjCAutoRefCount && + S.getSourceManager().isInSystemHeader( + OffendingDecl->getLocation())) + diag = diag::err_unavailable_in_arc; + }; + + switch (AL->getImplicitReason()) { + case UnavailableAttr::IR_None: break; + + case UnavailableAttr::IR_ARCForbiddenType: + flagARCError(); + diag_available_here = diag::note_arc_forbidden_type; + break; + + case UnavailableAttr::IR_ForbiddenWeak: + if (S.getLangOpts().ObjCWeakRuntime) + diag_available_here = diag::note_arc_weak_disabled; + else + diag_available_here = diag::note_arc_weak_no_runtime; + break; + + case UnavailableAttr::IR_ARCForbiddenConversion: + flagARCError(); + diag_available_here = diag::note_performs_forbidden_arc_conversion; + break; + + case UnavailableAttr::IR_ARCInitReturnsUnrelated: + flagARCError(); + diag_available_here = diag::note_arc_init_returns_unrelated; + break; + + case UnavailableAttr::IR_ARCFieldWithOwnership: + flagARCError(); + diag_available_here = diag::note_arc_field_with_ownership; + break; + } + } + } + break; + + case AR_Available: + llvm_unreachable("Warning for availability of available declaration?"); + } + + SmallVector<FixItHint, 12> FixIts; + if (K == AR_Deprecated) { + StringRef Replacement; + if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) + Replacement = AL->getReplacement(); + if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) + Replacement = AL->getReplacement(); + + CharSourceRange UseRange; + if (!Replacement.empty()) + UseRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + if (UseRange.isValid()) { + if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { + Selector Sel = MethodDecl->getSelector(); + SmallVector<StringRef, 12> SelectorSlotNames; + Optional<unsigned> NumParams = tryParseObjCMethodName( + Replacement, SelectorSlotNames, S.getLangOpts()); + if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { + assert(SelectorSlotNames.size() == Locs.size()); + for (unsigned I = 0; I < Locs.size(); ++I) { + if (!Sel.getNameForSlot(I).empty()) { + CharSourceRange NameRange = CharSourceRange::getCharRange( + Locs[I], S.getLocForEndOfToken(Locs[I])); + FixIts.push_back(FixItHint::CreateReplacement( + NameRange, SelectorSlotNames[I])); + } else + FixIts.push_back( + FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); + } + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } else + FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); + } + } + + if (!Message.empty()) { + S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; + if (ObjCProperty) + S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) + << ObjCProperty->getDeclName() << property_note_select; + } else if (!UnknownObjCClass) { + S.Diag(Loc, diag) << ReferringDecl << FixIts; + if (ObjCProperty) + S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) + << ObjCProperty->getDeclName() << property_note_select; + } else { + S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; + S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); + } + + S.Diag(NoteLocation, diag_available_here) + << OffendingDecl << available_here_select_kind; +} + +void Sema::handleDelayedAvailabilityCheck(DelayedDiagnostic &DD, Decl *Ctx) { + assert(DD.Kind == DelayedDiagnostic::Availability && + "Expected an availability diagnostic here"); + + DD.Triggered = true; + DoEmitAvailabilityWarning( + *this, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), + DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), + DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); +} + +static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, + const NamedDecl *ReferringDecl, + const NamedDecl *OffendingDecl, + StringRef Message, + ArrayRef<SourceLocation> Locs, + const ObjCInterfaceDecl *UnknownObjCClass, + const ObjCPropertyDecl *ObjCProperty, + bool ObjCPropertyAccess) { + // Delay if we're currently parsing a declaration. + if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { + S.DelayedDiagnostics.add( + DelayedDiagnostic::makeAvailability( + AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, + ObjCProperty, Message, ObjCPropertyAccess)); + return; + } + + Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); + DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, + Message, Locs, UnknownObjCClass, ObjCProperty, + ObjCPropertyAccess); +} + +namespace { + +/// Returns true if the given statement can be a body-like child of \p Parent. +bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) { + switch (Parent->getStmtClass()) { + case Stmt::IfStmtClass: + return cast<IfStmt>(Parent)->getThen() == S || + cast<IfStmt>(Parent)->getElse() == S; + case Stmt::WhileStmtClass: + return cast<WhileStmt>(Parent)->getBody() == S; + case Stmt::DoStmtClass: + return cast<DoStmt>(Parent)->getBody() == S; + case Stmt::ForStmtClass: + return cast<ForStmt>(Parent)->getBody() == S; + case Stmt::CXXForRangeStmtClass: + return cast<CXXForRangeStmt>(Parent)->getBody() == S; + case Stmt::ObjCForCollectionStmtClass: + return cast<ObjCForCollectionStmt>(Parent)->getBody() == S; + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + return cast<SwitchCase>(Parent)->getSubStmt() == S; + default: + return false; + } +} + +class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> { + const Stmt *Target; + +public: + bool VisitStmt(Stmt *S) { return S != Target; } + + /// Returns true if the given statement is present in the given declaration. + static bool isContained(const Stmt *Target, const Decl *D) { + StmtUSEFinder Visitor; + Visitor.Target = Target; + return !Visitor.TraverseDecl(const_cast<Decl *>(D)); + } +}; + +/// Traverses the AST and finds the last statement that used a given +/// declaration. +class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> { + const Decl *D; + +public: + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (DRE->getDecl() == D) + return false; + return true; + } + + static const Stmt *findLastStmtThatUsesDecl(const Decl *D, + const CompoundStmt *Scope) { + LastDeclUSEFinder Visitor; + Visitor.D = D; + for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) { + const Stmt *S = *I; + if (!Visitor.TraverseStmt(const_cast<Stmt *>(S))) + return S; + } + return nullptr; + } +}; + +/// This class implements -Wunguarded-availability. +/// +/// This is done with a traversal of the AST of a function that makes reference +/// to a partially available declaration. Whenever we encounter an \c if of the +/// form: \c if(@available(...)), we use the version from the condition to visit +/// the then statement. +class DiagnoseUnguardedAvailability + : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> { + typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base; + + Sema &SemaRef; + Decl *Ctx; + + /// Stack of potentially nested 'if (@available(...))'s. + SmallVector<VersionTuple, 8> AvailabilityStack; + SmallVector<const Stmt *, 16> StmtStack; + + void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range, + ObjCInterfaceDecl *ClassReceiver = nullptr); + +public: + DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) + : SemaRef(SemaRef), Ctx(Ctx) { + AvailabilityStack.push_back( + SemaRef.Context.getTargetInfo().getPlatformMinVersion()); + } + + bool TraverseDecl(Decl *D) { + // Avoid visiting nested functions to prevent duplicate warnings. + if (!D || isa<FunctionDecl>(D)) + return true; + return Base::TraverseDecl(D); + } + + bool TraverseStmt(Stmt *S) { + if (!S) + return true; + StmtStack.push_back(S); + bool Result = Base::TraverseStmt(S); + StmtStack.pop_back(); + return Result; + } + + void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } + + bool TraverseIfStmt(IfStmt *If); + + bool TraverseLambdaExpr(LambdaExpr *E) { return true; } + + // for 'case X:' statements, don't bother looking at the 'X'; it can't lead + // to any useful diagnostics. + bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); } + + bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { + if (PRE->isClassReceiver()) + DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation()); + return true; + } + + bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { + if (ObjCMethodDecl *D = Msg->getMethodDecl()) { + ObjCInterfaceDecl *ID = nullptr; + QualType ReceiverTy = Msg->getClassReceiver(); + if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType()) + ID = ReceiverTy->getAsObjCInterfaceType()->getInterface(); + + DiagnoseDeclAvailability( + D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID); + } + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + DiagnoseDeclAvailability(DRE->getDecl(), + SourceRange(DRE->getBeginLoc(), DRE->getEndLoc())); + return true; + } + + bool VisitMemberExpr(MemberExpr *ME) { + DiagnoseDeclAvailability(ME->getMemberDecl(), + SourceRange(ME->getBeginLoc(), ME->getEndLoc())); + return true; + } + + bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { + SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use) + << (!SemaRef.getLangOpts().ObjC); + return true; + } + + bool VisitTypeLoc(TypeLoc Ty); +}; + +void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( + NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) { + AvailabilityResult Result; + const NamedDecl *OffendingDecl; + std::tie(Result, OffendingDecl) = + ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass); + if (Result != AR_Available) { + // All other diagnostic kinds have already been handled in + // DiagnoseAvailabilityOfDecl. + if (Result != AR_NotYetIntroduced) + return; + + const AvailabilityAttr *AA = + getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); + VersionTuple Introduced = AA->getIntroduced(); + + if (AvailabilityStack.back() >= Introduced) + return; + + // If the context of this function is less available than D, we should not + // emit a diagnostic. + if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx, + OffendingDecl)) + return; + + // We would like to emit the diagnostic even if -Wunguarded-availability is + // not specified for deployment targets >= to iOS 11 or equivalent or + // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or + // later. + unsigned DiagKind = + shouldDiagnoseAvailabilityByDefault( + SemaRef.Context, + SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced) + ? diag::warn_unguarded_availability_new + : diag::warn_unguarded_availability; + + std::string PlatformName(AvailabilityAttr::getPrettyPlatformName( + SemaRef.getASTContext().getTargetInfo().getPlatformName())); + + SemaRef.Diag(Range.getBegin(), DiagKind) + << Range << D << PlatformName << Introduced.getAsString(); + + SemaRef.Diag(OffendingDecl->getLocation(), + diag::note_partial_availability_specified_here) + << OffendingDecl << PlatformName << Introduced.getAsString() + << SemaRef.Context.getTargetInfo() + .getPlatformMinVersion() + .getAsString(); + + auto FixitDiag = + SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) + << Range << D + << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0 + : /*__builtin_available*/ 1); + + // Find the statement which should be enclosed in the if @available check. + if (StmtStack.empty()) + return; + const Stmt *StmtOfUse = StmtStack.back(); + const CompoundStmt *Scope = nullptr; + for (const Stmt *S : llvm::reverse(StmtStack)) { + if (const auto *CS = dyn_cast<CompoundStmt>(S)) { + Scope = CS; + break; + } + if (isBodyLikeChildStmt(StmtOfUse, S)) { + // The declaration won't be seen outside of the statement, so we don't + // have to wrap the uses of any declared variables in if (@available). + // Therefore we can avoid setting Scope here. + break; + } + StmtOfUse = S; + } + const Stmt *LastStmtOfUse = nullptr; + if (isa<DeclStmt>(StmtOfUse) && Scope) { + for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) { + if (StmtUSEFinder::isContained(StmtStack.back(), D)) { + LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope); + break; + } + } + } + + const SourceManager &SM = SemaRef.getSourceManager(); + SourceLocation IfInsertionLoc = + SM.getExpansionLoc(StmtOfUse->getBeginLoc()); + SourceLocation StmtEndLoc = + SM.getExpansionRange( + (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc()) + .getEnd(); + if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) + return; + + StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM); + const char *ExtraIndentation = " "; + std::string FixItString; + llvm::raw_string_ostream FixItOS(FixItString); + FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available" + : "__builtin_available") + << "(" + << AvailabilityAttr::getPlatformNameSourceSpelling( + SemaRef.getASTContext().getTargetInfo().getPlatformName()) + << " " << Introduced.getAsString() << ", *)) {\n" + << Indentation << ExtraIndentation; + FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str()); + SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken( + StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(), + /*SkipTrailingWhitespaceAndNewLine=*/false); + if (ElseInsertionLoc.isInvalid()) + ElseInsertionLoc = + Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts()); + FixItOS.str().clear(); + FixItOS << "\n" + << Indentation << "} else {\n" + << Indentation << ExtraIndentation + << "// Fallback on earlier versions\n" + << Indentation << "}"; + FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str()); + } +} + +bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { + const Type *TyPtr = Ty.getTypePtr(); + SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()}; + + if (Range.isInvalid()) + return true; + + if (const auto *TT = dyn_cast<TagType>(TyPtr)) { + TagDecl *TD = TT->getDecl(); + DiagnoseDeclAvailability(TD, Range); + + } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { + TypedefNameDecl *D = TD->getDecl(); + DiagnoseDeclAvailability(D, Range); + + } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) { + if (NamedDecl *D = ObjCO->getInterface()) + DiagnoseDeclAvailability(D, Range); + } + + return true; +} + +bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) { + VersionTuple CondVersion; + if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) { + CondVersion = E->getVersion(); + + // If we're using the '*' case here or if this check is redundant, then we + // use the enclosing version to check both branches. + if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) + return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse()); + } else { + // This isn't an availability checking 'if', we can just continue. + return Base::TraverseIfStmt(If); + } + + AvailabilityStack.push_back(CondVersion); + bool ShouldContinue = TraverseStmt(If->getThen()); + AvailabilityStack.pop_back(); + + return ShouldContinue && TraverseStmt(If->getElse()); +} + +} // end anonymous namespace + +void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { + Stmt *Body = nullptr; + + if (auto *FD = D->getAsFunction()) { + // FIXME: We only examine the pattern decl for availability violations now, + // but we should also examine instantiated templates. + if (FD->isTemplateInstantiation()) + return; + + Body = FD->getBody(); + } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) + Body = MD->getBody(); + else if (auto *BD = dyn_cast<BlockDecl>(D)) + Body = BD->getBody(); + + assert(Body && "Need a body here!"); + + DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); +} + +void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, + ArrayRef<SourceLocation> Locs, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess, + bool AvoidPartialAvailabilityChecks, + ObjCInterfaceDecl *ClassReceiver) { + std::string Message; + AvailabilityResult Result; + const NamedDecl* OffendingDecl; + // See if this declaration is unavailable, deprecated, or partial. + std::tie(Result, OffendingDecl) = + ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); + if (Result == AR_Available) + return; + + if (Result == AR_NotYetIntroduced) { + if (AvoidPartialAvailabilityChecks) + return; + + // We need to know the @available context in the current function to + // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that + // when we're done parsing the current function. + if (getCurFunctionOrMethodDecl()) { + getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + return; + } else if (getCurBlock() || getCurLambda()) { + getCurFunction()->HasPotentialAvailabilityViolations = true; + return; + } + } + + const ObjCPropertyDecl *ObjCPDecl = nullptr; + if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { + if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { + AvailabilityResult PDeclResult = PD->getAvailability(nullptr); + if (PDeclResult == Result) + ObjCPDecl = PD; + } + } + + EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, + UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); +} diff --git a/clang/lib/Sema/SemaCUDA.cpp b/clang/lib/Sema/SemaCUDA.cpp index 0c61057e1072..283a04683a32 100644 --- a/clang/lib/Sema/SemaCUDA.cpp +++ b/clang/lib/Sema/SemaCUDA.cpp @@ -14,8 +14,10 @@ #include "clang/AST/Decl.h" #include "clang/AST/ExprCXX.h" #include "clang/Basic/Cuda.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/SemaInternal.h" @@ -210,6 +212,20 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, llvm_unreachable("All cases should've been handled by now."); } +template <typename AttrT> static bool hasImplicitAttr(const FunctionDecl *D) { + if (!D) + return false; + if (auto *A = D->getAttr<AttrT>()) + return A->isImplicit(); + return D->isImplicit(); +} + +bool Sema::isCUDAImplicitHostDeviceFunction(const FunctionDecl *D) { + bool IsImplicitDevAttr = hasImplicitAttr<CUDADeviceAttr>(D); + bool IsImplicitHostAttr = hasImplicitAttr<CUDAHostAttr>(D); + return IsImplicitDevAttr && IsImplicitHostAttr; +} + void Sema::EraseUnwantedCUDAMatches( const FunctionDecl *Caller, SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) { @@ -425,6 +441,10 @@ bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { if (CD->getParent()->isDynamicClass()) return false; + // Union ctor does not call ctors of its data members. + if (CD->getParent()->isUnion()) + return true; + // The only form of initializer allowed is an empty constructor. // This will recursively check all base classes and member initializers if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { @@ -464,6 +484,11 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { if (ClassDecl->isDynamicClass()) return false; + // Union does not have base class and union dtor does not call dtors of its + // data members. + if (DD->getParent()->isUnion()) + return true; + // Only empty destructors are allowed. This will recursively check // destructors for all base classes... if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) { @@ -503,9 +528,14 @@ void Sema::checkAllowedCUDAInitializer(VarDecl *VD) { // constructor according to CUDA rules. This deviates from NVCC, // but allows us to handle things like constexpr constructors. if (!AllowedInit && - (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) - AllowedInit = VD->getInit()->isConstantInitializer( - Context, VD->getType()->isReferenceType()); + (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>())) { + auto *Init = VD->getInit(); + AllowedInit = + ((VD->getType()->isDependentType() || Init->isValueDependent()) && + VD->isConstexpr()) || + Init->isConstantInitializer(Context, + VD->getType()->isReferenceType()); + } // Also make sure that destructor, if there is one, is empty. if (AllowedInit) @@ -602,6 +632,13 @@ void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); } +void Sema::MaybeAddCUDAConstantAttr(VarDecl *VD) { + if (getLangOpts().CUDAIsDevice && VD->isConstexpr() && + (VD->isFileVarDecl() || VD->isStaticDataMember())) { + VD->addAttr(CUDAConstantAttr::CreateImplicit(getASTContext())); + } +} + Sema::DeviceDiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); @@ -674,25 +711,6 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { // Otherwise, mark the call in our call graph so we can traverse it later. bool CallerKnownEmitted = getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted; - if (CallerKnownEmitted) { - // Host-side references to a __global__ function refer to the stub, so the - // function itself is never emitted and therefore should not be marked. - if (!shouldIgnoreInHostDeviceCheck(Callee)) - markKnownEmitted( - *this, Caller, Callee, Loc, [](Sema &S, FunctionDecl *FD) { - return S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted; - }); - } else { - // If we have - // host fn calls kernel fn calls host+device, - // the HD function does not get instantiated on the host. We model this by - // omitting at the call to the kernel from the callgraph. This ensures - // that, when compiling for host, only HD functions actually called from the - // host get marked as known-emitted. - if (!shouldIgnoreInHostDeviceCheck(Callee)) - DeviceCallGraph[Caller].insert({Callee, Loc}); - } - DeviceDiagBuilder::Kind DiagKind = [this, Caller, Callee, CallerKnownEmitted] { switch (IdentifyCUDAPreference(Caller, Callee)) { @@ -729,20 +747,58 @@ bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack; } +// Check the wrong-sided reference capture of lambda for CUDA/HIP. +// A lambda function may capture a stack variable by reference when it is +// defined and uses the capture by reference when the lambda is called. When +// the capture and use happen on different sides, the capture is invalid and +// should be diagnosed. +void Sema::CUDACheckLambdaCapture(CXXMethodDecl *Callee, + const sema::Capture &Capture) { + // In host compilation we only need to check lambda functions emitted on host + // side. In such lambda functions, a reference capture is invalid only + // if the lambda structure is populated by a device function or kernel then + // is passed to and called by a host function. However that is impossible, + // since a device function or kernel can only call a device function, also a + // kernel cannot pass a lambda back to a host function since we cannot + // define a kernel argument type which can hold the lambda before the lambda + // itself is defined. + if (!LangOpts.CUDAIsDevice) + return; + + // File-scope lambda can only do init captures for global variables, which + // results in passing by value for these global variables. + FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext); + if (!Caller) + return; + + // In device compilation, we only need to check lambda functions which are + // emitted on device side. For such lambdas, a reference capture is invalid + // only if the lambda structure is populated by a host function then passed + // to and called in a device function or kernel. + bool CalleeIsDevice = Callee->hasAttr<CUDADeviceAttr>(); + bool CallerIsHost = + !Caller->hasAttr<CUDAGlobalAttr>() && !Caller->hasAttr<CUDADeviceAttr>(); + bool ShouldCheck = CalleeIsDevice && CallerIsHost; + if (!ShouldCheck || !Capture.isReferenceCapture()) + return; + auto DiagKind = DeviceDiagBuilder::K_Deferred; + if (Capture.isVariableCapture()) { + DeviceDiagBuilder(DiagKind, Capture.getLocation(), + diag::err_capture_bad_target, Callee, *this) + << Capture.getVariable(); + } else if (Capture.isThisCapture()) { + DeviceDiagBuilder(DiagKind, Capture.getLocation(), + diag::err_capture_bad_target_this_ptr, Callee, *this); + } + return; +} + void Sema::CUDASetLambdaAttrs(CXXMethodDecl *Method) { assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); if (Method->hasAttr<CUDAHostAttr>() || Method->hasAttr<CUDADeviceAttr>()) return; - FunctionDecl *CurFn = dyn_cast<FunctionDecl>(CurContext); - if (!CurFn) - return; - CUDAFunctionTarget Target = IdentifyCUDATarget(CurFn); - if (Target == CFT_Global || Target == CFT_Device) { - Method->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - } else if (Target == CFT_HostDevice) { - Method->addAttr(CUDADeviceAttr::CreateImplicit(Context)); - Method->addAttr(CUDAHostAttr::CreateImplicit(Context)); - } + Method->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + Method->addAttr(CUDAHostAttr::CreateImplicit(Context)); } void Sema::checkCUDATargetOverload(FunctionDecl *NewFD, diff --git a/clang/lib/Sema/SemaCast.cpp b/clang/lib/Sema/SemaCast.cpp index a905ebc67305..2efe26052c78 100644 --- a/clang/lib/Sema/SemaCast.cpp +++ b/clang/lib/Sema/SemaCast.cpp @@ -48,7 +48,8 @@ enum CastType { CT_Reinterpret, ///< reinterpret_cast CT_Dynamic, ///< dynamic_cast CT_CStyle, ///< (Type)expr - CT_Functional ///< Type(expr) + CT_Functional, ///< Type(expr) + CT_Addrspace ///< addrspace_cast }; namespace { @@ -88,6 +89,7 @@ namespace { void CheckCXXCStyleCast(bool FunctionalCast, bool ListInitialization); void CheckCStyleCast(); void CheckBuiltinBitCast(); + void CheckAddrspaceCast(); void updatePartOfExplicitCastFlags(CastExpr *CE) { // Walk down from the CE to the OrigSrcExpr, and mark all immediate @@ -159,6 +161,30 @@ namespace { PlaceholderKind = (BuiltinType::Kind) 0; } }; + + void CheckNoDeref(Sema &S, const QualType FromType, const QualType ToType, + SourceLocation OpLoc) { + if (const auto *PtrType = dyn_cast<PointerType>(FromType)) { + if (PtrType->getPointeeType()->hasAttr(attr::NoDeref)) { + if (const auto *DestType = dyn_cast<PointerType>(ToType)) { + if (!DestType->getPointeeType()->hasAttr(attr::NoDeref)) { + S.Diag(OpLoc, diag::warn_noderef_to_dereferenceable_pointer); + } + } + } + } + } + + struct CheckNoDerefRAII { + CheckNoDerefRAII(CastOperation &Op) : Op(Op) {} + ~CheckNoDerefRAII() { + if (!Op.SrcExpr.isInvalid()) + CheckNoDeref(Op.Self, Op.SrcExpr.get()->getType(), Op.ResultType, + Op.OpRange.getBegin()); + } + + CastOperation &Op; + }; } static void DiagnoseCastQual(Sema &Self, const ExprResult &SrcExpr, @@ -225,12 +251,14 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, unsigned &msg); static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, - SourceRange OpRange, - unsigned &msg, + SourceRange OpRange, unsigned &msg, CastKind &Kind); +static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, + QualType DestType, bool CStyle, + unsigned &msg, CastKind &Kind); - -/// ActOnCXXNamedCast - Parse {dynamic,static,reinterpret,const}_cast's. +/// ActOnCXXNamedCast - Parse +/// {dynamic,static,reinterpret,const,addrspace}_cast's. ExprResult Sema::ActOnCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, SourceLocation LAngleBracketLoc, Declarator &D, @@ -272,6 +300,16 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, switch (Kind) { default: llvm_unreachable("Unknown C++ cast!"); + case tok::kw_addrspace_cast: + if (!TypeDependent) { + Op.CheckAddrspaceCast(); + if (Op.SrcExpr.isInvalid()) + return ExprError(); + } + return Op.complete(CXXAddrspaceCastExpr::Create( + Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), + DestTInfo, OpLoc, Parens.getEnd(), AngleBrackets)); + case tok::kw_const_cast: if (!TypeDependent) { Op.CheckConstCast(); @@ -375,6 +413,7 @@ static bool tryDiagnoseOverloadedCast(Sema &S, CastType CT, case CT_Const: case CT_Reinterpret: case CT_Dynamic: + case CT_Addrspace: return false; // These do. @@ -708,6 +747,8 @@ static TryCastResult getCastAwayConstnessCastKind(CastAwayConstnessKind CACK, /// Refer to C++ 5.2.7 for details. Dynamic casts are used mostly for runtime- /// checked downcasts in class hierarchies. void CastOperation::CheckDynamicCast() { + CheckNoDerefRAII NoderefCheck(*this); + if (ValueKind == VK_RValue) SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get()); else if (isPlaceholder()) @@ -861,6 +902,8 @@ void CastOperation::CheckDynamicCast() { /// const char *str = "literal"; /// legacy_function(const_cast\<char*\>(str)); void CastOperation::CheckConstCast() { + CheckNoDerefRAII NoderefCheck(*this); + if (ValueKind == VK_RValue) SrcExpr = Self.DefaultFunctionArrayLvalueConversion(SrcExpr.get()); else if (isPlaceholder()) @@ -878,6 +921,18 @@ void CastOperation::CheckConstCast() { SrcExpr = ExprError(); } +void CastOperation::CheckAddrspaceCast() { + unsigned msg = diag::err_bad_cxx_cast_generic; + auto TCR = + TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ false, msg, Kind); + if (TCR != TC_Success && msg != 0) { + Self.Diag(OpRange.getBegin(), msg) + << CT_Addrspace << SrcExpr.get()->getType() << DestType << OpRange; + } + if (!isValidCast(TCR)) + SrcExpr = ExprError(); +} + /// Check that a reinterpret_cast\<DestType\>(SrcExpr) is not used as upcast /// or downcast between respective pointers or references. static void DiagnoseReinterpretUpDownCast(Sema &Self, const Expr *SrcExpr, @@ -1018,6 +1073,8 @@ void CastOperation::CheckReinterpretCast() { /// Refer to C++ 5.2.9 for details. Static casts are mostly used for making /// implicit conversions explicit and getting rid of data loss warnings. void CastOperation::CheckStaticCast() { + CheckNoDerefRAII NoderefCheck(*this); + if (isPlaceholder()) { checkNonOverloadPlaceholders(); if (SrcExpr.isInvalid()) @@ -1961,7 +2018,7 @@ static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr, << FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText); } -static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, +static void checkIntToPointerCast(bool CStyle, const SourceRange &OpRange, const Expr *SrcExpr, QualType DestType, Sema &Self) { QualType SrcType = SrcExpr->getType(); @@ -1983,7 +2040,7 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, unsigned Diag = DestType->isVoidPointerType() ? diag::warn_int_to_void_pointer_cast : diag::warn_int_to_pointer_cast; - Self.Diag(Loc, Diag) << SrcType << DestType; + Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange; } } @@ -2062,6 +2119,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; // FIXME: Use a specific diagnostic for the rest of these cases. case OK_VectorComponent: inappropriate = "vector element"; break; + case OK_MatrixComponent: + inappropriate = "matrix element"; + break; case OK_ObjCProperty: inappropriate = "property expression"; break; case OK_ObjCSubscript: inappropriate = "container subscripting expression"; break; @@ -2204,13 +2264,19 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, // C++ 5.2.10p4: A pointer can be explicitly converted to any integral // type large enough to hold it; except in Microsoft mode, where the // integral type size doesn't matter (except we don't allow bool). - bool MicrosoftException = Self.getLangOpts().MicrosoftExt && - !DestType->isBooleanType(); if ((Self.Context.getTypeSize(SrcType) > - Self.Context.getTypeSize(DestType)) && - !MicrosoftException) { - msg = diag::err_bad_reinterpret_cast_small_int; - return TC_Failed; + Self.Context.getTypeSize(DestType))) { + bool MicrosoftException = + Self.getLangOpts().MicrosoftExt && !DestType->isBooleanType(); + if (MicrosoftException) { + unsigned Diag = SrcType->isVoidPointerType() + ? diag::warn_void_pointer_to_int_cast + : diag::warn_pointer_to_int_cast; + Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange; + } else { + msg = diag::err_bad_reinterpret_cast_small_int; + return TC_Failed; + } } Kind = CK_PointerToIntegral; return TC_Success; @@ -2218,8 +2284,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, if (SrcType->isIntegralOrEnumerationType()) { assert(destIsPtr && "One type must be a pointer"); - checkIntToPointerCast(CStyle, OpRange.getBegin(), SrcExpr.get(), DestType, - Self); + checkIntToPointerCast(CStyle, OpRange, SrcExpr.get(), DestType, Self); // C++ 5.2.10p5: A value of integral or enumeration type can be explicitly // converted to a pointer. // C++ 5.2.10p9: [Note: ...a null pointer constant of integral type is not @@ -2311,6 +2376,24 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, return SuccessResult; } + // Diagnose address space conversion in nested pointers. + QualType DestPtee = DestType->getPointeeType().isNull() + ? DestType->getPointeeType() + : DestType->getPointeeType()->getPointeeType(); + QualType SrcPtee = SrcType->getPointeeType().isNull() + ? SrcType->getPointeeType() + : SrcType->getPointeeType()->getPointeeType(); + while (!DestPtee.isNull() && !SrcPtee.isNull()) { + if (DestPtee.getAddressSpace() != SrcPtee.getAddressSpace()) { + Self.Diag(OpRange.getBegin(), + diag::warn_bad_cxx_cast_nested_pointer_addr_space) + << CStyle << SrcType << DestType << SrcExpr.get()->getSourceRange(); + break; + } + DestPtee = DestPtee->getPointeeType(); + SrcPtee = SrcPtee->getPointeeType(); + } + // C++ 5.2.10p7: A pointer to an object can be explicitly converted to // a pointer to an object of different type. // Void pointers are not specified, but supported by every compiler out there. @@ -2321,7 +2404,7 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, - unsigned &msg) { + unsigned &msg, CastKind &Kind) { if (!Self.getLangOpts().OpenCL) // FIXME: As compiler doesn't have any information about overlapping addr // spaces at the moment we have to be permissive here. @@ -2330,6 +2413,9 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, // non-OpenCL mode too, we fast-path above because no other languages // define overlapping address spaces currently. auto SrcType = SrcExpr.get()->getType(); + // FIXME: Should this be generalized to references? The reference parameter + // however becomes a reference pointee type here and therefore rejected. + // Perhaps this is the right behavior though according to C++. auto SrcPtrType = SrcType->getAs<PointerType>(); if (!SrcPtrType) return TC_NotApplicable; @@ -2338,9 +2424,7 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, return TC_NotApplicable; auto SrcPointeeType = SrcPtrType->getPointeeType(); auto DestPointeeType = DestPtrType->getPointeeType(); - if (SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace()) - return TC_NotApplicable; - if (!DestPtrType->isAddressSpaceOverlapping(*SrcPtrType)) { + if (!DestPointeeType.isAddressSpaceOverlapping(SrcPointeeType)) { msg = diag::err_bad_cxx_cast_addr_space_mismatch; return TC_Failed; } @@ -2348,10 +2432,15 @@ static TryCastResult TryAddressSpaceCast(Sema &Self, ExprResult &SrcExpr, Self.Context.removeAddrSpaceQualType(SrcPointeeType.getCanonicalType()); auto DestPointeeTypeWithoutAS = Self.Context.removeAddrSpaceQualType(DestPointeeType.getCanonicalType()); - return Self.Context.hasSameType(SrcPointeeTypeWithoutAS, - DestPointeeTypeWithoutAS) - ? TC_Success - : TC_NotApplicable; + if (Self.Context.hasSameType(SrcPointeeTypeWithoutAS, + DestPointeeTypeWithoutAS)) { + Kind = SrcPointeeType.getAddressSpace() == DestPointeeType.getAddressSpace() + ? CK_NoOp + : CK_AddressSpaceConversion; + return TC_Success; + } else { + return TC_NotApplicable; + } } void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { @@ -2378,9 +2467,9 @@ void CastOperation::checkAddressSpaceCast(QualType SrcType, QualType DestType) { const PointerType *SrcPPtr = cast<PointerType>(SrcPtr); QualType DestPPointee = DestPPtr->getPointeeType(); QualType SrcPPointee = SrcPPtr->getPointeeType(); - if (Nested ? DestPPointee.getAddressSpace() != - SrcPPointee.getAddressSpace() - : !DestPPtr->isAddressSpaceOverlapping(*SrcPPtr)) { + if (Nested + ? DestPPointee.getAddressSpace() != SrcPPointee.getAddressSpace() + : !DestPPointee.isAddressSpaceOverlapping(SrcPPointee)) { Self.Diag(OpRange.getBegin(), DiagID) << SrcType << DestType << Sema::AA_Casting << SrcExpr.get()->getSourceRange(); @@ -2482,22 +2571,21 @@ void CastOperation::CheckCXXCStyleCast(bool FunctionalStyle, Sema::CheckedConversionKind CCK = FunctionalStyle ? Sema::CCK_FunctionalCast : Sema::CCK_CStyleCast; if (tcr == TC_NotApplicable) { - tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg); + tcr = TryAddressSpaceCast(Self, SrcExpr, DestType, /*CStyle*/ true, msg, + Kind); if (SrcExpr.isInvalid()) return; - if (isValidCast(tcr)) - Kind = CK_AddressSpaceConversion; - if (tcr == TC_NotApplicable) { - // ... or if that is not possible, a static_cast, ignoring const, ... + // ... or if that is not possible, a static_cast, ignoring const and + // addr space, ... tcr = TryStaticCast(Self, SrcExpr, DestType, CCK, OpRange, msg, Kind, BasePath, ListInitialization); if (SrcExpr.isInvalid()) return; if (tcr == TC_NotApplicable) { - // ... and finally a reinterpret_cast, ignoring const. + // ... and finally a reinterpret_cast, ignoring const and addr space. tcr = TryReinterpretCast(Self, SrcExpr, DestType, /*CStyle*/ true, OpRange, msg, Kind); if (SrcExpr.isInvalid()) @@ -2629,6 +2717,13 @@ void CastOperation::CheckCStyleCast() { return; } + // Allow casting a sizeless built-in type to itself. + if (DestType->isSizelessBuiltinType() && + Self.Context.hasSameUnqualifiedType(DestType, SrcType)) { + Kind = CK_NoOp; + return; + } + if (!DestType->isScalarType() && !DestType->isVectorType()) { const RecordType *DestRecordTy = DestType->getAs<RecordType>(); @@ -2724,6 +2819,20 @@ void CastOperation::CheckCStyleCast() { return; } + // Can't cast to or from bfloat + if (DestType->isBFloat16Type() && !SrcType->isBFloat16Type()) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_to_bfloat16) + << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + if (SrcType->isBFloat16Type() && !DestType->isBFloat16Type()) { + Self.Diag(SrcExpr.get()->getExprLoc(), diag::err_cast_from_bfloat16) + << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + // If either type is a pointer, the other type has to be either an // integer or a pointer. if (!DestType->isArithmeticType()) { @@ -2734,8 +2843,8 @@ void CastOperation::CheckCStyleCast() { SrcExpr = ExprError(); return; } - checkIntToPointerCast(/* CStyle */ true, OpRange.getBegin(), SrcExpr.get(), - DestType, Self); + checkIntToPointerCast(/* CStyle */ true, OpRange, SrcExpr.get(), DestType, + Self); } else if (!SrcType->isArithmeticType()) { if (!DestType->isIntegralType(Self.Context) && DestType->isArithmeticType()) { @@ -2745,6 +2854,25 @@ void CastOperation::CheckCStyleCast() { SrcExpr = ExprError(); return; } + + if ((Self.Context.getTypeSize(SrcType) > + Self.Context.getTypeSize(DestType)) && + !DestType->isBooleanType()) { + // C 6.3.2.3p6: Any pointer type may be converted to an integer type. + // Except as previously specified, the result is implementation-defined. + // If the result cannot be represented in the integer type, the behavior + // is undefined. The result need not be in the range of values of any + // integer type. + unsigned Diag; + if (SrcType->isVoidPointerType()) + Diag = DestType->isEnumeralType() ? diag::warn_void_pointer_to_enum_cast + : diag::warn_void_pointer_to_int_cast; + else if (DestType->isEnumeralType()) + Diag = diag::warn_pointer_to_enum_cast; + else + Diag = diag::warn_pointer_to_int_cast; + Self.Diag(OpRange.getBegin(), Diag) << SrcType << DestType << OpRange; + } } if (Self.getLangOpts().OpenCL && diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 74742023d1b3..509d88e25000 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -30,6 +30,7 @@ #include "clang/AST/NSAPI.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/OperationKinds.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/Stmt.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/Type.h" @@ -87,6 +88,7 @@ #include "llvm/Support/SaveAndRestore.h" #include "llvm/Support/raw_ostream.h" #include <algorithm> +#include <bitset> #include <cassert> #include <cstddef> #include <cstdint> @@ -236,8 +238,8 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { } Expr::EvalResult AlignResult; unsigned MaxAlignmentBits = S.Context.getIntWidth(SrcTy) - 1; - // We can't check validity of alignment if it is type dependent. - if (!AlignOp->isInstantiationDependent() && + // We can't check validity of alignment if it is value dependent. + if (!AlignOp->isValueDependent() && AlignOp->EvaluateAsInt(AlignResult, S.Context, Expr::SE_AllowSideEffects)) { llvm::APSInt AlignValue = AlignResult.Val.getInt(); @@ -282,48 +284,60 @@ static bool SemaBuiltinAlignment(Sema &S, CallExpr *TheCall, unsigned ID) { return false; } -static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall) { +static bool SemaBuiltinOverflow(Sema &S, CallExpr *TheCall, + unsigned BuiltinID) { if (checkArgCount(S, TheCall, 3)) return true; // First two arguments should be integers. for (unsigned I = 0; I < 2; ++I) { - ExprResult Arg = TheCall->getArg(I); + ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(I)); + if (Arg.isInvalid()) return true; + TheCall->setArg(I, Arg.get()); + QualType Ty = Arg.get()->getType(); if (!Ty->isIntegerType()) { S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_int) << Ty << Arg.get()->getSourceRange(); return true; } - InitializedEntity Entity = InitializedEntity::InitializeParameter( - S.getASTContext(), Ty, /*consume*/ false); - Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); - if (Arg.isInvalid()) - return true; - TheCall->setArg(I, Arg.get()); } // Third argument should be a pointer to a non-const integer. // IRGen correctly handles volatile, restrict, and address spaces, and // the other qualifiers aren't possible. { - ExprResult Arg = TheCall->getArg(2); + ExprResult Arg = S.DefaultFunctionArrayLvalueConversion(TheCall->getArg(2)); + if (Arg.isInvalid()) return true; + TheCall->setArg(2, Arg.get()); + QualType Ty = Arg.get()->getType(); const auto *PtrTy = Ty->getAs<PointerType>(); - if (!(PtrTy && PtrTy->getPointeeType()->isIntegerType() && - !PtrTy->getPointeeType().isConstQualified())) { + if (!PtrTy || + !PtrTy->getPointeeType()->isIntegerType() || + PtrTy->getPointeeType().isConstQualified()) { S.Diag(Arg.get()->getBeginLoc(), diag::err_overflow_builtin_must_be_ptr_int) - << Ty << Arg.get()->getSourceRange(); + << Ty << Arg.get()->getSourceRange(); return true; } - InitializedEntity Entity = InitializedEntity::InitializeParameter( - S.getASTContext(), Ty, /*consume*/ false); - Arg = S.PerformCopyInitialization(Entity, SourceLocation(), Arg); - if (Arg.isInvalid()) - return true; - TheCall->setArg(2, Arg.get()); } + + // Disallow signed ExtIntType args larger than 128 bits to mul function until + // we improve backend support. + if (BuiltinID == Builtin::BI__builtin_mul_overflow) { + for (unsigned I = 0; I < 3; ++I) { + const auto Arg = TheCall->getArg(I); + // Third argument will be a pointer. + auto Ty = I < 2 ? Arg->getType() : Arg->getType()->getPointeeType(); + if (Ty->isExtIntType() && Ty->isSignedIntegerType() && + S.getASTContext().getIntWidth(Ty) > 128) + return S.Diag(Arg->getBeginLoc(), + diag::err_overflow_builtin_ext_int_max_size) + << 128; + } + } + return false; } @@ -390,13 +404,194 @@ static bool SemaBuiltinCallWithStaticChain(Sema &S, CallExpr *BuiltinCall) { return false; } +namespace { + +class EstimateSizeFormatHandler + : public analyze_format_string::FormatStringHandler { + size_t Size; + +public: + EstimateSizeFormatHandler(StringRef Format) + : Size(std::min(Format.find(0), Format.size()) + + 1 /* null byte always written by sprintf */) {} + + bool HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, + const char *, unsigned SpecifierLen) override { + + const size_t FieldWidth = computeFieldWidth(FS); + const size_t Precision = computePrecision(FS); + + // The actual format. + switch (FS.getConversionSpecifier().getKind()) { + // Just a char. + case analyze_format_string::ConversionSpecifier::cArg: + case analyze_format_string::ConversionSpecifier::CArg: + Size += std::max(FieldWidth, (size_t)1); + break; + // Just an integer. + case analyze_format_string::ConversionSpecifier::dArg: + case analyze_format_string::ConversionSpecifier::DArg: + case analyze_format_string::ConversionSpecifier::iArg: + case analyze_format_string::ConversionSpecifier::oArg: + case analyze_format_string::ConversionSpecifier::OArg: + case analyze_format_string::ConversionSpecifier::uArg: + case analyze_format_string::ConversionSpecifier::UArg: + case analyze_format_string::ConversionSpecifier::xArg: + case analyze_format_string::ConversionSpecifier::XArg: + Size += std::max(FieldWidth, Precision); + break; + + // %g style conversion switches between %f or %e style dynamically. + // %f always takes less space, so default to it. + case analyze_format_string::ConversionSpecifier::gArg: + case analyze_format_string::ConversionSpecifier::GArg: + + // Floating point number in the form '[+]ddd.ddd'. + case analyze_format_string::ConversionSpecifier::fArg: + case analyze_format_string::ConversionSpecifier::FArg: + Size += std::max(FieldWidth, 1 /* integer part */ + + (Precision ? 1 + Precision + : 0) /* period + decimal */); + break; + + // Floating point number in the form '[-]d.ddde[+-]dd'. + case analyze_format_string::ConversionSpecifier::eArg: + case analyze_format_string::ConversionSpecifier::EArg: + Size += + std::max(FieldWidth, + 1 /* integer part */ + + (Precision ? 1 + Precision : 0) /* period + decimal */ + + 1 /* e or E letter */ + 2 /* exponent */); + break; + + // Floating point number in the form '[-]0xh.hhhhp±dd'. + case analyze_format_string::ConversionSpecifier::aArg: + case analyze_format_string::ConversionSpecifier::AArg: + Size += + std::max(FieldWidth, + 2 /* 0x */ + 1 /* integer part */ + + (Precision ? 1 + Precision : 0) /* period + decimal */ + + 1 /* p or P letter */ + 1 /* + or - */ + 1 /* value */); + break; + + // Just a string. + case analyze_format_string::ConversionSpecifier::sArg: + case analyze_format_string::ConversionSpecifier::SArg: + Size += FieldWidth; + break; + + // Just a pointer in the form '0xddd'. + case analyze_format_string::ConversionSpecifier::pArg: + Size += std::max(FieldWidth, 2 /* leading 0x */ + Precision); + break; + + // A plain percent. + case analyze_format_string::ConversionSpecifier::PercentArg: + Size += 1; + break; + + default: + break; + } + + Size += FS.hasPlusPrefix() || FS.hasSpacePrefix(); + + if (FS.hasAlternativeForm()) { + switch (FS.getConversionSpecifier().getKind()) { + default: + break; + // Force a leading '0'. + case analyze_format_string::ConversionSpecifier::oArg: + Size += 1; + break; + // Force a leading '0x'. + case analyze_format_string::ConversionSpecifier::xArg: + case analyze_format_string::ConversionSpecifier::XArg: + Size += 2; + break; + // Force a period '.' before decimal, even if precision is 0. + case analyze_format_string::ConversionSpecifier::aArg: + case analyze_format_string::ConversionSpecifier::AArg: + case analyze_format_string::ConversionSpecifier::eArg: + case analyze_format_string::ConversionSpecifier::EArg: + case analyze_format_string::ConversionSpecifier::fArg: + case analyze_format_string::ConversionSpecifier::FArg: + case analyze_format_string::ConversionSpecifier::gArg: + case analyze_format_string::ConversionSpecifier::GArg: + Size += (Precision ? 0 : 1); + break; + } + } + assert(SpecifierLen <= Size && "no underflow"); + Size -= SpecifierLen; + return true; + } + + size_t getSizeLowerBound() const { return Size; } + +private: + static size_t computeFieldWidth(const analyze_printf::PrintfSpecifier &FS) { + const analyze_format_string::OptionalAmount &FW = FS.getFieldWidth(); + size_t FieldWidth = 0; + if (FW.getHowSpecified() == analyze_format_string::OptionalAmount::Constant) + FieldWidth = FW.getConstantAmount(); + return FieldWidth; + } + + static size_t computePrecision(const analyze_printf::PrintfSpecifier &FS) { + const analyze_format_string::OptionalAmount &FW = FS.getPrecision(); + size_t Precision = 0; + + // See man 3 printf for default precision value based on the specifier. + switch (FW.getHowSpecified()) { + case analyze_format_string::OptionalAmount::NotSpecified: + switch (FS.getConversionSpecifier().getKind()) { + default: + break; + case analyze_format_string::ConversionSpecifier::dArg: // %d + case analyze_format_string::ConversionSpecifier::DArg: // %D + case analyze_format_string::ConversionSpecifier::iArg: // %i + Precision = 1; + break; + case analyze_format_string::ConversionSpecifier::oArg: // %d + case analyze_format_string::ConversionSpecifier::OArg: // %D + case analyze_format_string::ConversionSpecifier::uArg: // %d + case analyze_format_string::ConversionSpecifier::UArg: // %D + case analyze_format_string::ConversionSpecifier::xArg: // %d + case analyze_format_string::ConversionSpecifier::XArg: // %D + Precision = 1; + break; + case analyze_format_string::ConversionSpecifier::fArg: // %f + case analyze_format_string::ConversionSpecifier::FArg: // %F + case analyze_format_string::ConversionSpecifier::eArg: // %e + case analyze_format_string::ConversionSpecifier::EArg: // %E + case analyze_format_string::ConversionSpecifier::gArg: // %g + case analyze_format_string::ConversionSpecifier::GArg: // %G + Precision = 6; + break; + case analyze_format_string::ConversionSpecifier::pArg: // %d + Precision = 1; + break; + } + break; + case analyze_format_string::OptionalAmount::Constant: + Precision = FW.getConstantAmount(); + break; + default: + break; + } + return Precision; + } +}; + +} // namespace + /// Check a call to BuiltinID for buffer overflows. If BuiltinID is a /// __builtin_*_chk function, then use the object size argument specified in the /// source. Otherwise, infer the object size using __builtin_object_size. void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, CallExpr *TheCall) { // FIXME: There are some more useful checks we could be doing here: - // - Analyze the format string of sprintf to see how much of buffer is used. // - Evaluate strlen of strcpy arguments, use as object size. if (TheCall->isValueDependent() || TheCall->isTypeDependent() || @@ -407,12 +602,55 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (!BuiltinID) return; + const TargetInfo &TI = getASTContext().getTargetInfo(); + unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); + unsigned DiagID = 0; bool IsChkVariant = false; + Optional<llvm::APSInt> UsedSize; unsigned SizeIndex, ObjectIndex; switch (BuiltinID) { default: return; + case Builtin::BIsprintf: + case Builtin::BI__builtin___sprintf_chk: { + size_t FormatIndex = BuiltinID == Builtin::BIsprintf ? 1 : 3; + auto *FormatExpr = TheCall->getArg(FormatIndex)->IgnoreParenImpCasts(); + + if (auto *Format = dyn_cast<StringLiteral>(FormatExpr)) { + + if (!Format->isAscii() && !Format->isUTF8()) + return; + + StringRef FormatStrRef = Format->getString(); + EstimateSizeFormatHandler H(FormatStrRef); + const char *FormatBytes = FormatStrRef.data(); + const ConstantArrayType *T = + Context.getAsConstantArrayType(Format->getType()); + assert(T && "String literal not of constant array type!"); + size_t TypeSize = T->getSize().getZExtValue(); + + // In case there's a null byte somewhere. + size_t StrLen = + std::min(std::max(TypeSize, size_t(1)) - 1, FormatStrRef.find(0)); + if (!analyze_format_string::ParsePrintfString( + H, FormatBytes, FormatBytes + StrLen, getLangOpts(), + Context.getTargetInfo(), false)) { + DiagID = diag::warn_fortify_source_format_overflow; + UsedSize = llvm::APSInt::getUnsigned(H.getSizeLowerBound()) + .extOrTrunc(SizeTypeWidth); + if (BuiltinID == Builtin::BI__builtin___sprintf_chk) { + IsChkVariant = true; + ObjectIndex = 2; + } else { + IsChkVariant = false; + ObjectIndex = 0; + } + break; + } + } + return; + } case Builtin::BI__builtin___memcpy_chk: case Builtin::BI__builtin___memmove_chk: case Builtin::BI__builtin___memset_chk: @@ -505,19 +743,19 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, if (!ObjArg->tryEvaluateObjectSize(Result, getASTContext(), BOSType)) return; // Get the object size in the target's size_t width. - const TargetInfo &TI = getASTContext().getTargetInfo(); - unsigned SizeTypeWidth = TI.getTypeWidth(TI.getSizeType()); ObjectSize = llvm::APSInt::getUnsigned(Result).extOrTrunc(SizeTypeWidth); } // Evaluate the number of bytes of the object that this call will use. - Expr::EvalResult Result; - Expr *UsedSizeArg = TheCall->getArg(SizeIndex); - if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext())) - return; - llvm::APSInt UsedSize = Result.Val.getInt(); + if (!UsedSize) { + Expr::EvalResult Result; + Expr *UsedSizeArg = TheCall->getArg(SizeIndex); + if (!UsedSizeArg->EvaluateAsInt(Result, getASTContext())) + return; + UsedSize = Result.Val.getInt().extOrTrunc(SizeTypeWidth); + } - if (UsedSize.ule(ObjectSize)) + if (UsedSize.getValue().ule(ObjectSize)) return; StringRef FunctionName = getASTContext().BuiltinInfo.getName(BuiltinID); @@ -533,7 +771,7 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD, DiagRuntimeBehavior(TheCall->getBeginLoc(), TheCall, PDiag(DiagID) << FunctionName << ObjectSize.toString(/*Radix=*/10) - << UsedSize.toString(/*Radix=*/10)); + << UsedSize.getValue().toString(/*Radix=*/10)); } static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, @@ -1152,6 +1390,49 @@ CheckBuiltinTargetSupport(Sema &S, unsigned BuiltinID, CallExpr *TheCall, return true; } +static void CheckNonNullArgument(Sema &S, const Expr *ArgExpr, + SourceLocation CallSiteLoc); + +bool Sema::CheckTSBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { + switch (TI.getTriple().getArch()) { + default: + // Some builtins don't require additional checking, so just consider these + // acceptable. + return false; + case llvm::Triple::arm: + case llvm::Triple::armeb: + case llvm::Triple::thumb: + case llvm::Triple::thumbeb: + return CheckARMBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::aarch64: + case llvm::Triple::aarch64_32: + case llvm::Triple::aarch64_be: + return CheckAArch64BuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::bpfeb: + case llvm::Triple::bpfel: + return CheckBPFBuiltinFunctionCall(BuiltinID, TheCall); + case llvm::Triple::hexagon: + return CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall); + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return CheckMipsBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::systemz: + return CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall); + case llvm::Triple::x86: + case llvm::Triple::x86_64: + return CheckX86BuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::ppc64le: + return CheckPPCBuiltinFunctionCall(TI, BuiltinID, TheCall); + case llvm::Triple::amdgcn: + return CheckAMDGCNBuiltinFunctionCall(BuiltinID, TheCall); + } +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -1421,6 +1702,19 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_nontemporal_load: case Builtin::BI__builtin_nontemporal_store: return SemaBuiltinNontemporalOverloaded(TheCallResult); + case Builtin::BI__builtin_memcpy_inline: { + clang::Expr *SizeOp = TheCall->getArg(2); + // We warn about copying to or from `nullptr` pointers when `size` is + // greater than 0. When `size` is value dependent we cannot evaluate its + // value so we bail out. + if (SizeOp->isValueDependent()) + break; + if (!SizeOp->EvaluateKnownConstInt(Context).isNullValue()) { + CheckNonNullArgument(*this, TheCall->getArg(0), TheCall->getExprLoc()); + CheckNonNullArgument(*this, TheCall->getArg(1), TheCall->getExprLoc()); + } + break; + } #define BUILTIN(ID, TYPE, ATTRS) #define ATOMIC_BUILTIN(ID, TYPE, ATTRS) \ case Builtin::BI##ID: \ @@ -1447,7 +1741,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin_add_overflow: case Builtin::BI__builtin_sub_overflow: case Builtin::BI__builtin_mul_overflow: - if (SemaBuiltinOverflow(*this, TheCall)) + if (SemaBuiltinOverflow(*this, TheCall, BuiltinID)) return ExprError(); break; case Builtin::BI__builtin_operator_new: @@ -1515,6 +1809,36 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.IntTy); break; } + case Builtin::BI__builtin_expect_with_probability: { + // We first want to ensure we are called with 3 arguments + if (checkArgCount(*this, TheCall, 3)) + return ExprError(); + // then check probability is constant float in range [0.0, 1.0] + const Expr *ProbArg = TheCall->getArg(2); + SmallVector<PartialDiagnosticAt, 8> Notes; + Expr::EvalResult Eval; + Eval.Diag = &Notes; + if ((!ProbArg->EvaluateAsConstantExpr(Eval, Expr::EvaluateForCodeGen, + Context)) || + !Eval.Val.isFloat()) { + Diag(ProbArg->getBeginLoc(), diag::err_probability_not_constant_float) + << ProbArg->getSourceRange(); + for (const PartialDiagnosticAt &PDiag : Notes) + Diag(PDiag.first, PDiag.second); + return ExprError(); + } + llvm::APFloat Probability = Eval.Val.getFloat(); + bool LoseInfo = false; + Probability.convert(llvm::APFloat::IEEEdouble(), + llvm::RoundingMode::Dynamic, &LoseInfo); + if (!(Probability >= llvm::APFloat(0.0) && + Probability <= llvm::APFloat(1.0))) { + Diag(ProbArg->getBeginLoc(), diag::err_probability_out_of_range) + << ProbArg->getSourceRange(); + return ExprError(); + } + break; + } case Builtin::BI__builtin_preserve_access_index: if (SemaBuiltinPreserveAI(*this, TheCall)) return ExprError(); @@ -1608,62 +1932,55 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, return ExprError(); break; case Builtin::BI__builtin_os_log_format: + Cleanup.setExprNeedsCleanups(true); + LLVM_FALLTHROUGH; case Builtin::BI__builtin_os_log_format_buffer_size: if (SemaBuiltinOSLogFormat(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_frame_address: + case Builtin::BI__builtin_return_address: { + if (SemaBuiltinConstantArgRange(TheCall, 0, 0, 0xFFFF)) + return ExprError(); + + // -Wframe-address warning if non-zero passed to builtin + // return/frame address. + Expr::EvalResult Result; + if (TheCall->getArg(0)->EvaluateAsInt(Result, getASTContext()) && + Result.Val.getInt() != 0) + Diag(TheCall->getBeginLoc(), diag::warn_frame_address) + << ((BuiltinID == Builtin::BI__builtin_return_address) + ? "__builtin_return_address" + : "__builtin_frame_address") + << TheCall->getSourceRange(); + break; + } + + case Builtin::BI__builtin_matrix_transpose: + return SemaBuiltinMatrixTranspose(TheCall, TheCallResult); + + case Builtin::BI__builtin_matrix_column_major_load: + return SemaBuiltinMatrixColumnMajorLoad(TheCall, TheCallResult); + + case Builtin::BI__builtin_matrix_column_major_store: + return SemaBuiltinMatrixColumnMajorStore(TheCall, TheCallResult); } // Since the target specific builtins for each arch overlap, only check those // of the arch we are compiling for. if (Context.BuiltinInfo.isTSBuiltin(BuiltinID)) { - switch (Context.getTargetInfo().getTriple().getArch()) { - case llvm::Triple::arm: - case llvm::Triple::armeb: - case llvm::Triple::thumb: - case llvm::Triple::thumbeb: - if (CheckARMBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::aarch64: - case llvm::Triple::aarch64_32: - case llvm::Triple::aarch64_be: - if (CheckAArch64BuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::bpfeb: - case llvm::Triple::bpfel: - if (CheckBPFBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::hexagon: - if (CheckHexagonBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - if (CheckMipsBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::systemz: - if (CheckSystemZBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::x86: - case llvm::Triple::x86_64: - if (CheckX86BuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::ppc64le: - if (CheckPPCBuiltinFunctionCall(BuiltinID, TheCall)) - return ExprError(); - break; - default: - break; + if (Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) { + assert(Context.getAuxTargetInfo() && + "Aux Target Builtin, but not an aux target?"); + + if (CheckTSBuiltinFunctionCall( + *Context.getAuxTargetInfo(), + Context.BuiltinInfo.getAuxBuiltinID(BuiltinID), TheCall)) + return ExprError(); + } else { + if (CheckTSBuiltinFunctionCall(Context.getTargetInfo(), BuiltinID, + TheCall)) + return ExprError(); } } @@ -1697,6 +2014,9 @@ static unsigned RFT(unsigned t, bool shift = false, bool ForceQuad = false) { case NeonTypeFlags::Float64: assert(!shift && "cannot shift float types!"); return (1 << IsQuad) - 1; + case NeonTypeFlags::BFloat16: + assert(!shift && "cannot shift float types!"); + return (4 << IsQuad) - 1; } llvm_unreachable("Invalid NeonTypeFlag!"); } @@ -1736,11 +2056,135 @@ static QualType getNeonEltType(NeonTypeFlags Flags, ASTContext &Context, return Context.FloatTy; case NeonTypeFlags::Float64: return Context.DoubleTy; + case NeonTypeFlags::BFloat16: + return Context.BFloat16Ty; } llvm_unreachable("Invalid NeonTypeFlag!"); } -bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckSVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + // Range check SVE intrinsics that take immediate values. + SmallVector<std::tuple<int,int,int>, 3> ImmChecks; + + switch (BuiltinID) { + default: + return false; +#define GET_SVE_IMMEDIATE_CHECK +#include "clang/Basic/arm_sve_sema_rangechecks.inc" +#undef GET_SVE_IMMEDIATE_CHECK + } + + // Perform all the immediate checks for this builtin call. + bool HasError = false; + for (auto &I : ImmChecks) { + int ArgNum, CheckTy, ElementSizeInBits; + std::tie(ArgNum, CheckTy, ElementSizeInBits) = I; + + typedef bool(*OptionSetCheckFnTy)(int64_t Value); + + // Function that checks whether the operand (ArgNum) is an immediate + // that is one of the predefined values. + auto CheckImmediateInSet = [&](OptionSetCheckFnTy CheckImm, + int ErrDiag) -> bool { + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + llvm::APSInt Imm; + if (SemaBuiltinConstantArg(TheCall, ArgNum, Imm)) + return true; + + if (!CheckImm(Imm.getSExtValue())) + return Diag(TheCall->getBeginLoc(), ErrDiag) << Arg->getSourceRange(); + return false; + }; + + switch ((SVETypeFlags::ImmCheckType)CheckTy) { + case SVETypeFlags::ImmCheck0_31: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 31)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_13: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 13)) + HasError = true; + break; + case SVETypeFlags::ImmCheck1_16: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, 16)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_7: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 7)) + HasError = true; + break; + case SVETypeFlags::ImmCheckExtract: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, + (2048 / ElementSizeInBits) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftRight: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, ElementSizeInBits)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftRightNarrow: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 1, + ElementSizeInBits / 2)) + HasError = true; + break; + case SVETypeFlags::ImmCheckShiftLeft: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, + ElementSizeInBits - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndex: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (1 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndexCompRotate: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (2 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckLaneIndexDot: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, + (128 / (4 * ElementSizeInBits)) - 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheckComplexRot90_270: + if (CheckImmediateInSet([](int64_t V) { return V == 90 || V == 270; }, + diag::err_rotation_argument_to_cadd)) + HasError = true; + break; + case SVETypeFlags::ImmCheckComplexRotAll90: + if (CheckImmediateInSet( + [](int64_t V) { + return V == 0 || V == 90 || V == 180 || V == 270; + }, + diag::err_rotation_argument_to_cmla)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_1: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 1)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_2: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 2)) + HasError = true; + break; + case SVETypeFlags::ImmCheck0_3: + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, 0, 3)) + HasError = true; + break; + } + } + + return HasError; +} + +bool Sema::CheckNeonBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, CallExpr *TheCall) { llvm::APSInt Result; uint64_t mask = 0; unsigned TV = 0; @@ -1774,12 +2218,11 @@ bool Sema::CheckNeonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { ExprResult RHS = DefaultFunctionArrayLvalueConversion(Arg); QualType RHSTy = RHS.get()->getType(); - llvm::Triple::ArchType Arch = Context.getTargetInfo().getTriple().getArch(); + llvm::Triple::ArchType Arch = TI.getTriple().getArch(); bool IsPolyUnsigned = Arch == llvm::Triple::aarch64 || Arch == llvm::Triple::aarch64_32 || Arch == llvm::Triple::aarch64_be; - bool IsInt64Long = - Context.getTargetInfo().getInt64Type() == TargetInfo::SignedLong; + bool IsInt64Long = TI.getInt64Type() == TargetInfo::SignedLong; QualType EltTy = getNeonEltType(NeonTypeFlags(TV), Context, IsPolyUnsigned, IsInt64Long); if (HasConstPtr) @@ -1817,6 +2260,47 @@ bool Sema::CheckMVEBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { } } +bool Sema::CheckCDEBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { + bool Err = false; + switch (BuiltinID) { + default: + return false; +#include "clang/Basic/arm_cde_builtin_sema.inc" + } + + if (Err) + return true; + + return CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), /*WantCDE*/ true); +} + +bool Sema::CheckARMCoprocessorImmediate(const TargetInfo &TI, + const Expr *CoprocArg, bool WantCDE) { + if (isConstantEvaluated()) + return false; + + // We can't check the value of a dependent argument. + if (CoprocArg->isTypeDependent() || CoprocArg->isValueDependent()) + return false; + + llvm::APSInt CoprocNoAP; + bool IsICE = CoprocArg->isIntegerConstantExpr(CoprocNoAP, Context); + (void)IsICE; + assert(IsICE && "Coprocossor immediate is not a constant expression"); + int64_t CoprocNo = CoprocNoAP.getExtValue(); + assert(CoprocNo >= 0 && "Coprocessor immediate must be non-negative"); + + uint32_t CDECoprocMask = TI.getARMCDECoprocMask(); + bool IsCDECoproc = CoprocNo <= 7 && (CDECoprocMask & (1 << CoprocNo)); + + if (IsCDECoproc != WantCDE) + return Diag(CoprocArg->getBeginLoc(), diag::err_arm_invalid_coproc) + << (int)CoprocNo << (int)WantCDE << CoprocArg->getSourceRange(); + + return false; +} + bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, unsigned MaxWidth) { assert((BuiltinID == ARM::BI__builtin_arm_ldrex || @@ -1932,7 +2416,8 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, return false; } -bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckARMBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { if (BuiltinID == ARM::BI__builtin_arm_ldrex || BuiltinID == ARM::BI__builtin_arm_ldaex || BuiltinID == ARM::BI__builtin_arm_strex || @@ -1955,10 +2440,12 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { BuiltinID == ARM::BI__builtin_arm_wsrp) return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); - if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) + if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) return true; if (CheckMVEBuiltinFunctionCall(BuiltinID, TheCall)) return true; + if (CheckCDEBuiltinFunctionCall(TI, BuiltinID, TheCall)) + return true; // For intrinsics which take an immediate value as part of the instruction, // range check them here. @@ -1981,11 +2468,33 @@ bool Sema::CheckARMBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case ARM::BI__builtin_arm_isb: case ARM::BI__builtin_arm_dbg: return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15); - } -} - -bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, - CallExpr *TheCall) { + case ARM::BI__builtin_arm_cdp: + case ARM::BI__builtin_arm_cdp2: + case ARM::BI__builtin_arm_mcr: + case ARM::BI__builtin_arm_mcr2: + case ARM::BI__builtin_arm_mrc: + case ARM::BI__builtin_arm_mrc2: + case ARM::BI__builtin_arm_mcrr: + case ARM::BI__builtin_arm_mcrr2: + case ARM::BI__builtin_arm_mrrc: + case ARM::BI__builtin_arm_mrrc2: + case ARM::BI__builtin_arm_ldc: + case ARM::BI__builtin_arm_ldcl: + case ARM::BI__builtin_arm_ldc2: + case ARM::BI__builtin_arm_ldc2l: + case ARM::BI__builtin_arm_stc: + case ARM::BI__builtin_arm_stcl: + case ARM::BI__builtin_arm_stc2: + case ARM::BI__builtin_arm_stc2l: + return SemaBuiltinConstantArgRange(TheCall, 0, 0, 15) || + CheckARMCoprocessorImmediate(TI, TheCall->getArg(0), + /*WantCDE*/ false); + } +} + +bool Sema::CheckAArch64BuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, + CallExpr *TheCall) { if (BuiltinID == AArch64::BI__builtin_arm_ldrex || BuiltinID == AArch64::BI__builtin_arm_ldaex || BuiltinID == AArch64::BI__builtin_arm_strex || @@ -2030,7 +2539,10 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, if (BuiltinID == AArch64::BI__getReg) return SemaBuiltinConstantArgRange(TheCall, 0, 0, 31); - if (CheckNeonBuiltinFunctionCall(BuiltinID, TheCall)) + if (CheckNeonBuiltinFunctionCall(TI, BuiltinID, TheCall)) + return true; + + if (CheckSVEBuiltinFunctionCall(BuiltinID, TheCall)) return true; // For intrinsics which take an immediate value as part of the instruction, @@ -2049,17 +2561,33 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - assert(BuiltinID == BPF::BI__builtin_preserve_field_info && + assert((BuiltinID == BPF::BI__builtin_preserve_field_info || + BuiltinID == BPF::BI__builtin_btf_type_id) && "unexpected ARM builtin"); if (checkArgCount(*this, TheCall, 2)) return true; + Expr *Arg; + if (BuiltinID == BPF::BI__builtin_btf_type_id) { + // The second argument needs to be a constant int + llvm::APSInt Value; + Arg = TheCall->getArg(1); + if (!Arg->isIntegerConstantExpr(Value, Context)) { + Diag(Arg->getBeginLoc(), diag::err_btf_type_id_not_const) + << 2 << Arg->getSourceRange(); + return true; + } + + TheCall->setType(Context.UnsignedIntTy); + return false; + } + // The first argument needs to be a record field access. // If it is an array element access, we delay decision // to BPF backend to check whether the access is a // field access or not. - Expr *Arg = TheCall->getArg(0); + Arg = TheCall->getArg(0); if (Arg->getType()->getAsPlaceholderType() || (Arg->IgnoreParens()->getObjectKind() != OK_BitField && !dyn_cast<MemberExpr>(Arg->IgnoreParens()) && @@ -2070,8 +2598,9 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, } // The second argument needs to be a constant int + Arg = TheCall->getArg(1); llvm::APSInt Value; - if (!TheCall->getArg(1)->isIntegerConstantExpr(Value, Context)) { + if (!Arg->isIntegerConstantExpr(Value, Context)) { Diag(Arg->getBeginLoc(), diag::err_preserve_field_info_not_const) << 2 << Arg->getSourceRange(); return true; @@ -2081,825 +2610,6 @@ bool Sema::CheckBPFBuiltinFunctionCall(unsigned BuiltinID, return false; } -bool Sema::CheckHexagonBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { - struct BuiltinAndString { - unsigned BuiltinID; - const char *Str; - }; - - static BuiltinAndString ValidCPU[] = { - { Hexagon::BI__builtin_HEXAGON_A6_vcmpbeq_notany, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_A6_vminub_RdP, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_F2_dfadd, "v66" }, - { Hexagon::BI__builtin_HEXAGON_F2_dfsub, "v66" }, - { Hexagon::BI__builtin_HEXAGON_M2_mnaci, "v66" }, - { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_M6_vabsdiffub, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S2_mask, "v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_nac, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_p_xacc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_nac, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_rol_i_r_xacc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_vsplatrbp, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_vtrunehb_ppp, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_S6_vtrunohb_ppp, "v62,v65,v66" }, - }; - - static BuiltinAndString ValidHVX[] = { - { Hexagon::BI__builtin_HEXAGON_V6_hi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_hi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lo, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lo_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_extractw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_extractw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplatb_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplath, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplath_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_lvsplatw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_and_n_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_not, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_not_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_or_n_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_scalar2v2_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_pred_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_shuffeqh_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_shuffeqw_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsb, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsb_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsb_sat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsdiffw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsh_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vabsw_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddb_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddbsat_dv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddcarrysat, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddcarrysat_128B, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddclbh_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddclbw_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddh_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddhw_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubh_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddubsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddububb_sat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduhw_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vadduwsat_dv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddw_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaddwsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_valignb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_valignb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_valignbi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vand, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vand_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandnqrt_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandqrt, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandqrt_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvnqv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvqv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvqv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvrt, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vandvrt_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslh_acc_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslhv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslhv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslw_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslwv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vaslwv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrh_acc_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhbrndsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhbsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhubrndsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhubsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrhv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasr_into, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasr_into_128B, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruhubrndsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruhubsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhrndsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasruwuhsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrw_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwhrndsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhrndsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwuhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vasrwv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vassign, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vassign_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vassignp, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vassignp_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgb, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgb_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgbrnd_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavghrnd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgubrnd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguhrnd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguw, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguw_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavguwrnd_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vavgwrnd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcl0h, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcl0h_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcl0w, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcl0w_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcombine, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vcombine_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vd0, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vd0_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdd0, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdd0_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealb4w_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdealvdd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdelta, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdelta_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpybus_dv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhb_dv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhisat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsuisat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhsusat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdmpyhvsat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vdsaduh_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqb_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqh_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_veqw_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtb_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgth_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtub_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuh_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtuw_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_and_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_or_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vgtw_xor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vinsertwr_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlalignbi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrb_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrhv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlsrwv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlut4, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlut4_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvbi_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_nm_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvvb_oracci_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwhi_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_nm_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vlutvwh_oracci_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxb_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmaxw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminb_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vminw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabusv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuu_acc_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpabuuv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpahhsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhb_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpauhuhsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpsuhuhsat_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybusv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpybv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyewuh_64_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyh_acc_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsat_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhsrs_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhss_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyhvsrs_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyieoh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewh_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiewuh_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyih, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyih_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyihb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiowh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwh_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyiwub_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_64_acc_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_rnd_sacc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyowh_sacc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyub_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyubv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuh_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhe_acc_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmpyuhv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmux, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vmux_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgb, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgb_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnavgw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnormamth, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnormamth_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnormamtw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnot, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vnot_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackeb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackeb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackeh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackeh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackhb_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackhub_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackob, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackob_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackoh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackoh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackwh_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpackwuh_sat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vpopcounth_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqb_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqh_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vprefixqw_128B, "v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrdelta, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrdelta_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_128B, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybub_rtt_acc_128B, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusi_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybusv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpybv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubi_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_128B, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyub_rtt_acc_128B, "v65" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrmpyubv_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vror, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vror_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrotr, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrotr_128B, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundhb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundhb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundhub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundhub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrounduhub_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrounduwuh_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundwh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundwh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vroundwuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vrsadubi_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatdw, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatdw_128B, "v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsathub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsathub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatuwuh_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatwh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsatwh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufeh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufeh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffeb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffob, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffob_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshuffvdd_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoeb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoeh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vshufoh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubb_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubbsat_dv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubh_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubhw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsububsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubububb_sat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuhw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubuwsat_dv_128B, "v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubw, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubw_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubw_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vsubwsat_dv_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vswap, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vswap_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpybus_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vtmpyhb_acc_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackob, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackob_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackoh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackub, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackub_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vunpackuh_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vxor, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vxor_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vzb, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vzb_128B, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vzh, "v60,v62,v65,v66" }, - { Hexagon::BI__builtin_HEXAGON_V6_vzh_128B, "v60,v62,v65,v66" }, - }; - - // Sort the tables on first execution so we can binary search them. - auto SortCmp = [](const BuiltinAndString &LHS, const BuiltinAndString &RHS) { - return LHS.BuiltinID < RHS.BuiltinID; - }; - static const bool SortOnce = - (llvm::sort(ValidCPU, SortCmp), - llvm::sort(ValidHVX, SortCmp), true); - (void)SortOnce; - auto LowerBoundCmp = [](const BuiltinAndString &BI, unsigned BuiltinID) { - return BI.BuiltinID < BuiltinID; - }; - - const TargetInfo &TI = Context.getTargetInfo(); - - const BuiltinAndString *FC = - llvm::lower_bound(ValidCPU, BuiltinID, LowerBoundCmp); - if (FC != std::end(ValidCPU) && FC->BuiltinID == BuiltinID) { - const TargetOptions &Opts = TI.getTargetOpts(); - StringRef CPU = Opts.CPU; - if (!CPU.empty()) { - assert(CPU.startswith("hexagon") && "Unexpected CPU name"); - CPU.consume_front("hexagon"); - SmallVector<StringRef, 3> CPUs; - StringRef(FC->Str).split(CPUs, ','); - if (llvm::none_of(CPUs, [CPU](StringRef S) { return S == CPU; })) - return Diag(TheCall->getBeginLoc(), - diag::err_hexagon_builtin_unsupported_cpu); - } - } - - const BuiltinAndString *FH = - llvm::lower_bound(ValidHVX, BuiltinID, LowerBoundCmp); - if (FH != std::end(ValidHVX) && FH->BuiltinID == BuiltinID) { - if (!TI.hasFeature("hvx")) - return Diag(TheCall->getBeginLoc(), - diag::err_hexagon_builtin_requires_hvx); - - SmallVector<StringRef, 3> HVXs; - StringRef(FH->Str).split(HVXs, ','); - bool IsValid = llvm::any_of(HVXs, - [&TI] (StringRef V) { - std::string F = "hvx" + V.str(); - return TI.hasFeature(F); - }); - if (!IsValid) - return Diag(TheCall->getBeginLoc(), - diag::err_hexagon_builtin_unsupported_hvx); - } - - return false; -} - bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { struct ArgInfo { uint8_t OpNum; @@ -2916,7 +2626,7 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { { Hexagon::BI__builtin_circ_ldd, {{ 3, true, 4, 3 }} }, { Hexagon::BI__builtin_circ_ldw, {{ 3, true, 4, 2 }} }, { Hexagon::BI__builtin_circ_ldh, {{ 3, true, 4, 1 }} }, - { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 0 }} }, + { Hexagon::BI__builtin_circ_lduh, {{ 3, true, 4, 1 }} }, { Hexagon::BI__builtin_circ_ldb, {{ 3, true, 4, 0 }} }, { Hexagon::BI__builtin_circ_ldub, {{ 3, true, 4, 0 }} }, { Hexagon::BI__builtin_circ_std, {{ 3, true, 4, 3 }} }, @@ -3137,17 +2847,17 @@ bool Sema::CheckHexagonBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { bool Sema::CheckHexagonBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - return CheckHexagonBuiltinCpu(BuiltinID, TheCall) || - CheckHexagonBuiltinArgument(BuiltinID, TheCall); + return CheckHexagonBuiltinArgument(BuiltinID, TheCall); } -bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - return CheckMipsBuiltinCpu(BuiltinID, TheCall) || +bool Sema::CheckMipsBuiltinFunctionCall(const TargetInfo &TI, + unsigned BuiltinID, CallExpr *TheCall) { + return CheckMipsBuiltinCpu(TI, BuiltinID, TheCall) || CheckMipsBuiltinArgument(BuiltinID, TheCall); } -bool Sema::CheckMipsBuiltinCpu(unsigned BuiltinID, CallExpr *TheCall) { - const TargetInfo &TI = Context.getTargetInfo(); +bool Sema::CheckMipsBuiltinCpu(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { if (Mips::BI__builtin_mips_addu_qb <= BuiltinID && BuiltinID <= Mips::BI__builtin_mips_lwx) { @@ -3340,10 +3050,14 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 2; break; case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 4; break; case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_ldr_d: i = 1; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_ldr_w: i = 1; l = -2048; u = 2044; m = 4; break; case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 1; break; case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 2; break; case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 4; break; case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_str_d: i = 2; l = -4096; u = 4088; m = 8; break; + case Mips::BI__builtin_msa_str_w: i = 2; l = -2048; u = 2044; m = 4; break; } if (!m) @@ -3353,15 +3067,13 @@ bool Sema::CheckMipsBuiltinArgument(unsigned BuiltinID, CallExpr *TheCall) { SemaBuiltinConstantArgMultiple(TheCall, i, m); } -bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckPPCBuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { unsigned i = 0, l = 0, u = 0; bool Is64BitBltin = BuiltinID == PPC::BI__builtin_divde || BuiltinID == PPC::BI__builtin_divdeu || BuiltinID == PPC::BI__builtin_bpermd; - bool IsTarget64Bit = Context.getTargetInfo() - .getTypeWidth(Context - .getTargetInfo() - .getIntPtrType()) == 64; + bool IsTarget64Bit = TI.getTypeWidth(TI.getIntPtrType()) == 64; bool IsBltinExtDiv = BuiltinID == PPC::BI__builtin_divwe || BuiltinID == PPC::BI__builtin_divweu || BuiltinID == PPC::BI__builtin_divde || @@ -3371,14 +3083,13 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { return Diag(TheCall->getBeginLoc(), diag::err_64_bit_builtin_32_bit_tgt) << TheCall->getSourceRange(); - if ((IsBltinExtDiv && !Context.getTargetInfo().hasFeature("extdiv")) || - (BuiltinID == PPC::BI__builtin_bpermd && - !Context.getTargetInfo().hasFeature("bpermd"))) + if ((IsBltinExtDiv && !TI.hasFeature("extdiv")) || + (BuiltinID == PPC::BI__builtin_bpermd && !TI.hasFeature("bpermd"))) return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_only_on_pwr7) << TheCall->getSourceRange(); auto SemaVSXCheck = [&](CallExpr *TheCall) -> bool { - if (!Context.getTargetInfo().hasFeature("vsx")) + if (!TI.hasFeature("vsx")) return Diag(TheCall->getBeginLoc(), diag::err_ppc_builtin_only_on_pwr7) << TheCall->getSourceRange(); return false; @@ -3414,10 +3125,75 @@ bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { SemaBuiltinConstantArgRange(TheCall, 1, 0, 1); case PPC::BI__builtin_pack_vector_int128: return SemaVSXCheck(TheCall); + case PPC::BI__builtin_altivec_vgnb: + return SemaBuiltinConstantArgRange(TheCall, 1, 2, 7); + case PPC::BI__builtin_vsx_xxeval: + return SemaBuiltinConstantArgRange(TheCall, 3, 0, 255); + case PPC::BI__builtin_altivec_vsldbi: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + case PPC::BI__builtin_altivec_vsrdbi: + return SemaBuiltinConstantArgRange(TheCall, 2, 0, 7); + case PPC::BI__builtin_vsx_xxpermx: + return SemaBuiltinConstantArgRange(TheCall, 3, 0, 7); } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } +bool Sema::CheckAMDGCNBuiltinFunctionCall(unsigned BuiltinID, + CallExpr *TheCall) { + // position of memory order and scope arguments in the builtin + unsigned OrderIndex, ScopeIndex; + switch (BuiltinID) { + case AMDGPU::BI__builtin_amdgcn_atomic_inc32: + case AMDGPU::BI__builtin_amdgcn_atomic_inc64: + case AMDGPU::BI__builtin_amdgcn_atomic_dec32: + case AMDGPU::BI__builtin_amdgcn_atomic_dec64: + OrderIndex = 2; + ScopeIndex = 3; + break; + case AMDGPU::BI__builtin_amdgcn_fence: + OrderIndex = 0; + ScopeIndex = 1; + break; + default: + return false; + } + + ExprResult Arg = TheCall->getArg(OrderIndex); + auto ArgExpr = Arg.get(); + Expr::EvalResult ArgResult; + + if (!ArgExpr->EvaluateAsInt(ArgResult, Context)) + return Diag(ArgExpr->getExprLoc(), diag::err_typecheck_expect_int) + << ArgExpr->getType(); + int ord = ArgResult.Val.getInt().getZExtValue(); + + // Check valididty of memory ordering as per C11 / C++11's memody model. + switch (static_cast<llvm::AtomicOrderingCABI>(ord)) { + case llvm::AtomicOrderingCABI::acquire: + case llvm::AtomicOrderingCABI::release: + case llvm::AtomicOrderingCABI::acq_rel: + case llvm::AtomicOrderingCABI::seq_cst: + break; + default: { + return Diag(ArgExpr->getBeginLoc(), + diag::warn_atomic_op_has_invalid_memory_order) + << ArgExpr->getSourceRange(); + } + } + + Arg = TheCall->getArg(ScopeIndex); + ArgExpr = Arg.get(); + Expr::EvalResult ArgResult1; + // Check that sync scope is a constant literal + if (!ArgExpr->EvaluateAsConstantExpr(ArgResult1, Expr::EvaluateForCodeGen, + Context)) + return Diag(ArgExpr->getExprLoc(), diag::err_expr_not_string_literal) + << ArgExpr->getType(); + + return false; +} + bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (BuiltinID == SystemZ::BI__builtin_tabort) { @@ -3486,7 +3262,8 @@ bool Sema::CheckSystemZBuiltinFunctionCall(unsigned BuiltinID, /// SemaBuiltinCpuSupports - Handle __builtin_cpu_supports(char *). /// This checks that the target supports __builtin_cpu_supports and /// that the string argument is constant and valid. -static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { +static bool SemaBuiltinCpuSupports(Sema &S, const TargetInfo &TI, + CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); // Check if the argument is a string literal. @@ -3497,7 +3274,7 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { // Check the contents of the string. StringRef Feature = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); - if (!S.Context.getTargetInfo().validateCpuSupports(Feature)) + if (!TI.validateCpuSupports(Feature)) return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_supports) << Arg->getSourceRange(); return false; @@ -3506,7 +3283,7 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { /// SemaBuiltinCpuIs - Handle __builtin_cpu_is(char *). /// This checks that the target supports __builtin_cpu_is and /// that the string argument is constant and valid. -static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) { +static bool SemaBuiltinCpuIs(Sema &S, const TargetInfo &TI, CallExpr *TheCall) { Expr *Arg = TheCall->getArg(0); // Check if the argument is a string literal. @@ -3517,7 +3294,7 @@ static bool SemaBuiltinCpuIs(Sema &S, CallExpr *TheCall) { // Check the contents of the string. StringRef Feature = cast<StringLiteral>(Arg->IgnoreParenImpCasts())->getString(); - if (!S.Context.getTargetInfo().validateCpuIs(Feature)) + if (!TI.validateCpuIs(Feature)) return S.Diag(TheCall->getBeginLoc(), diag::err_invalid_cpu_is) << Arg->getSourceRange(); return false; @@ -3831,6 +3608,64 @@ bool Sema::CheckX86BuiltinGatherScatterScale(unsigned BuiltinID, << Arg->getSourceRange(); } +enum { TileRegLow = 0, TileRegHigh = 7 }; + +bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, + ArrayRef<int> ArgNums) { + for (int ArgNum : ArgNums) { + if (SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh)) + return true; + } + return false; +} + +bool Sema::CheckX86BuiltinTileArgumentsRange(CallExpr *TheCall, int ArgNum) { + return SemaBuiltinConstantArgRange(TheCall, ArgNum, TileRegLow, TileRegHigh); +} + +bool Sema::CheckX86BuiltinTileDuplicate(CallExpr *TheCall, + ArrayRef<int> ArgNums) { + // Because the max number of tile register is TileRegHigh + 1, so here we use + // each bit to represent the usage of them in bitset. + std::bitset<TileRegHigh + 1> ArgValues; + for (int ArgNum : ArgNums) { + llvm::APSInt Arg; + SemaBuiltinConstantArg(TheCall, ArgNum, Arg); + int ArgExtValue = Arg.getExtValue(); + assert((ArgExtValue >= TileRegLow || ArgExtValue <= TileRegHigh) && + "Incorrect tile register num."); + if (ArgValues.test(ArgExtValue)) + return Diag(TheCall->getBeginLoc(), + diag::err_x86_builtin_tile_arg_duplicate) + << TheCall->getArg(ArgNum)->getSourceRange(); + ArgValues.set(ArgExtValue); + } + return false; +} + +bool Sema::CheckX86BuiltinTileRangeAndDuplicate(CallExpr *TheCall, + ArrayRef<int> ArgNums) { + return CheckX86BuiltinTileArgumentsRange(TheCall, ArgNums) || + CheckX86BuiltinTileDuplicate(TheCall, ArgNums); +} + +bool Sema::CheckX86BuiltinTileArguments(unsigned BuiltinID, CallExpr *TheCall) { + switch (BuiltinID) { + default: + return false; + case X86::BI__builtin_ia32_tileloadd64: + case X86::BI__builtin_ia32_tileloaddt164: + case X86::BI__builtin_ia32_tilestored64: + case X86::BI__builtin_ia32_tilezero: + return CheckX86BuiltinTileArgumentsRange(TheCall, 0); + case X86::BI__builtin_ia32_tdpbssd: + case X86::BI__builtin_ia32_tdpbsud: + case X86::BI__builtin_ia32_tdpbusd: + case X86::BI__builtin_ia32_tdpbuud: + case X86::BI__builtin_ia32_tdpbf16ps: + return CheckX86BuiltinTileRangeAndDuplicate(TheCall, {0, 1, 2}); + } +} static bool isX86_32Builtin(unsigned BuiltinID) { // These builtins only work on x86-32 targets. switch (BuiltinID) { @@ -3842,15 +3677,16 @@ static bool isX86_32Builtin(unsigned BuiltinID) { return false; } -bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { +bool Sema::CheckX86BuiltinFunctionCall(const TargetInfo &TI, unsigned BuiltinID, + CallExpr *TheCall) { if (BuiltinID == X86::BI__builtin_cpu_supports) - return SemaBuiltinCpuSupports(*this, TheCall); + return SemaBuiltinCpuSupports(*this, TI, TheCall); if (BuiltinID == X86::BI__builtin_cpu_is) - return SemaBuiltinCpuIs(*this, TheCall); + return SemaBuiltinCpuIs(*this, TI, TheCall); // Check for 32-bit only builtins on a 64-bit target. - const llvm::Triple &TT = Context.getTargetInfo().getTriple(); + const llvm::Triple &TT = TI.getTriple(); if (TT.getArch() != llvm::Triple::x86 && isX86_32Builtin(BuiltinID)) return Diag(TheCall->getCallee()->getBeginLoc(), diag::err_32_bit_builtin_64_bit_tgt); @@ -3863,6 +3699,10 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { if (CheckX86BuiltinGatherScatterScale(BuiltinID, TheCall)) return true; + // If the intrinsic has a tile arguments, make sure they are valid. + if (CheckX86BuiltinTileArguments(BuiltinID, TheCall)) + return true; + // For intrinsics which take an immediate value as part of the instruction, // range check them here. int i = 0, l = 0, u = 0; @@ -4473,6 +4313,24 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, } } + if (FDecl && FDecl->hasAttr<AllocAlignAttr>()) { + auto *AA = FDecl->getAttr<AllocAlignAttr>(); + const Expr *Arg = Args[AA->getParamIndex().getASTIndex()]; + if (!Arg->isValueDependent()) { + Expr::EvalResult Align; + if (Arg->EvaluateAsInt(Align, Context)) { + const llvm::APSInt &I = Align.Val.getInt(); + if (!I.isPowerOf2()) + Diag(Arg->getExprLoc(), diag::warn_alignment_not_power_of_two) + << Arg->getSourceRange(); + + if (I > Sema::MaximumAlignment) + Diag(Arg->getExprLoc(), diag::warn_assume_aligned_too_great) + << Arg->getSourceRange() << Sema::MaximumAlignment; + } + } + } + if (FD) diagnoseArgDependentDiagnoseIfAttrs(FD, ThisArg, Args, Loc); } @@ -5491,6 +5349,15 @@ Sema::SemaBuiltinAtomicOverloaded(ExprResult TheCallResult) { // gracefully. TheCall->setType(ResultType); + // Prohibit use of _ExtInt with atomic builtins. + // The arguments would have already been converted to the first argument's + // type, so only need to check the first argument. + const auto *ExtIntValType = ValType->getAs<ExtIntType>(); + if (ExtIntValType && !llvm::isPowerOf2_64(ExtIntValType->getNumBits())) { + Diag(FirstArg->getExprLoc(), diag::err_atomic_builtin_ext_int_size); + return ExprError(); + } + return TheCallResult; } @@ -6193,11 +6060,9 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return Diag(TheCall->getBeginLoc(), diag::err_alignment_not_power_of_two) << Arg->getSourceRange(); - // Alignment calculations can wrap around if it's greater than 2**29. - unsigned MaximumAlignment = 536870912; - if (Result > MaximumAlignment) + if (Result > Sema::MaximumAlignment) Diag(TheCall->getBeginLoc(), diag::warn_assume_aligned_too_great) - << Arg->getSourceRange() << MaximumAlignment; + << Arg->getSourceRange() << Sema::MaximumAlignment; } if (NumArgs > 2) { @@ -6412,7 +6277,8 @@ static bool IsShiftedByte(llvm::APSInt Value) { /// SemaBuiltinConstantArgShiftedByte - Check if argument ArgNum of TheCall is /// a constant expression representing an arbitrary byte value shifted left by /// a multiple of 8 bits. -bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) { +bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -6424,6 +6290,10 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) { if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; + // Truncate to the given size. + Result = Result.getLoBits(ArgBits); + Result.setIsUnsigned(true); + if (IsShiftedByte(Result)) return false; @@ -6437,7 +6307,8 @@ bool Sema::SemaBuiltinConstantArgShiftedByte(CallExpr *TheCall, int ArgNum) { /// 0x00FF, 0x01FF, ..., 0xFFFF). This strange range check is needed for some /// Arm MVE intrinsics. bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, - int ArgNum) { + int ArgNum, + unsigned ArgBits) { llvm::APSInt Result; // We can't check the value of a dependent argument. @@ -6449,6 +6320,10 @@ bool Sema::SemaBuiltinConstantArgShiftedByteOrXXFF(CallExpr *TheCall, if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) return true; + // Truncate to the given size. + Result = Result.getLoBits(ArgBits); + Result.setIsUnsigned(true); + // Check to see if it's in either of the required forms. if (IsShiftedByte(Result) || (Result > 0 && Result < 0x10000 && (Result & 0xFF) == 0xFF)) @@ -10228,6 +10103,9 @@ struct IntRange { false/*NonNegative*/); } + if (const auto *EIT = dyn_cast<ExtIntType>(T)) + return IntRange(EIT->getNumBits(), EIT->isUnsigned()); + const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -10251,6 +10129,9 @@ struct IntRange { if (const EnumType *ET = dyn_cast<EnumType>(T)) T = C.getCanonicalType(ET->getDecl()->getIntegerType()).getTypePtr(); + if (const auto *EIT = dyn_cast<ExtIntType>(T)) + return IntRange(EIT->getNumBits(), EIT->isUnsigned()); + const BuiltinType *BT = cast<BuiltinType>(T); assert(BT->isInteger()); @@ -12064,27 +11945,31 @@ static void CheckImplicitConversion(Sema &S, Expr *E, QualType T, } } -static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, +static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, SourceLocation CC, QualType T); static void CheckConditionalOperand(Sema &S, Expr *E, QualType T, SourceLocation CC, bool &ICContext) { E = E->IgnoreParenImpCasts(); - if (isa<ConditionalOperator>(E)) - return CheckConditionalOperator(S, cast<ConditionalOperator>(E), CC, T); + if (auto *CO = dyn_cast<AbstractConditionalOperator>(E)) + return CheckConditionalOperator(S, CO, CC, T); AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) return CheckImplicitConversion(S, E, T, CC, &ICContext); } -static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, +static void CheckConditionalOperator(Sema &S, AbstractConditionalOperator *E, SourceLocation CC, QualType T) { AnalyzeImplicitConversions(S, E->getCond(), E->getQuestionLoc()); + Expr *TrueExpr = E->getTrueExpr(); + if (auto *BCO = dyn_cast<BinaryConditionalOperator>(E)) + TrueExpr = BCO->getCommon(); + bool Suspicious = false; - CheckConditionalOperand(S, E->getTrueExpr(), T, CC, Suspicious); + CheckConditionalOperand(S, TrueExpr, T, CC, Suspicious); CheckConditionalOperand(S, E->getFalseExpr(), T, CC, Suspicious); if (T->isBooleanType()) @@ -12103,7 +11988,7 @@ static void CheckConditionalOperator(Sema &S, ConditionalOperator *E, if (E->getType() == T) return; Suspicious = false; - CheckImplicitConversion(S, E->getTrueExpr()->IgnoreParenImpCasts(), + CheckImplicitConversion(S, TrueExpr->IgnoreParenImpCasts(), E->getType(), CC, &Suspicious); if (!Suspicious) CheckImplicitConversion(S, E->getFalseExpr()->IgnoreParenImpCasts(), @@ -12120,24 +12005,44 @@ static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); } -/// AnalyzeImplicitConversions - Find and report any interesting -/// implicit conversions in the given expression. There are a couple -/// of competing diagnostics here, -Wconversion and -Wsign-compare. -static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, - bool IsListInit/*= false*/) { +namespace { +struct AnalyzeImplicitConversionsWorkItem { + Expr *E; + SourceLocation CC; + bool IsListInit; +}; +} + +/// Data recursive variant of AnalyzeImplicitConversions. Subexpressions +/// that should be visited are added to WorkList. +static void AnalyzeImplicitConversions( + Sema &S, AnalyzeImplicitConversionsWorkItem Item, + llvm::SmallVectorImpl<AnalyzeImplicitConversionsWorkItem> &WorkList) { + Expr *OrigE = Item.E; + SourceLocation CC = Item.CC; + QualType T = OrigE->getType(); Expr *E = OrigE->IgnoreParenImpCasts(); // Propagate whether we are in a C++ list initialization expression. // If so, we do not issue warnings for implicit int-float conversion // precision loss, because C++11 narrowing already handles it. - IsListInit = - IsListInit || (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus); + bool IsListInit = Item.IsListInit || + (isa<InitListExpr>(OrigE) && S.getLangOpts().CPlusPlus); if (E->isTypeDependent() || E->isValueDependent()) return; - if (const auto *UO = dyn_cast<UnaryOperator>(E)) + Expr *SourceExpr = E; + // Examine, but don't traverse into the source expression of an + // OpaqueValueExpr, since it may have multiple parents and we don't want to + // emit duplicate diagnostics. Its fine to examine the form or attempt to + // evaluate it in the context of checking the specific conversion to T though. + if (auto *OVE = dyn_cast<OpaqueValueExpr>(E)) + if (auto *Src = OVE->getSourceExpr()) + SourceExpr = Src; + + if (const auto *UO = dyn_cast<UnaryOperator>(SourceExpr)) if (UO->getOpcode() == UO_Not && UO->getSubExpr()->isKnownToHaveBooleanValue()) S.Diag(UO->getBeginLoc(), diag::warn_bitwise_negation_bool) @@ -12146,21 +12051,20 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, // For conditional operators, we analyze the arguments as if they // were being fed directly into the output. - if (isa<ConditionalOperator>(E)) { - ConditionalOperator *CO = cast<ConditionalOperator>(E); + if (auto *CO = dyn_cast<AbstractConditionalOperator>(SourceExpr)) { CheckConditionalOperator(S, CO, CC, T); return; } // Check implicit argument conversions for function calls. - if (CallExpr *Call = dyn_cast<CallExpr>(E)) + if (CallExpr *Call = dyn_cast<CallExpr>(SourceExpr)) CheckImplicitArgumentConversions(S, Call, CC); // Go ahead and check any implicit conversions we might have skipped. // The non-canonical typecheck is just an optimization; // CheckImplicitConversion will filter out dead implicit conversions. - if (E->getType() != T) - CheckImplicitConversion(S, E, T, CC, nullptr, IsListInit); + if (SourceExpr->getType() != T) + CheckImplicitConversion(S, SourceExpr, T, CC, nullptr, IsListInit); // Now continue drilling into this expression. @@ -12170,7 +12074,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, // FIXME: Use a more uniform representation for this. for (auto *SE : POE->semantics()) if (auto *OVE = dyn_cast<OpaqueValueExpr>(SE)) - AnalyzeImplicitConversions(S, OVE->getSourceExpr(), CC, IsListInit); + WorkList.push_back({OVE->getSourceExpr(), CC, IsListInit}); } // Skip past explicit casts. @@ -12178,7 +12082,8 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, E = CE->getSubExpr()->IgnoreParenImpCasts(); if (!CE->getType()->isVoidType() && E->getType()->isAtomicType()) S.Diag(E->getBeginLoc(), diag::warn_atomic_implicit_seq_cst); - return AnalyzeImplicitConversions(S, E, CC, IsListInit); + WorkList.push_back({E, CC, IsListInit}); + return; } if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { @@ -12217,7 +12122,7 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, // Ignore checking string literals that are in logical and operators. // This is a common pattern for asserts. continue; - AnalyzeImplicitConversions(S, ChildExpr, CC, IsListInit); + WorkList.push_back({ChildExpr, CC, IsListInit}); } if (BO && BO->isLogicalOp()) { @@ -12241,6 +12146,17 @@ static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, } } +/// AnalyzeImplicitConversions - Find and report any interesting +/// implicit conversions in the given expression. There are a couple +/// of competing diagnostics here, -Wconversion and -Wsign-compare. +static void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC, + bool IsListInit/*= false*/) { + llvm::SmallVector<AnalyzeImplicitConversionsWorkItem, 16> WorkList; + WorkList.push_back({OrigE, CC, IsListInit}); + while (!WorkList.empty()) + AnalyzeImplicitConversions(S, WorkList.pop_back_val(), WorkList); +} + /// Diagnose integer type and any valid implicit conversion to it. static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { // Taking into account implicit conversions, @@ -13182,6 +13098,11 @@ public: } void VisitCallExpr(const CallExpr *CE) { + // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. + + if (CE->isUnevaluatedBuiltinCall(Context)) + return; + // C++11 [intro.execution]p15: // When calling a function [...], every value computation and side effect // associated with any argument expression, or with the postfix expression @@ -13189,10 +13110,165 @@ public: // expression or statement in the body of the function [and thus before // the value computation of its result]. SequencedSubexpression Sequenced(*this); - SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), - [&] { Base::VisitCallExpr(CE); }); + SemaRef.runWithSufficientStackSpace(CE->getExprLoc(), [&] { + // C++17 [expr.call]p5 + // The postfix-expression is sequenced before each expression in the + // expression-list and any default argument. [...] + SequenceTree::Seq CalleeRegion; + SequenceTree::Seq OtherRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + CalleeRegion = Tree.allocate(Region); + OtherRegion = Tree.allocate(Region); + } else { + CalleeRegion = Region; + OtherRegion = Region; + } + SequenceTree::Seq OldRegion = Region; - // FIXME: CXXNewExpr and CXXDeleteExpr implicitly call functions. + // Visit the callee expression first. + Region = CalleeRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + SequencedSubexpression Sequenced(*this); + Visit(CE->getCallee()); + } else { + Visit(CE->getCallee()); + } + + // Then visit the argument expressions. + Region = OtherRegion; + for (const Expr *Argument : CE->arguments()) + Visit(Argument); + + Region = OldRegion; + if (SemaRef.getLangOpts().CPlusPlus17) { + Tree.merge(CalleeRegion); + Tree.merge(OtherRegion); + } + }); + } + + void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *CXXOCE) { + // C++17 [over.match.oper]p2: + // [...] the operator notation is first transformed to the equivalent + // function-call notation as summarized in Table 12 (where @ denotes one + // of the operators covered in the specified subclause). However, the + // operands are sequenced in the order prescribed for the built-in + // operator (Clause 8). + // + // From the above only overloaded binary operators and overloaded call + // operators have sequencing rules in C++17 that we need to handle + // separately. + if (!SemaRef.getLangOpts().CPlusPlus17 || + (CXXOCE->getNumArgs() != 2 && CXXOCE->getOperator() != OO_Call)) + return VisitCallExpr(CXXOCE); + + enum { + NoSequencing, + LHSBeforeRHS, + RHSBeforeLHS, + LHSBeforeRest + } SequencingKind; + switch (CXXOCE->getOperator()) { + case OO_Equal: + case OO_PlusEqual: + case OO_MinusEqual: + case OO_StarEqual: + case OO_SlashEqual: + case OO_PercentEqual: + case OO_CaretEqual: + case OO_AmpEqual: + case OO_PipeEqual: + case OO_LessLessEqual: + case OO_GreaterGreaterEqual: + SequencingKind = RHSBeforeLHS; + break; + + case OO_LessLess: + case OO_GreaterGreater: + case OO_AmpAmp: + case OO_PipePipe: + case OO_Comma: + case OO_ArrowStar: + case OO_Subscript: + SequencingKind = LHSBeforeRHS; + break; + + case OO_Call: + SequencingKind = LHSBeforeRest; + break; + + default: + SequencingKind = NoSequencing; + break; + } + + if (SequencingKind == NoSequencing) + return VisitCallExpr(CXXOCE); + + // This is a call, so all subexpressions are sequenced before the result. + SequencedSubexpression Sequenced(*this); + + SemaRef.runWithSufficientStackSpace(CXXOCE->getExprLoc(), [&] { + assert(SemaRef.getLangOpts().CPlusPlus17 && + "Should only get there with C++17 and above!"); + assert((CXXOCE->getNumArgs() == 2 || CXXOCE->getOperator() == OO_Call) && + "Should only get there with an overloaded binary operator" + " or an overloaded call operator!"); + + if (SequencingKind == LHSBeforeRest) { + assert(CXXOCE->getOperator() == OO_Call && + "We should only have an overloaded call operator here!"); + + // This is very similar to VisitCallExpr, except that we only have the + // C++17 case. The postfix-expression is the first argument of the + // CXXOperatorCallExpr. The expressions in the expression-list, if any, + // are in the following arguments. + // + // Note that we intentionally do not visit the callee expression since + // it is just a decayed reference to a function. + SequenceTree::Seq PostfixExprRegion = Tree.allocate(Region); + SequenceTree::Seq ArgsRegion = Tree.allocate(Region); + SequenceTree::Seq OldRegion = Region; + + assert(CXXOCE->getNumArgs() >= 1 && + "An overloaded call operator must have at least one argument" + " for the postfix-expression!"); + const Expr *PostfixExpr = CXXOCE->getArgs()[0]; + llvm::ArrayRef<const Expr *> Args(CXXOCE->getArgs() + 1, + CXXOCE->getNumArgs() - 1); + + // Visit the postfix-expression first. + { + Region = PostfixExprRegion; + SequencedSubexpression Sequenced(*this); + Visit(PostfixExpr); + } + + // Then visit the argument expressions. + Region = ArgsRegion; + for (const Expr *Arg : Args) + Visit(Arg); + + Region = OldRegion; + Tree.merge(PostfixExprRegion); + Tree.merge(ArgsRegion); + } else { + assert(CXXOCE->getNumArgs() == 2 && + "Should only have two arguments here!"); + assert((SequencingKind == LHSBeforeRHS || + SequencingKind == RHSBeforeLHS) && + "Unexpected sequencing kind!"); + + // We do not visit the callee expression since it is just a decayed + // reference to a function. + const Expr *E1 = CXXOCE->getArg(0); + const Expr *E2 = CXXOCE->getArg(1); + if (SequencingKind == RHSBeforeLHS) + std::swap(E1, E2); + + return VisitSequencedExpressions(E1, E2); + } + }); } void VisitCXXConstructExpr(const CXXConstructExpr *CCE) { @@ -13323,11 +13399,12 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, // C99 6.9.1p5: If the declarator includes a parameter type list, the // declaration of each parameter shall include an identifier. - if (CheckParameterNames && - Param->getIdentifier() == nullptr && - !Param->isImplicit() && - !getLangOpts().CPlusPlus) - Diag(Param->getLocation(), diag::err_parameter_name_omitted); + if (CheckParameterNames && Param->getIdentifier() == nullptr && + !Param->isImplicit() && !getLangOpts().CPlusPlus) { + // Diagnose this as an extension in C17 and earlier. + if (!getLangOpts().C2x) + Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x); + } // C99 6.7.5.3p12: // If the function declarator is not part of a definition of that @@ -13380,17 +13457,233 @@ bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, return HasInvalidParm; } -/// A helper function to get the alignment of a Decl referred to by DeclRefExpr -/// or MemberExpr. -static CharUnits getDeclAlign(Expr *E, CharUnits TypeAlign, - ASTContext &Context) { - if (const auto *DRE = dyn_cast<DeclRefExpr>(E)) - return Context.getDeclAlign(DRE->getDecl()); +Optional<std::pair<CharUnits, CharUnits>> +static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx); + +/// Compute the alignment and offset of the base class object given the +/// derived-to-base cast expression and the alignment and offset of the derived +/// class object. +static std::pair<CharUnits, CharUnits> +getDerivedToBaseAlignmentAndOffset(const CastExpr *CE, QualType DerivedType, + CharUnits BaseAlignment, CharUnits Offset, + ASTContext &Ctx) { + for (auto PathI = CE->path_begin(), PathE = CE->path_end(); PathI != PathE; + ++PathI) { + const CXXBaseSpecifier *Base = *PathI; + const CXXRecordDecl *BaseDecl = Base->getType()->getAsCXXRecordDecl(); + if (Base->isVirtual()) { + // The complete object may have a lower alignment than the non-virtual + // alignment of the base, in which case the base may be misaligned. Choose + // the smaller of the non-virtual alignment and BaseAlignment, which is a + // conservative lower bound of the complete object alignment. + CharUnits NonVirtualAlignment = + Ctx.getASTRecordLayout(BaseDecl).getNonVirtualAlignment(); + BaseAlignment = std::min(BaseAlignment, NonVirtualAlignment); + Offset = CharUnits::Zero(); + } else { + const ASTRecordLayout &RL = + Ctx.getASTRecordLayout(DerivedType->getAsCXXRecordDecl()); + Offset += RL.getBaseClassOffset(BaseDecl); + } + DerivedType = Base->getType(); + } + + return std::make_pair(BaseAlignment, Offset); +} - if (const auto *ME = dyn_cast<MemberExpr>(E)) - return Context.getDeclAlign(ME->getMemberDecl()); +/// Compute the alignment and offset of a binary additive operator. +static Optional<std::pair<CharUnits, CharUnits>> +getAlignmentAndOffsetFromBinAddOrSub(const Expr *PtrE, const Expr *IntE, + bool IsSub, ASTContext &Ctx) { + QualType PointeeType = PtrE->getType()->getPointeeType(); - return TypeAlign; + if (!PointeeType->isConstantSizeType()) + return llvm::None; + + auto P = getBaseAlignmentAndOffsetFromPtr(PtrE, Ctx); + + if (!P) + return llvm::None; + + llvm::APSInt IdxRes; + CharUnits EltSize = Ctx.getTypeSizeInChars(PointeeType); + if (IntE->isIntegerConstantExpr(IdxRes, Ctx)) { + CharUnits Offset = EltSize * IdxRes.getExtValue(); + if (IsSub) + Offset = -Offset; + return std::make_pair(P->first, P->second + Offset); + } + + // If the integer expression isn't a constant expression, compute the lower + // bound of the alignment using the alignment and offset of the pointer + // expression and the element size. + return std::make_pair( + P->first.alignmentAtOffset(P->second).alignmentAtOffset(EltSize), + CharUnits::Zero()); +} + +/// This helper function takes an lvalue expression and returns the alignment of +/// a VarDecl and a constant offset from the VarDecl. +Optional<std::pair<CharUnits, CharUnits>> +static getBaseAlignmentAndOffsetFromLValue(const Expr *E, ASTContext &Ctx) { + E = E->IgnoreParens(); + switch (E->getStmtClass()) { + default: + break; + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::ImplicitCastExprClass: { + auto *CE = cast<CastExpr>(E); + const Expr *From = CE->getSubExpr(); + switch (CE->getCastKind()) { + default: + break; + case CK_NoOp: + return getBaseAlignmentAndOffsetFromLValue(From, Ctx); + case CK_UncheckedDerivedToBase: + case CK_DerivedToBase: { + auto P = getBaseAlignmentAndOffsetFromLValue(From, Ctx); + if (!P) + break; + return getDerivedToBaseAlignmentAndOffset(CE, From->getType(), P->first, + P->second, Ctx); + } + } + break; + } + case Stmt::ArraySubscriptExprClass: { + auto *ASE = cast<ArraySubscriptExpr>(E); + return getAlignmentAndOffsetFromBinAddOrSub(ASE->getBase(), ASE->getIdx(), + false, Ctx); + } + case Stmt::DeclRefExprClass: { + if (auto *VD = dyn_cast<VarDecl>(cast<DeclRefExpr>(E)->getDecl())) { + // FIXME: If VD is captured by copy or is an escaping __block variable, + // use the alignment of VD's type. + if (!VD->getType()->isReferenceType()) + return std::make_pair(Ctx.getDeclAlign(VD), CharUnits::Zero()); + if (VD->hasInit()) + return getBaseAlignmentAndOffsetFromLValue(VD->getInit(), Ctx); + } + break; + } + case Stmt::MemberExprClass: { + auto *ME = cast<MemberExpr>(E); + auto *FD = dyn_cast<FieldDecl>(ME->getMemberDecl()); + if (!FD || FD->getType()->isReferenceType()) + break; + Optional<std::pair<CharUnits, CharUnits>> P; + if (ME->isArrow()) + P = getBaseAlignmentAndOffsetFromPtr(ME->getBase(), Ctx); + else + P = getBaseAlignmentAndOffsetFromLValue(ME->getBase(), Ctx); + if (!P) + break; + const ASTRecordLayout &Layout = Ctx.getASTRecordLayout(FD->getParent()); + uint64_t Offset = Layout.getFieldOffset(FD->getFieldIndex()); + return std::make_pair(P->first, + P->second + CharUnits::fromQuantity(Offset)); + } + case Stmt::UnaryOperatorClass: { + auto *UO = cast<UnaryOperator>(E); + switch (UO->getOpcode()) { + default: + break; + case UO_Deref: + return getBaseAlignmentAndOffsetFromPtr(UO->getSubExpr(), Ctx); + } + break; + } + case Stmt::BinaryOperatorClass: { + auto *BO = cast<BinaryOperator>(E); + auto Opcode = BO->getOpcode(); + switch (Opcode) { + default: + break; + case BO_Comma: + return getBaseAlignmentAndOffsetFromLValue(BO->getRHS(), Ctx); + } + break; + } + } + return llvm::None; +} + +/// This helper function takes a pointer expression and returns the alignment of +/// a VarDecl and a constant offset from the VarDecl. +Optional<std::pair<CharUnits, CharUnits>> +static getBaseAlignmentAndOffsetFromPtr(const Expr *E, ASTContext &Ctx) { + E = E->IgnoreParens(); + switch (E->getStmtClass()) { + default: + break; + case Stmt::CStyleCastExprClass: + case Stmt::CXXStaticCastExprClass: + case Stmt::ImplicitCastExprClass: { + auto *CE = cast<CastExpr>(E); + const Expr *From = CE->getSubExpr(); + switch (CE->getCastKind()) { + default: + break; + case CK_NoOp: + return getBaseAlignmentAndOffsetFromPtr(From, Ctx); + case CK_ArrayToPointerDecay: + return getBaseAlignmentAndOffsetFromLValue(From, Ctx); + case CK_UncheckedDerivedToBase: + case CK_DerivedToBase: { + auto P = getBaseAlignmentAndOffsetFromPtr(From, Ctx); + if (!P) + break; + return getDerivedToBaseAlignmentAndOffset( + CE, From->getType()->getPointeeType(), P->first, P->second, Ctx); + } + } + break; + } + case Stmt::CXXThisExprClass: { + auto *RD = E->getType()->getPointeeType()->getAsCXXRecordDecl(); + CharUnits Alignment = Ctx.getASTRecordLayout(RD).getNonVirtualAlignment(); + return std::make_pair(Alignment, CharUnits::Zero()); + } + case Stmt::UnaryOperatorClass: { + auto *UO = cast<UnaryOperator>(E); + if (UO->getOpcode() == UO_AddrOf) + return getBaseAlignmentAndOffsetFromLValue(UO->getSubExpr(), Ctx); + break; + } + case Stmt::BinaryOperatorClass: { + auto *BO = cast<BinaryOperator>(E); + auto Opcode = BO->getOpcode(); + switch (Opcode) { + default: + break; + case BO_Add: + case BO_Sub: { + const Expr *LHS = BO->getLHS(), *RHS = BO->getRHS(); + if (Opcode == BO_Add && !RHS->getType()->isIntegralOrEnumerationType()) + std::swap(LHS, RHS); + return getAlignmentAndOffsetFromBinAddOrSub(LHS, RHS, Opcode == BO_Sub, + Ctx); + } + case BO_Comma: + return getBaseAlignmentAndOffsetFromPtr(BO->getRHS(), Ctx); + } + break; + } + } + return llvm::None; +} + +static CharUnits getPresumedAlignmentOfPointer(const Expr *E, Sema &S) { + // See if we can compute the alignment of a VarDecl and an offset from it. + Optional<std::pair<CharUnits, CharUnits>> P = + getBaseAlignmentAndOffsetFromPtr(E, S.Context); + + if (P) + return P->first.alignmentAtOffset(P->second); + + // If that failed, return the type's alignment. + return S.Context.getTypeAlignInChars(E->getType()->getPointeeType()); } /// CheckCastAlign - Implements -Wcast-align, which warns when a @@ -13420,21 +13713,13 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { if (!SrcPtr) return; QualType SrcPointee = SrcPtr->getPointeeType(); - // Whitelist casts from cv void*. We already implicitly - // whitelisted casts to cv void*, since they have alignment 1. - // Also whitelist casts involving incomplete types, which implicitly + // Explicitly allow casts from cv void*. We already implicitly + // allowed casts to cv void*, since they have alignment 1. + // Also allow casts involving incomplete types, which implicitly // includes 'void'. if (SrcPointee->isIncompleteType()) return; - CharUnits SrcAlign = Context.getTypeAlignInChars(SrcPointee); - - if (auto *CE = dyn_cast<CastExpr>(Op)) { - if (CE->getCastKind() == CK_ArrayToPointerDecay) - SrcAlign = getDeclAlign(CE->getSubExpr(), SrcAlign, Context); - } else if (auto *UO = dyn_cast<UnaryOperator>(Op)) { - if (UO->getOpcode() == UO_AddrOf) - SrcAlign = getDeclAlign(UO->getSubExpr(), SrcAlign, Context); - } + CharUnits SrcAlign = getPresumedAlignmentOfPointer(Op, *this); if (SrcAlign >= DestAlign) return; @@ -13916,7 +14201,7 @@ static bool isSetterLikeSelector(Selector sel) { if (str.startswith("set")) str = str.substr(3); else if (str.startswith("add")) { - // Specially whitelist 'addOperationWithBlock:'. + // Specially allow 'addOperationWithBlock:'. if (sel.getNumArgs() == 1 && str.startswith("addOperationWithBlock")) return false; str = str.substr(3); @@ -14242,12 +14527,12 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, return; unsigned Attributes = PD->getPropertyAttributes(); - if (Attributes & ObjCPropertyDecl::OBJC_PR_assign) { + if (Attributes & ObjCPropertyAttribute::kind_assign) { // when 'assign' attribute was not explicitly specified // by user, ignore it and rely on property type itself // for lifetime info. unsigned AsWrittenAttr = PD->getPropertyAttributesAsWritten(); - if (!(AsWrittenAttr & ObjCPropertyDecl::OBJC_PR_assign) && + if (!(AsWrittenAttr & ObjCPropertyAttribute::kind_assign) && LHSType->isObjCRetainableType()) return; @@ -14259,8 +14544,7 @@ void Sema::checkUnsafeExprAssigns(SourceLocation Loc, } RHS = cast->getSubExpr(); } - } - else if (Attributes & ObjCPropertyDecl::OBJC_PR_weak) { + } else if (Attributes & ObjCPropertyAttribute::kind_weak) { if (checkUnsafeAssignObject(*this, Loc, Qualifiers::OCL_Weak, RHS, true)) return; } @@ -15045,3 +15329,259 @@ void Sema::CheckAddressOfPackedMember(Expr *rhs) { rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, _2, _3, _4)); } + +ExprResult Sema::SemaBuiltinMatrixTranspose(CallExpr *TheCall, + ExprResult CallResult) { + if (checkArgCount(*this, TheCall, 1)) + return ExprError(); + + ExprResult MatrixArg = DefaultLvalueConversion(TheCall->getArg(0)); + if (MatrixArg.isInvalid()) + return MatrixArg; + Expr *Matrix = MatrixArg.get(); + + auto *MType = Matrix->getType()->getAs<ConstantMatrixType>(); + if (!MType) { + Diag(Matrix->getBeginLoc(), diag::err_builtin_matrix_arg); + return ExprError(); + } + + // Create returned matrix type by swapping rows and columns of the argument + // matrix type. + QualType ResultType = Context.getConstantMatrixType( + MType->getElementType(), MType->getNumColumns(), MType->getNumRows()); + + // Change the return type to the type of the returned matrix. + TheCall->setType(ResultType); + + // Update call argument to use the possibly converted matrix argument. + TheCall->setArg(0, Matrix); + return CallResult; +} + +// Get and verify the matrix dimensions. +static llvm::Optional<unsigned> +getAndVerifyMatrixDimension(Expr *Expr, StringRef Name, Sema &S) { + llvm::APSInt Value(64); + SourceLocation ErrorPos; + if (!Expr->isIntegerConstantExpr(Value, S.Context, &ErrorPos)) { + S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_scalar_unsigned_arg) + << Name; + return {}; + } + uint64_t Dim = Value.getZExtValue(); + if (!ConstantMatrixType::isDimensionValid(Dim)) { + S.Diag(Expr->getBeginLoc(), diag::err_builtin_matrix_invalid_dimension) + << Name << ConstantMatrixType::getMaxElementsPerDimension(); + return {}; + } + return Dim; +} + +ExprResult Sema::SemaBuiltinMatrixColumnMajorLoad(CallExpr *TheCall, + ExprResult CallResult) { + if (!getLangOpts().MatrixTypes) { + Diag(TheCall->getBeginLoc(), diag::err_builtin_matrix_disabled); + return ExprError(); + } + + if (checkArgCount(*this, TheCall, 4)) + return ExprError(); + + unsigned PtrArgIdx = 0; + Expr *PtrExpr = TheCall->getArg(PtrArgIdx); + Expr *RowsExpr = TheCall->getArg(1); + Expr *ColumnsExpr = TheCall->getArg(2); + Expr *StrideExpr = TheCall->getArg(3); + + bool ArgError = false; + + // Check pointer argument. + { + ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr); + if (PtrConv.isInvalid()) + return PtrConv; + PtrExpr = PtrConv.get(); + TheCall->setArg(0, PtrExpr); + if (PtrExpr->isTypeDependent()) { + TheCall->setType(Context.DependentTy); + return TheCall; + } + } + + auto *PtrTy = PtrExpr->getType()->getAs<PointerType>(); + QualType ElementTy; + if (!PtrTy) { + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) + << PtrArgIdx + 1; + ArgError = true; + } else { + ElementTy = PtrTy->getPointeeType().getUnqualifiedType(); + + if (!ConstantMatrixType::isValidElementType(ElementTy)) { + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) + << PtrArgIdx + 1; + ArgError = true; + } + } + + // Apply default Lvalue conversions and convert the expression to size_t. + auto ApplyArgumentConversions = [this](Expr *E) { + ExprResult Conv = DefaultLvalueConversion(E); + if (Conv.isInvalid()) + return Conv; + + return tryConvertExprToType(Conv.get(), Context.getSizeType()); + }; + + // Apply conversion to row and column expressions. + ExprResult RowsConv = ApplyArgumentConversions(RowsExpr); + if (!RowsConv.isInvalid()) { + RowsExpr = RowsConv.get(); + TheCall->setArg(1, RowsExpr); + } else + RowsExpr = nullptr; + + ExprResult ColumnsConv = ApplyArgumentConversions(ColumnsExpr); + if (!ColumnsConv.isInvalid()) { + ColumnsExpr = ColumnsConv.get(); + TheCall->setArg(2, ColumnsExpr); + } else + ColumnsExpr = nullptr; + + // If any any part of the result matrix type is still pending, just use + // Context.DependentTy, until all parts are resolved. + if ((RowsExpr && RowsExpr->isTypeDependent()) || + (ColumnsExpr && ColumnsExpr->isTypeDependent())) { + TheCall->setType(Context.DependentTy); + return CallResult; + } + + // Check row and column dimenions. + llvm::Optional<unsigned> MaybeRows; + if (RowsExpr) + MaybeRows = getAndVerifyMatrixDimension(RowsExpr, "row", *this); + + llvm::Optional<unsigned> MaybeColumns; + if (ColumnsExpr) + MaybeColumns = getAndVerifyMatrixDimension(ColumnsExpr, "column", *this); + + // Check stride argument. + ExprResult StrideConv = ApplyArgumentConversions(StrideExpr); + if (StrideConv.isInvalid()) + return ExprError(); + StrideExpr = StrideConv.get(); + TheCall->setArg(3, StrideExpr); + + llvm::APSInt Value(64); + if (MaybeRows && StrideExpr->isIntegerConstantExpr(Value, Context)) { + uint64_t Stride = Value.getZExtValue(); + if (Stride < *MaybeRows) { + Diag(StrideExpr->getBeginLoc(), + diag::err_builtin_matrix_stride_too_small); + ArgError = true; + } + } + + if (ArgError || !MaybeRows || !MaybeColumns) + return ExprError(); + + TheCall->setType( + Context.getConstantMatrixType(ElementTy, *MaybeRows, *MaybeColumns)); + return CallResult; +} + +ExprResult Sema::SemaBuiltinMatrixColumnMajorStore(CallExpr *TheCall, + ExprResult CallResult) { + if (checkArgCount(*this, TheCall, 3)) + return ExprError(); + + unsigned PtrArgIdx = 1; + Expr *MatrixExpr = TheCall->getArg(0); + Expr *PtrExpr = TheCall->getArg(PtrArgIdx); + Expr *StrideExpr = TheCall->getArg(2); + + bool ArgError = false; + + { + ExprResult MatrixConv = DefaultLvalueConversion(MatrixExpr); + if (MatrixConv.isInvalid()) + return MatrixConv; + MatrixExpr = MatrixConv.get(); + TheCall->setArg(0, MatrixExpr); + } + if (MatrixExpr->isTypeDependent()) { + TheCall->setType(Context.DependentTy); + return TheCall; + } + + auto *MatrixTy = MatrixExpr->getType()->getAs<ConstantMatrixType>(); + if (!MatrixTy) { + Diag(MatrixExpr->getBeginLoc(), diag::err_builtin_matrix_arg) << 0; + ArgError = true; + } + + { + ExprResult PtrConv = DefaultFunctionArrayLvalueConversion(PtrExpr); + if (PtrConv.isInvalid()) + return PtrConv; + PtrExpr = PtrConv.get(); + TheCall->setArg(1, PtrExpr); + if (PtrExpr->isTypeDependent()) { + TheCall->setType(Context.DependentTy); + return TheCall; + } + } + + // Check pointer argument. + auto *PtrTy = PtrExpr->getType()->getAs<PointerType>(); + if (!PtrTy) { + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_pointer_arg) + << PtrArgIdx + 1; + ArgError = true; + } else { + QualType ElementTy = PtrTy->getPointeeType(); + if (ElementTy.isConstQualified()) { + Diag(PtrExpr->getBeginLoc(), diag::err_builtin_matrix_store_to_const); + ArgError = true; + } + ElementTy = ElementTy.getUnqualifiedType().getCanonicalType(); + if (MatrixTy && + !Context.hasSameType(ElementTy, MatrixTy->getElementType())) { + Diag(PtrExpr->getBeginLoc(), + diag::err_builtin_matrix_pointer_arg_mismatch) + << ElementTy << MatrixTy->getElementType(); + ArgError = true; + } + } + + // Apply default Lvalue conversions and convert the stride expression to + // size_t. + { + ExprResult StrideConv = DefaultLvalueConversion(StrideExpr); + if (StrideConv.isInvalid()) + return StrideConv; + + StrideConv = tryConvertExprToType(StrideConv.get(), Context.getSizeType()); + if (StrideConv.isInvalid()) + return StrideConv; + StrideExpr = StrideConv.get(); + TheCall->setArg(2, StrideExpr); + } + + // Check stride argument. + llvm::APSInt Value(64); + if (MatrixTy && StrideExpr->isIntegerConstantExpr(Value, Context)) { + uint64_t Stride = Value.getZExtValue(); + if (Stride < MatrixTy->getNumRows()) { + Diag(StrideExpr->getBeginLoc(), + diag::err_builtin_matrix_stride_too_small); + ArgError = true; + } + } + + if (ArgError) + return ExprError(); + + return CallResult; +} diff --git a/clang/lib/Sema/SemaCodeComplete.cpp b/clang/lib/Sema/SemaCodeComplete.cpp index 7260977c634d..0a8a27068ebf 100644 --- a/clang/lib/Sema/SemaCodeComplete.cpp +++ b/clang/lib/Sema/SemaCodeComplete.cpp @@ -9,25 +9,36 @@ // This file defines the code-completion semantic actions. // //===----------------------------------------------------------------------===// +#include "clang/AST/ASTConcept.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/QualTypeNames.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/Type.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/OperatorKinds.h" #include "clang/Basic/Specifiers.h" #include "clang/Lex/HeaderSearch.h" #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CodeCompleteConsumer.h" +#include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallPtrSet.h" @@ -36,7 +47,9 @@ #include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/ADT/iterator_range.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/Path.h" +#include "llvm/Support/raw_ostream.h" #include <list> #include <map> #include <string> @@ -1676,11 +1689,9 @@ static void AddTypeSpecifierResults(const LangOptions &LangOpts, Results.AddResult(Result("class", CCP_Type)); Results.AddResult(Result("wchar_t", CCP_Type)); - // typename qualified-id + // typename name Builder.AddTypedTextChunk("typename"); Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddPlaceholderChunk("qualifier"); - Builder.AddTextChunk("::"); Builder.AddPlaceholderChunk("name"); Results.AddResult(Result(Builder.TakeString())); @@ -1807,6 +1818,18 @@ static void AddTypedefResult(ResultBuilder &Results) { Results.AddResult(CodeCompletionResult(Builder.TakeString())); } +// using name = type +static void AddUsingAliasResult(CodeCompletionBuilder &Builder, + ResultBuilder &Results) { + Builder.AddTypedTextChunk("using"); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("name"); + Builder.AddChunk(CodeCompletionString::CK_Equal); + Builder.AddPlaceholderChunk("type"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + Results.AddResult(CodeCompletionResult(Builder.TakeString())); +} + static bool WantTypesInContext(Sema::ParserCompletionContext CCC, const LangOptions &LangOpts) { switch (CCC) { @@ -2050,6 +2073,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, Builder.AddChunk(CodeCompletionString::CK_SemiColon); Results.AddResult(Result(Builder.TakeString())); + if (SemaRef.getLangOpts().CPlusPlus11) + AddUsingAliasResult(Builder, Results); + // using typename qualifier::name (only in a dependent context) if (SemaRef.CurContext->isDependentContext()) { Builder.AddTypedTextChunk("using typename"); @@ -2130,6 +2156,9 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, Scope *S, case Sema::PCC_RecoveryInFunction: case Sema::PCC_Statement: { + if (SemaRef.getLangOpts().CPlusPlus11) + AddUsingAliasResult(Builder, Results); + AddTypedefResult(Results); if (SemaRef.getLangOpts().CPlusPlus && Results.includeCodePatterns() && @@ -2748,7 +2777,7 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, std::string Result; if (Param->getIdentifier() && !ObjCMethodParam && !SuppressName) - Result = Param->getIdentifier()->getName(); + Result = std::string(Param->getIdentifier()->getName()); QualType Type = Param->getType(); if (ObjCSubsts) @@ -2787,7 +2816,7 @@ FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, // for the block; just use the parameter type as a placeholder. std::string Result; if (!ObjCMethodParam && Param->getIdentifier()) - Result = Param->getIdentifier()->getName(); + Result = std::string(Param->getIdentifier()->getName()); QualType Type = Param->getType().getUnqualifiedType(); @@ -3002,7 +3031,7 @@ static void AddTemplateParameterChunks( } else if (NonTypeTemplateParmDecl *NTTP = dyn_cast<NonTypeTemplateParmDecl>(*P)) { if (NTTP->getIdentifier()) - PlaceholderStr = NTTP->getIdentifier()->getName(); + PlaceholderStr = std::string(NTTP->getIdentifier()->getName()); NTTP->getType().getAsStringInternal(PlaceholderStr, Policy); HasDefaultArg = NTTP->hasDefaultArgument(); } else { @@ -3705,8 +3734,11 @@ CodeCompleteConsumer::OverloadCandidate::CreateSignatureString( Result.addBriefComment(RC->getBriefText(S.getASTContext())); } AddResultTypeChunk(S.Context, Policy, FDecl, QualType(), Result); - Result.AddTextChunk( - Result.getAllocator().CopyString(FDecl->getNameAsString())); + + std::string Name; + llvm::raw_string_ostream OS(Name); + FDecl->getDeclName().print(OS, Policy); + Result.AddTextChunk(Result.getAllocator().CopyString(OS.str())); } else { Result.AddResultTypeChunk(Result.getAllocator().CopyString( Proto->getReturnType().getAsString(Policy))); @@ -4329,7 +4361,7 @@ static void AddLambdaCompletion(ResultBuilder &Results, First = false; constexpr llvm::StringLiteral NamePlaceholder = "!#!NAME_GOES_HERE!#!"; - std::string Type = NamePlaceholder; + std::string Type = std::string(NamePlaceholder); Parameter.getAsStringInternal(Type, PrintingPolicy(LangOpts)); llvm::StringRef Prefix, Suffix; std::tie(Prefix, Suffix) = llvm::StringRef(Type).split(NamePlaceholder); @@ -4719,6 +4751,386 @@ static void AddRecordMembersCompletionResults( } } +// Returns the RecordDecl inside the BaseType, falling back to primary template +// in case of specializations. Since we might not have a decl for the +// instantiation/specialization yet, e.g. dependent code. +static RecordDecl *getAsRecordDecl(const QualType BaseType) { + if (auto *RD = BaseType->getAsRecordDecl()) + return RD; + + if (const auto *TST = BaseType->getAs<TemplateSpecializationType>()) { + if (const auto *TD = dyn_cast_or_null<ClassTemplateDecl>( + TST->getTemplateName().getAsTemplateDecl())) { + return TD->getTemplatedDecl(); + } + } + + return nullptr; +} + +namespace { +// Collects completion-relevant information about a concept-constrainted type T. +// In particular, examines the constraint expressions to find members of T. +// +// The design is very simple: we walk down each constraint looking for +// expressions of the form T.foo(). +// If we're extra lucky, the return type is specified. +// We don't do any clever handling of && or || in constraint expressions, we +// take members from both branches. +// +// For example, given: +// template <class T> concept X = requires (T t, string& s) { t.print(s); }; +// template <X U> void foo(U u) { u.^ } +// We want to suggest the inferred member function 'print(string)'. +// We see that u has type U, so X<U> holds. +// X<U> requires t.print(s) to be valid, where t has type U (substituted for T). +// By looking at the CallExpr we find the signature of print(). +// +// While we tend to know in advance which kind of members (access via . -> ::) +// we want, it's simpler just to gather them all and post-filter. +// +// FIXME: some of this machinery could be used for non-concept type-parms too, +// enabling completion for type parameters based on other uses of that param. +// +// FIXME: there are other cases where a type can be constrained by a concept, +// e.g. inside `if constexpr(ConceptSpecializationExpr) { ... }` +class ConceptInfo { +public: + // Describes a likely member of a type, inferred by concept constraints. + // Offered as a code completion for T. T-> and T:: contexts. + struct Member { + // Always non-null: we only handle members with ordinary identifier names. + const IdentifierInfo *Name = nullptr; + // Set for functions we've seen called. + // We don't have the declared parameter types, only the actual types of + // arguments we've seen. These are still valuable, as it's hard to render + // a useful function completion with neither parameter types nor names! + llvm::Optional<SmallVector<QualType, 1>> ArgTypes; + // Whether this is accessed as T.member, T->member, or T::member. + enum AccessOperator { + Colons, + Arrow, + Dot, + } Operator = Dot; + // What's known about the type of a variable or return type of a function. + const TypeConstraint *ResultType = nullptr; + // FIXME: also track: + // - kind of entity (function/variable/type), to expose structured results + // - template args kinds/types, as a proxy for template params + + // For now we simply return these results as "pattern" strings. + CodeCompletionString *render(Sema &S, CodeCompletionAllocator &Alloc, + CodeCompletionTUInfo &Info) const { + CodeCompletionBuilder B(Alloc, Info); + // Result type + if (ResultType) { + std::string AsString; + { + llvm::raw_string_ostream OS(AsString); + QualType ExactType = deduceType(*ResultType); + if (!ExactType.isNull()) + ExactType.print(OS, getCompletionPrintingPolicy(S)); + else + ResultType->print(OS, getCompletionPrintingPolicy(S)); + } + B.AddResultTypeChunk(Alloc.CopyString(AsString)); + } + // Member name + B.AddTypedTextChunk(Alloc.CopyString(Name->getName())); + // Function argument list + if (ArgTypes) { + B.AddChunk(clang::CodeCompletionString::CK_LeftParen); + bool First = true; + for (QualType Arg : *ArgTypes) { + if (First) + First = false; + else { + B.AddChunk(clang::CodeCompletionString::CK_Comma); + B.AddChunk(clang::CodeCompletionString::CK_HorizontalSpace); + } + B.AddPlaceholderChunk(Alloc.CopyString( + Arg.getAsString(getCompletionPrintingPolicy(S)))); + } + B.AddChunk(clang::CodeCompletionString::CK_RightParen); + } + return B.TakeString(); + } + }; + + // BaseType is the type parameter T to infer members from. + // T must be accessible within S, as we use it to find the template entity + // that T is attached to in order to gather the relevant constraints. + ConceptInfo(const TemplateTypeParmType &BaseType, Scope *S) { + auto *TemplatedEntity = getTemplatedEntity(BaseType.getDecl(), S); + for (const Expr *E : constraintsForTemplatedEntity(TemplatedEntity)) + believe(E, &BaseType); + } + + std::vector<Member> members() { + std::vector<Member> Results; + for (const auto &E : this->Results) + Results.push_back(E.second); + llvm::sort(Results, [](const Member &L, const Member &R) { + return L.Name->getName() < R.Name->getName(); + }); + return Results; + } + +private: + // Infer members of T, given that the expression E (dependent on T) is true. + void believe(const Expr *E, const TemplateTypeParmType *T) { + if (!E || !T) + return; + if (auto *CSE = dyn_cast<ConceptSpecializationExpr>(E)) { + // If the concept is + // template <class A, class B> concept CD = f<A, B>(); + // And the concept specialization is + // CD<int, T> + // Then we're substituting T for B, so we want to make f<A, B>() true + // by adding members to B - i.e. believe(f<A, B>(), B); + // + // For simplicity: + // - we don't attempt to substitute int for A + // - when T is used in other ways (like CD<T*>) we ignore it + ConceptDecl *CD = CSE->getNamedConcept(); + TemplateParameterList *Params = CD->getTemplateParameters(); + unsigned Index = 0; + for (const auto &Arg : CSE->getTemplateArguments()) { + if (Index >= Params->size()) + break; // Won't happen in valid code. + if (isApprox(Arg, T)) { + auto *TTPD = dyn_cast<TemplateTypeParmDecl>(Params->getParam(Index)); + if (!TTPD) + continue; + // T was used as an argument, and bound to the parameter TT. + auto *TT = cast<TemplateTypeParmType>(TTPD->getTypeForDecl()); + // So now we know the constraint as a function of TT is true. + believe(CD->getConstraintExpr(), TT); + // (concepts themselves have no associated constraints to require) + } + + ++Index; + } + } else if (auto *BO = dyn_cast<BinaryOperator>(E)) { + // For A && B, we can infer members from both branches. + // For A || B, the union is still more useful than the intersection. + if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { + believe(BO->getLHS(), T); + believe(BO->getRHS(), T); + } + } else if (auto *RE = dyn_cast<RequiresExpr>(E)) { + // A requires(){...} lets us infer members from each requirement. + for (const concepts::Requirement *Req : RE->getRequirements()) { + if (!Req->isDependent()) + continue; // Can't tell us anything about T. + // Now Req cannot a substitution-error: those aren't dependent. + + if (auto *TR = dyn_cast<concepts::TypeRequirement>(Req)) { + // Do a full traversal so we get `foo` from `typename T::foo::bar`. + QualType AssertedType = TR->getType()->getType(); + ValidVisitor(this, T).TraverseType(AssertedType); + } else if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) { + ValidVisitor Visitor(this, T); + // If we have a type constraint on the value of the expression, + // AND the whole outer expression describes a member, then we'll + // be able to use the constraint to provide the return type. + if (ER->getReturnTypeRequirement().isTypeConstraint()) { + Visitor.OuterType = + ER->getReturnTypeRequirement().getTypeConstraint(); + Visitor.OuterExpr = ER->getExpr(); + } + Visitor.TraverseStmt(ER->getExpr()); + } else if (auto *NR = dyn_cast<concepts::NestedRequirement>(Req)) { + believe(NR->getConstraintExpr(), T); + } + } + } + } + + // This visitor infers members of T based on traversing expressions/types + // that involve T. It is invoked with code known to be valid for T. + class ValidVisitor : public RecursiveASTVisitor<ValidVisitor> { + ConceptInfo *Outer; + const TemplateTypeParmType *T; + + CallExpr *Caller = nullptr; + Expr *Callee = nullptr; + + public: + // If set, OuterExpr is constrained by OuterType. + Expr *OuterExpr = nullptr; + const TypeConstraint *OuterType = nullptr; + + ValidVisitor(ConceptInfo *Outer, const TemplateTypeParmType *T) + : Outer(Outer), T(T) { + assert(T); + } + + // In T.foo or T->foo, `foo` is a member function/variable. + bool VisitCXXDependentScopeMemberExpr(CXXDependentScopeMemberExpr *E) { + const Type *Base = E->getBaseType().getTypePtr(); + bool IsArrow = E->isArrow(); + if (Base->isPointerType() && IsArrow) { + IsArrow = false; + Base = Base->getPointeeType().getTypePtr(); + } + if (isApprox(Base, T)) + addValue(E, E->getMember(), IsArrow ? Member::Arrow : Member::Dot); + return true; + } + + // In T::foo, `foo` is a static member function/variable. + bool VisitDependentScopeDeclRefExpr(DependentScopeDeclRefExpr *E) { + if (E->getQualifier() && isApprox(E->getQualifier()->getAsType(), T)) + addValue(E, E->getDeclName(), Member::Colons); + return true; + } + + // In T::typename foo, `foo` is a type. + bool VisitDependentNameType(DependentNameType *DNT) { + const auto *Q = DNT->getQualifier(); + if (Q && isApprox(Q->getAsType(), T)) + addType(DNT->getIdentifier()); + return true; + } + + // In T::foo::bar, `foo` must be a type. + // VisitNNS() doesn't exist, and TraverseNNS isn't always called :-( + bool TraverseNestedNameSpecifierLoc(NestedNameSpecifierLoc NNSL) { + if (NNSL) { + NestedNameSpecifier *NNS = NNSL.getNestedNameSpecifier(); + const auto *Q = NNS->getPrefix(); + if (Q && isApprox(Q->getAsType(), T)) + addType(NNS->getAsIdentifier()); + } + // FIXME: also handle T::foo<X>::bar + return RecursiveASTVisitor::TraverseNestedNameSpecifierLoc(NNSL); + } + + // FIXME also handle T::foo<X> + + // Track the innermost caller/callee relationship so we can tell if a + // nested expr is being called as a function. + bool VisitCallExpr(CallExpr *CE) { + Caller = CE; + Callee = CE->getCallee(); + return true; + } + + private: + void addResult(Member &&M) { + auto R = Outer->Results.try_emplace(M.Name); + Member &O = R.first->second; + // Overwrite existing if the new member has more info. + // The preference of . vs :: vs -> is fairly arbitrary. + if (/*Inserted*/ R.second || + std::make_tuple(M.ArgTypes.hasValue(), M.ResultType != nullptr, + M.Operator) > std::make_tuple(O.ArgTypes.hasValue(), + O.ResultType != nullptr, + O.Operator)) + O = std::move(M); + } + + void addType(const IdentifierInfo *Name) { + if (!Name) + return; + Member M; + M.Name = Name; + M.Operator = Member::Colons; + addResult(std::move(M)); + } + + void addValue(Expr *E, DeclarationName Name, + Member::AccessOperator Operator) { + if (!Name.isIdentifier()) + return; + Member Result; + Result.Name = Name.getAsIdentifierInfo(); + Result.Operator = Operator; + // If this is the callee of an immediately-enclosing CallExpr, then + // treat it as a method, otherwise it's a variable. + if (Caller != nullptr && Callee == E) { + Result.ArgTypes.emplace(); + for (const auto *Arg : Caller->arguments()) + Result.ArgTypes->push_back(Arg->getType()); + if (Caller == OuterExpr) { + Result.ResultType = OuterType; + } + } else { + if (E == OuterExpr) + Result.ResultType = OuterType; + } + addResult(std::move(Result)); + } + }; + + static bool isApprox(const TemplateArgument &Arg, const Type *T) { + return Arg.getKind() == TemplateArgument::Type && + isApprox(Arg.getAsType().getTypePtr(), T); + } + + static bool isApprox(const Type *T1, const Type *T2) { + return T1 && T2 && + T1->getCanonicalTypeUnqualified() == + T2->getCanonicalTypeUnqualified(); + } + + // Returns the DeclContext immediately enclosed by the template parameter + // scope. For primary templates, this is the templated (e.g.) CXXRecordDecl. + // For specializations, this is e.g. ClassTemplatePartialSpecializationDecl. + static DeclContext *getTemplatedEntity(const TemplateTypeParmDecl *D, + Scope *S) { + if (D == nullptr) + return nullptr; + Scope *Inner = nullptr; + while (S) { + if (S->isTemplateParamScope() && S->isDeclScope(D)) + return Inner ? Inner->getEntity() : nullptr; + Inner = S; + S = S->getParent(); + } + return nullptr; + } + + // Gets all the type constraint expressions that might apply to the type + // variables associated with DC (as returned by getTemplatedEntity()). + static SmallVector<const Expr *, 1> + constraintsForTemplatedEntity(DeclContext *DC) { + SmallVector<const Expr *, 1> Result; + if (DC == nullptr) + return Result; + // Primary templates can have constraints. + if (const auto *TD = cast<Decl>(DC)->getDescribedTemplate()) + TD->getAssociatedConstraints(Result); + // Partial specializations may have constraints. + if (const auto *CTPSD = + dyn_cast<ClassTemplatePartialSpecializationDecl>(DC)) + CTPSD->getAssociatedConstraints(Result); + if (const auto *VTPSD = dyn_cast<VarTemplatePartialSpecializationDecl>(DC)) + VTPSD->getAssociatedConstraints(Result); + return Result; + } + + // Attempt to find the unique type satisfying a constraint. + // This lets us show e.g. `int` instead of `std::same_as<int>`. + static QualType deduceType(const TypeConstraint &T) { + // Assume a same_as<T> return type constraint is std::same_as or equivalent. + // In this case the return type is T. + DeclarationName DN = T.getNamedConcept()->getDeclName(); + if (DN.isIdentifier() && DN.getAsIdentifierInfo()->isStr("same_as")) + if (const auto *Args = T.getTemplateArgsAsWritten()) + if (Args->getNumTemplateArgs() == 1) { + const auto &Arg = Args->arguments().front().getArgument(); + if (Arg.getKind() == TemplateArgument::Type) + return Arg.getAsType(); + } + return {}; + } + + llvm::DenseMap<const IdentifierInfo *, Member> Results; +}; +} // namespace + void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Expr *OtherOpBase, SourceLocation OpLoc, bool IsArrow, @@ -4767,37 +5179,46 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Base = ConvertedBase.get(); QualType BaseType = Base->getType(); + if (BaseType.isNull()) + return false; ExprValueKind BaseKind = Base->getValueKind(); if (IsArrow) { if (const PointerType *Ptr = BaseType->getAs<PointerType>()) { BaseType = Ptr->getPointeeType(); BaseKind = VK_LValue; - } else if (BaseType->isObjCObjectPointerType()) - /*Do nothing*/; - else + } else if (BaseType->isObjCObjectPointerType() || + BaseType->isTemplateTypeParmType()) { + // Both cases (dot/arrow) handled below. + } else { return false; + } } - if (const RecordType *Record = BaseType->getAs<RecordType>()) { + if (RecordDecl *RD = getAsRecordDecl(BaseType)) { AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind, - Record->getDecl(), - std::move(AccessOpFixIt)); - } else if (const auto *TST = - BaseType->getAs<TemplateSpecializationType>()) { - TemplateName TN = TST->getTemplateName(); - if (const auto *TD = - dyn_cast_or_null<ClassTemplateDecl>(TN.getAsTemplateDecl())) { - CXXRecordDecl *RD = TD->getTemplatedDecl(); - AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind, - RD, std::move(AccessOpFixIt)); + RD, std::move(AccessOpFixIt)); + } else if (const auto *TTPT = + dyn_cast<TemplateTypeParmType>(BaseType.getTypePtr())) { + auto Operator = + IsArrow ? ConceptInfo::Member::Arrow : ConceptInfo::Member::Dot; + for (const auto &R : ConceptInfo(*TTPT, S).members()) { + if (R.Operator != Operator) + continue; + CodeCompletionResult Result( + R.render(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo())); + if (AccessOpFixIt) + Result.FixIts.push_back(*AccessOpFixIt); + Results.AddResult(std::move(Result)); } - } else if (const auto *ICNT = BaseType->getAs<InjectedClassNameType>()) { - if (auto *RD = ICNT->getDecl()) - AddRecordMembersCompletionResults(*this, Results, S, BaseType, BaseKind, - RD, std::move(AccessOpFixIt)); } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { - // Objective-C property reference. + // Objective-C property reference. Bail if we're performing fix-it code + // completion since Objective-C properties are normally backed by ivars, + // most Objective-C fix-its here would have little value. + if (AccessOpFixIt.hasValue()) { + return false; + } AddedPropertiesSet AddedProperties; if (const ObjCObjectPointerType *ObjCPtr = @@ -4817,7 +5238,12 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, /*InOriginalClass*/ false); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { - // Objective-C instance variable access. + // Objective-C instance variable access. Bail if we're performing fix-it + // code completion since Objective-C properties are normally backed by + // ivars, most Objective-C fix-its here would have little value. + if (AccessOpFixIt.hasValue()) { + return false; + } ObjCInterfaceDecl *Class = nullptr; if (const ObjCObjectPointerType *ObjCPtr = BaseType->getAs<ObjCObjectPointerType>()) @@ -5282,6 +5708,44 @@ QualType Sema::ProduceCtorInitMemberSignatureHelp( return QualType(); } +void Sema::CodeCompleteDesignator(const QualType BaseType, + llvm::ArrayRef<Expr *> InitExprs, + const Designation &D) { + if (BaseType.isNull()) + return; + // FIXME: Handle nested designations, e.g. : .x.^ + if (!D.empty()) + return; + + const auto *RD = getAsRecordDecl(BaseType); + if (!RD) + return; + if (const auto *CTSD = llvm::dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + // Template might not be instantiated yet, fall back to primary template in + // such cases. + if (CTSD->getTemplateSpecializationKind() == TSK_Undeclared) + RD = CTSD->getSpecializedTemplate()->getTemplatedDecl(); + } + if (RD->fields().empty()) + return; + + CodeCompletionContext CCC(CodeCompletionContext::CCC_DotMemberAccess, + BaseType); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), CCC); + + Results.EnterNewScope(); + for (const auto *FD : RD->fields()) { + // FIXME: Make use of previous designators to mark any fields before those + // inaccessible, and also compute the next initializer priority. + ResultBuilder::Result Result(FD, Results.getBasePriority(FD)); + Results.AddResult(Result, CurContext, /*Hiding=*/nullptr); + } + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D); if (!VD) { @@ -5297,7 +5761,7 @@ void Sema::CodeCompleteInitializer(Scope *S, Decl *D) { CodeCompleteExpression(S, Data); } -void Sema::CodeCompleteAfterIf(Scope *S) { +void Sema::CodeCompleteAfterIf(Scope *S, bool IsBracedThen) { ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), mapCodeCompletionContext(*this, PCC_Statement)); @@ -5314,15 +5778,25 @@ void Sema::CodeCompleteAfterIf(Scope *S) { // "else" block CodeCompletionBuilder Builder(Results.getAllocator(), Results.getCodeCompletionTUInfo()); + + auto AddElseBodyPattern = [&] { + if (IsBracedThen) { + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddChunk(CodeCompletionString::CK_LeftBrace); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddPlaceholderChunk("statements"); + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_RightBrace); + } else { + Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddPlaceholderChunk("statement"); + Builder.AddChunk(CodeCompletionString::CK_SemiColon); + } + }; Builder.AddTypedTextChunk("else"); - if (Results.includeCodePatterns()) { - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddChunk(CodeCompletionString::CK_LeftBrace); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddPlaceholderChunk("statements"); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddChunk(CodeCompletionString::CK_RightBrace); - } + if (Results.includeCodePatterns()) + AddElseBodyPattern(); Results.AddResult(Builder.TakeString()); // "else if" block @@ -5335,12 +5809,7 @@ void Sema::CodeCompleteAfterIf(Scope *S) { Builder.AddPlaceholderChunk("expression"); Builder.AddChunk(CodeCompletionString::CK_RightParen); if (Results.includeCodePatterns()) { - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddChunk(CodeCompletionString::CK_LeftBrace); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddPlaceholderChunk("statements"); - Builder.AddChunk(CodeCompletionString::CK_VerticalSpace); - Builder.AddChunk(CodeCompletionString::CK_RightBrace); + AddElseBodyPattern(); } Results.AddResult(Builder.TakeString()); @@ -5393,13 +5862,14 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // Always pretend to enter a context to ensure that a dependent type // resolves to a dependent record. DeclContext *Ctx = computeDeclContext(SS, /*EnteringContext=*/true); - if (!Ctx) - return; // Try to instantiate any non-dependent declaration contexts before - // we look in them. - if (!isDependentScopeSpecifier(SS) && RequireCompleteDeclContext(SS, Ctx)) - return; + // we look in them. Bail out if we fail. + NestedNameSpecifier *NNS = SS.getScopeRep(); + if (NNS != nullptr && SS.isValid() && !NNS->isDependent()) { + if (Ctx == nullptr || RequireCompleteDeclContext(SS, Ctx)) + return; + } ResultBuilder Results(*this, CodeCompleter->getAllocator(), CodeCompleter->getCodeCompletionTUInfo(), CC); @@ -5409,21 +5879,34 @@ void Sema::CodeCompleteQualifiedId(Scope *S, CXXScopeSpec &SS, // The "template" keyword can follow "::" in the grammar, but only // put it into the grammar if the nested-name-specifier is dependent. - NestedNameSpecifier *NNS = SS.getScopeRep(); + // FIXME: results is always empty, this appears to be dead. if (!Results.empty() && NNS->isDependent()) Results.AddResult("template"); + // If the scope is a concept-constrained type parameter, infer nested + // members based on the constraints. + if (const auto *TTPT = + dyn_cast_or_null<TemplateTypeParmType>(NNS->getAsType())) { + for (const auto &R : ConceptInfo(*TTPT, S).members()) { + if (R.Operator != ConceptInfo::Member::Colons) + continue; + Results.AddResult(CodeCompletionResult( + R.render(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo()))); + } + } + // Add calls to overridden virtual functions, if there are any. // // FIXME: This isn't wonderful, because we don't know whether we're actually // in a context that permits expressions. This is a general issue with // qualified-id completions. - if (!EnteringContext) + if (Ctx && !EnteringContext) MaybeAddOverrideCalls(*this, Ctx, Results); Results.ExitScope(); - if (CodeCompleter->includeNamespaceLevelDecls() || - (!Ctx->isNamespace() && !Ctx->isTranslationUnit())) { + if (Ctx && + (CodeCompleter->includeNamespaceLevelDecls() || !Ctx->isFileContext())) { CodeCompletionDeclConsumer Consumer(Results, Ctx, BaseType); LookupVisibleDecls(Ctx, LookupOrdinaryName, Consumer, /*IncludeGlobalScope=*/true, @@ -5785,6 +6268,53 @@ void Sema::CodeCompleteLambdaIntroducer(Scope *S, LambdaIntroducer &Intro, Results.data(), Results.size()); } +void Sema::CodeCompleteAfterFunctionEquals(Declarator &D) { + if (!LangOpts.CPlusPlus11) + return; + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), + CodeCompletionContext::CCC_Other); + auto ShouldAddDefault = [&D, this]() { + if (!D.isFunctionDeclarator()) + return false; + auto &Id = D.getName(); + if (Id.getKind() == UnqualifiedIdKind::IK_DestructorName) + return true; + // FIXME(liuhui): Ideally, we should check the constructor parameter list to + // verify that it is the default, copy or move constructor? + if (Id.getKind() == UnqualifiedIdKind::IK_ConstructorName && + D.getFunctionTypeInfo().NumParams <= 1) + return true; + if (Id.getKind() == UnqualifiedIdKind::IK_OperatorFunctionId) { + auto Op = Id.OperatorFunctionId.Operator; + // FIXME(liuhui): Ideally, we should check the function parameter list to + // verify that it is the copy or move assignment? + if (Op == OverloadedOperatorKind::OO_Equal) + return true; + if (LangOpts.CPlusPlus20 && + (Op == OverloadedOperatorKind::OO_EqualEqual || + Op == OverloadedOperatorKind::OO_ExclaimEqual || + Op == OverloadedOperatorKind::OO_Less || + Op == OverloadedOperatorKind::OO_LessEqual || + Op == OverloadedOperatorKind::OO_Greater || + Op == OverloadedOperatorKind::OO_GreaterEqual || + Op == OverloadedOperatorKind::OO_Spaceship)) + return true; + } + return false; + }; + + Results.EnterNewScope(); + if (ShouldAddDefault()) + Results.AddResult("default"); + // FIXME(liuhui): Ideally, we should only provide `delete` completion for the + // first function declaration. + Results.AddResult("delete"); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + /// Macro that optionally prepends an "@" to the string literal passed in via /// Keyword, depending on whether NeedAt is true or false. #define OBJC_AT_KEYWORD_NAME(NeedAt, Keyword) ((NeedAt) ? "@" Keyword : Keyword) @@ -6063,22 +6593,24 @@ static bool ObjCPropertyFlagConflicts(unsigned Attributes, unsigned NewFlag) { Attributes |= NewFlag; // Check for collisions with "readonly". - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) + if ((Attributes & ObjCPropertyAttribute::kind_readonly) && + (Attributes & ObjCPropertyAttribute::kind_readwrite)) return true; // Check for more than one of { assign, copy, retain, strong, weak }. unsigned AssignCopyRetMask = Attributes & - (ObjCDeclSpec::DQ_PR_assign | ObjCDeclSpec::DQ_PR_unsafe_unretained | - ObjCDeclSpec::DQ_PR_copy | ObjCDeclSpec::DQ_PR_retain | - ObjCDeclSpec::DQ_PR_strong | ObjCDeclSpec::DQ_PR_weak); - if (AssignCopyRetMask && AssignCopyRetMask != ObjCDeclSpec::DQ_PR_assign && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_unsafe_unretained && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_copy && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_retain && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_strong && - AssignCopyRetMask != ObjCDeclSpec::DQ_PR_weak) + (ObjCPropertyAttribute::kind_assign | + ObjCPropertyAttribute::kind_unsafe_unretained | + ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong | ObjCPropertyAttribute::kind_weak); + if (AssignCopyRetMask && + AssignCopyRetMask != ObjCPropertyAttribute::kind_assign && + AssignCopyRetMask != ObjCPropertyAttribute::kind_unsafe_unretained && + AssignCopyRetMask != ObjCPropertyAttribute::kind_copy && + AssignCopyRetMask != ObjCPropertyAttribute::kind_retain && + AssignCopyRetMask != ObjCPropertyAttribute::kind_strong && + AssignCopyRetMask != ObjCPropertyAttribute::kind_weak) return true; return false; @@ -6094,32 +6626,41 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_Other); Results.EnterNewScope(); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readonly)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_readonly)) Results.AddResult(CodeCompletionResult("readonly")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_assign)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_assign)) Results.AddResult(CodeCompletionResult("assign")); if (!ObjCPropertyFlagConflicts(Attributes, - ObjCDeclSpec::DQ_PR_unsafe_unretained)) + ObjCPropertyAttribute::kind_unsafe_unretained)) Results.AddResult(CodeCompletionResult("unsafe_unretained")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_readwrite)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_readwrite)) Results.AddResult(CodeCompletionResult("readwrite")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_retain)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_retain)) Results.AddResult(CodeCompletionResult("retain")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_strong)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_strong)) Results.AddResult(CodeCompletionResult("strong")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_copy)) + if (!ObjCPropertyFlagConflicts(Attributes, ObjCPropertyAttribute::kind_copy)) Results.AddResult(CodeCompletionResult("copy")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nonatomic)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_nonatomic)) Results.AddResult(CodeCompletionResult("nonatomic")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_atomic)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_atomic)) Results.AddResult(CodeCompletionResult("atomic")); // Only suggest "weak" if we're compiling for ARC-with-weak-references or GC. if (getLangOpts().ObjCWeak || getLangOpts().getGC() != LangOptions::NonGC) - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_weak)) + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_weak)) Results.AddResult(CodeCompletionResult("weak")); - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_setter)) { + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_setter)) { CodeCompletionBuilder Setter(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Setter.AddTypedTextChunk("setter"); @@ -6127,7 +6668,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Setter.AddPlaceholderChunk("method"); Results.AddResult(CodeCompletionResult(Setter.TakeString())); } - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_getter)) { + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_getter)) { CodeCompletionBuilder Getter(Results.getAllocator(), Results.getCodeCompletionTUInfo()); Getter.AddTypedTextChunk("getter"); @@ -6135,7 +6677,8 @@ void Sema::CodeCompleteObjCPropertyFlags(Scope *S, ObjCDeclSpec &ODS) { Getter.AddPlaceholderChunk("method"); Results.AddResult(CodeCompletionResult(Getter.TakeString())); } - if (!ObjCPropertyFlagConflicts(Attributes, ObjCDeclSpec::DQ_PR_nullability)) { + if (!ObjCPropertyFlagConflicts(Attributes, + ObjCPropertyAttribute::kind_nullability)) { Results.AddResult(CodeCompletionResult("nonnull")); Results.AddResult(CodeCompletionResult("nullable")); Results.AddResult(CodeCompletionResult("null_unspecified")); @@ -7602,7 +8145,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, } Key(Allocator, PropName->getName()); // The uppercased name of the property name. - std::string UpperKey = PropName->getName(); + std::string UpperKey = std::string(PropName->getName()); if (!UpperKey.empty()) UpperKey[0] = toUppercase(UpperKey[0]); @@ -7660,8 +8203,8 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, Builder.AddChunk(CodeCompletionString::CK_RightParen); } - Builder.AddTypedTextChunk(Allocator.CopyString(SelectorId->getName())); - Builder.AddTypedTextChunk(":"); + Builder.AddTypedTextChunk( + Allocator.CopyString(SelectorId->getName() + ":")); AddObjCPassingTypeChunk(Property->getType(), /*Quals=*/0, Context, Policy, Builder); Builder.AddTextChunk(Key); @@ -8249,39 +8792,43 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Optional<bool> IsInstanceMethod, Selector Sel = Method->getSelector(); - // Add the first part of the selector to the pattern. - Builder.AddTypedTextChunk( - Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); - - // Add parameters to the pattern. - unsigned I = 0; - for (ObjCMethodDecl::param_iterator P = Method->param_begin(), - PEnd = Method->param_end(); - P != PEnd; (void)++P, ++I) { - // Add the part of the selector name. - if (I == 0) - Builder.AddTypedTextChunk(":"); - else if (I < Sel.getNumArgs()) { - Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); - Builder.AddTypedTextChunk( - Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); - } else - break; - - // Add the parameter type. - QualType ParamType; - if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) - ParamType = (*P)->getType(); - else - ParamType = (*P)->getOriginalType(); - ParamType = ParamType.substObjCTypeArgs( - Context, {}, ObjCSubstitutionContext::Parameter); - AttributedType::stripOuterNullability(ParamType); - AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), Context, - Policy, Builder); + if (Sel.isUnarySelector()) { + // Unary selectors have no arguments. + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString(Sel.getNameForSlot(0))); + } else { + // Add all parameters to the pattern. + unsigned I = 0; + for (ObjCMethodDecl::param_iterator P = Method->param_begin(), + PEnd = Method->param_end(); + P != PEnd; (void)++P, ++I) { + // Add the part of the selector name. + if (I == 0) + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); + else if (I < Sel.getNumArgs()) { + Builder.AddChunk(CodeCompletionString::CK_HorizontalSpace); + Builder.AddTypedTextChunk( + Builder.getAllocator().CopyString(Sel.getNameForSlot(I) + ":")); + } else + break; - if (IdentifierInfo *Id = (*P)->getIdentifier()) - Builder.AddTextChunk(Builder.getAllocator().CopyString(Id->getName())); + // Add the parameter type. + QualType ParamType; + if ((*P)->getObjCDeclQualifier() & Decl::OBJC_TQ_CSNullability) + ParamType = (*P)->getType(); + else + ParamType = (*P)->getOriginalType(); + ParamType = ParamType.substObjCTypeArgs( + Context, {}, ObjCSubstitutionContext::Parameter); + AttributedType::stripOuterNullability(ParamType); + AddObjCPassingTypeChunk(ParamType, (*P)->getObjCDeclQualifier(), + Context, Policy, Builder); + + if (IdentifierInfo *Id = (*P)->getIdentifier()) + Builder.AddTextChunk( + Builder.getAllocator().CopyString(Id->getName())); + } } if (Method->isVariadic()) { @@ -8723,7 +9270,16 @@ void Sema::CodeCompleteIncludedFile(llvm::StringRef Dir, bool Angled) { if (++Count == 2500) // If we happen to hit a huge directory, break; // bail out early so we're not too slow. StringRef Filename = llvm::sys::path::filename(It->path()); - switch (It->type()) { + + // To know whether a symlink should be treated as file or a directory, we + // have to stat it. This should be cheap enough as there shouldn't be many + // symlinks. + llvm::sys::fs::file_type Type = It->type(); + if (Type == llvm::sys::fs::file_type::symlink_file) { + if (auto FileStatus = FS.status(It->path())) + Type = FileStatus->getType(); + } + switch (Type) { case llvm::sys::fs::file_type::directory_file: // All entries in a framework directory must have a ".framework" suffix, // but the suffix does not appear in the source code's include/import. diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp index 018ac2d7dc9d..ddd95faebe99 100644 --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -17,7 +17,10 @@ #include "clang/Sema/SemaDiagnostic.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/Template.h" -#include "clang/AST/ExprCXX.h" +#include "clang/Sema/Overload.h" +#include "clang/Sema/Initialization.h" +#include "clang/Sema/SemaInternal.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/OperatorPrecedence.h" #include "llvm/ADT/DenseMap.h" @@ -25,21 +28,47 @@ using namespace clang; using namespace sema; -bool -Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken, - bool *PossibleNonPrimary, - bool IsTrailingRequiresClause) { +namespace { +class LogicalBinOp { + OverloadedOperatorKind Op = OO_None; + const Expr *LHS = nullptr; + const Expr *RHS = nullptr; + +public: + LogicalBinOp(const Expr *E) { + if (auto *BO = dyn_cast<BinaryOperator>(E)) { + Op = BinaryOperator::getOverloadedOperator(BO->getOpcode()); + LHS = BO->getLHS(); + RHS = BO->getRHS(); + } else if (auto *OO = dyn_cast<CXXOperatorCallExpr>(E)) { + Op = OO->getOperator(); + LHS = OO->getArg(0); + RHS = OO->getArg(1); + } + } + + bool isAnd() const { return Op == OO_AmpAmp; } + bool isOr() const { return Op == OO_PipePipe; } + explicit operator bool() const { return isAnd() || isOr(); } + + const Expr *getLHS() const { return LHS; } + const Expr *getRHS() const { return RHS; } +}; +} + +bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression, + Token NextToken, bool *PossibleNonPrimary, + bool IsTrailingRequiresClause) { // C++2a [temp.constr.atomic]p1 // ..E shall be a constant expression of type bool. ConstraintExpression = ConstraintExpression->IgnoreParenImpCasts(); - if (auto *BinOp = dyn_cast<BinaryOperator>(ConstraintExpression)) { - if (BinOp->getOpcode() == BO_LAnd || BinOp->getOpcode() == BO_LOr) - return CheckConstraintExpression(BinOp->getLHS(), NextToken, - PossibleNonPrimary) && - CheckConstraintExpression(BinOp->getRHS(), NextToken, - PossibleNonPrimary); + if (LogicalBinOp BO = ConstraintExpression) { + return CheckConstraintExpression(BO.getLHS(), NextToken, + PossibleNonPrimary) && + CheckConstraintExpression(BO.getRHS(), NextToken, + PossibleNonPrimary); } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpression)) return CheckConstraintExpression(C->getSubExpr(), NextToken, PossibleNonPrimary); @@ -57,7 +86,7 @@ Sema::CheckConstraintExpression(Expr *ConstraintExpression, Token NextToken, (NextToken.is(tok::l_paren) && (IsTrailingRequiresClause || (Type->isDependentType() && - IsDependentFunctionNameExpr(ConstraintExpression)) || + isa<UnresolvedLookupExpr>(ConstraintExpression)) || Type->isFunctionType() || Type->isSpecificBuiltinType(BuiltinType::Overload))) || // We have the following case: @@ -96,39 +125,37 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, AtomicEvaluator &&Evaluator) { ConstraintExpr = ConstraintExpr->IgnoreParenImpCasts(); - if (auto *BO = dyn_cast<BinaryOperator>(ConstraintExpr)) { - if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { - if (calculateConstraintSatisfaction(S, BO->getLHS(), Satisfaction, - Evaluator)) - return true; + if (LogicalBinOp BO = ConstraintExpr) { + if (calculateConstraintSatisfaction(S, BO.getLHS(), Satisfaction, + Evaluator)) + return true; - bool IsLHSSatisfied = Satisfaction.IsSatisfied; + bool IsLHSSatisfied = Satisfaction.IsSatisfied; - if (BO->getOpcode() == BO_LOr && IsLHSSatisfied) - // [temp.constr.op] p3 - // A disjunction is a constraint taking two operands. To determine if - // a disjunction is satisfied, the satisfaction of the first operand - // is checked. If that is satisfied, the disjunction is satisfied. - // Otherwise, the disjunction is satisfied if and only if the second - // operand is satisfied. - return false; + if (BO.isOr() && IsLHSSatisfied) + // [temp.constr.op] p3 + // A disjunction is a constraint taking two operands. To determine if + // a disjunction is satisfied, the satisfaction of the first operand + // is checked. If that is satisfied, the disjunction is satisfied. + // Otherwise, the disjunction is satisfied if and only if the second + // operand is satisfied. + return false; - if (BO->getOpcode() == BO_LAnd && !IsLHSSatisfied) - // [temp.constr.op] p2 - // A conjunction is a constraint taking two operands. To determine if - // a conjunction is satisfied, the satisfaction of the first operand - // is checked. If that is not satisfied, the conjunction is not - // satisfied. Otherwise, the conjunction is satisfied if and only if - // the second operand is satisfied. - return false; + if (BO.isAnd() && !IsLHSSatisfied) + // [temp.constr.op] p2 + // A conjunction is a constraint taking two operands. To determine if + // a conjunction is satisfied, the satisfaction of the first operand + // is checked. If that is not satisfied, the conjunction is not + // satisfied. Otherwise, the conjunction is satisfied if and only if + // the second operand is satisfied. + return false; - return calculateConstraintSatisfaction(S, BO->getRHS(), Satisfaction, - std::forward<AtomicEvaluator>(Evaluator)); - } - } - else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) + return calculateConstraintSatisfaction( + S, BO.getRHS(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator)); + } else if (auto *C = dyn_cast<ExprWithCleanups>(ConstraintExpr)) { return calculateConstraintSatisfaction(S, C->getSubExpr(), Satisfaction, std::forward<AtomicEvaluator>(Evaluator)); + } // An atomic constraint expression ExprResult SubstitutedAtomicExpr = Evaluator(ConstraintExpr); @@ -164,9 +191,8 @@ calculateConstraintSatisfaction(Sema &S, const Expr *ConstraintExpr, return false; } -template <typename TemplateDeclT> static bool calculateConstraintSatisfaction( - Sema &S, TemplateDeclT *Template, ArrayRef<TemplateArgument> TemplateArgs, + Sema &S, const NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceLocation TemplateNameLoc, MultiLevelTemplateArgumentList &MLTAL, const Expr *ConstraintExpr, ConstraintSatisfaction &Satisfaction) { return calculateConstraintSatisfaction( @@ -179,8 +205,9 @@ static bool calculateConstraintSatisfaction( { TemplateDeductionInfo Info(TemplateNameLoc); Sema::InstantiatingTemplate Inst(S, AtomicExpr->getBeginLoc(), - Sema::InstantiatingTemplate::ConstraintSubstitution{}, Template, - Info, AtomicExpr->getSourceRange()); + Sema::InstantiatingTemplate::ConstraintSubstitution{}, + const_cast<NamedDecl *>(Template), Info, + AtomicExpr->getSourceRange()); if (Inst.isInvalid()) return ExprError(); // We do not want error diagnostics escaping here. @@ -227,8 +254,7 @@ static bool calculateConstraintSatisfaction( }); } -template<typename TemplateDeclT> -static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, +static bool CheckConstraintSatisfaction(Sema &S, const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, @@ -246,8 +272,8 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, } Sema::InstantiatingTemplate Inst(S, TemplateIDRange.getBegin(), - Sema::InstantiatingTemplate::ConstraintsCheck{}, Template, TemplateArgs, - TemplateIDRange); + Sema::InstantiatingTemplate::ConstraintsCheck{}, + const_cast<NamedDecl *>(Template), TemplateArgs, TemplateIDRange); if (Inst.isInvalid()) return true; @@ -269,36 +295,45 @@ static bool CheckConstraintSatisfaction(Sema &S, TemplateDeclT *Template, return false; } -bool Sema::CheckConstraintSatisfaction(TemplateDecl *Template, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} +bool Sema::CheckConstraintSatisfaction( + const NamedDecl *Template, ArrayRef<const Expr *> ConstraintExprs, + ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange, + ConstraintSatisfaction &OutSatisfaction) { + if (ConstraintExprs.empty()) { + OutSatisfaction.IsSatisfied = true; + return false; + } -bool -Sema::CheckConstraintSatisfaction(ClassTemplatePartialSpecializationDecl* Part, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Part, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); -} + llvm::FoldingSetNodeID ID; + void *InsertPos; + ConstraintSatisfaction *Satisfaction = nullptr; + bool ShouldCache = LangOpts.ConceptSatisfactionCaching && Template; + if (ShouldCache) { + ConstraintSatisfaction::Profile(ID, Context, Template, TemplateArgs); + Satisfaction = SatisfactionCache.FindNodeOrInsertPos(ID, InsertPos); + if (Satisfaction) { + OutSatisfaction = *Satisfaction; + return false; + } + Satisfaction = new ConstraintSatisfaction(Template, TemplateArgs); + } else { + Satisfaction = &OutSatisfaction; + } + if (::CheckConstraintSatisfaction(*this, Template, ConstraintExprs, + TemplateArgs, TemplateIDRange, + *Satisfaction)) { + if (ShouldCache) + delete Satisfaction; + return true; + } -bool -Sema::CheckConstraintSatisfaction(VarTemplatePartialSpecializationDecl* Partial, - ArrayRef<const Expr *> ConstraintExprs, - ArrayRef<TemplateArgument> TemplateArgs, - SourceRange TemplateIDRange, - ConstraintSatisfaction &Satisfaction) { - return ::CheckConstraintSatisfaction(*this, Partial, ConstraintExprs, - TemplateArgs, TemplateIDRange, - Satisfaction); + if (ShouldCache) { + // We cannot use InsertNode here because CheckConstraintSatisfaction might + // have invalidated it. + SatisfactionCache.InsertNode(Satisfaction); + OutSatisfaction = *Satisfaction; + } + return false; } bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, @@ -310,6 +345,30 @@ bool Sema::CheckConstraintSatisfaction(const Expr *ConstraintExpr, }); } +bool Sema::CheckFunctionConstraints(const FunctionDecl *FD, + ConstraintSatisfaction &Satisfaction, + SourceLocation UsageLoc) { + const Expr *RC = FD->getTrailingRequiresClause(); + if (RC->isInstantiationDependent()) { + Satisfaction.IsSatisfied = true; + return false; + } + Qualifiers ThisQuals; + CXXRecordDecl *Record = nullptr; + if (auto *Method = dyn_cast<CXXMethodDecl>(FD)) { + ThisQuals = Method->getMethodQualifiers(); + Record = const_cast<CXXRecordDecl *>(Method->getParent()); + } + CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); + // We substitute with empty arguments in order to rebuild the atomic + // constraint in a constant-evaluated context. + // FIXME: Should this be a dedicated TreeTransform? + return CheckConstraintSatisfaction( + FD, {RC}, /*TemplateArgs=*/{}, + SourceRange(UsageLoc.isValid() ? UsageLoc : FD->getLocation()), + Satisfaction); +} + bool Sema::EnsureTemplateArgumentListConstraints( TemplateDecl *TD, ArrayRef<TemplateArgument> TemplateArgs, SourceRange TemplateIDRange) { @@ -336,6 +395,118 @@ bool Sema::EnsureTemplateArgumentListConstraints( return false; } +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::ExprRequirement *Req, + bool First) { + assert(!Req->isSatisfied() + && "Diagnose() can only be used on an unsatisfied requirement"); + switch (Req->getSatisfactionStatus()) { + case concepts::ExprRequirement::SS_Dependent: + llvm_unreachable("Diagnosing a dependent requirement"); + break; + case concepts::ExprRequirement::SS_ExprSubstitutionFailure: { + auto *SubstDiag = Req->getExprSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_expr_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_expr_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + break; + } + case concepts::ExprRequirement::SS_NoexceptNotMet: + S.Diag(Req->getNoexceptLoc(), + diag::note_expr_requirement_noexcept_not_met) + << (int)First << Req->getExpr(); + break; + case concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure: { + auto *SubstDiag = + Req->getReturnTypeRequirement().getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_type_requirement_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_expr_requirement_type_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + break; + } + case concepts::ExprRequirement::SS_ConstraintsNotSatisfied: { + ConceptSpecializationExpr *ConstraintExpr = + Req->getReturnTypeRequirementSubstitutedConstraintExpr(); + if (ConstraintExpr->getTemplateArgsAsWritten()->NumTemplateArgs == 1) + // A simple case - expr type is the type being constrained and the concept + // was not provided arguments. + S.Diag(ConstraintExpr->getBeginLoc(), + diag::note_expr_requirement_constraints_not_satisfied_simple) + << (int)First << S.BuildDecltypeType(Req->getExpr(), + Req->getExpr()->getBeginLoc()) + << ConstraintExpr->getNamedConcept(); + else + S.Diag(ConstraintExpr->getBeginLoc(), + diag::note_expr_requirement_constraints_not_satisfied) + << (int)First << ConstraintExpr; + S.DiagnoseUnsatisfiedConstraint(ConstraintExpr->getSatisfaction()); + break; + } + case concepts::ExprRequirement::SS_Satisfied: + llvm_unreachable("We checked this above"); + } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::TypeRequirement *Req, + bool First) { + assert(!Req->isSatisfied() + && "Diagnose() can only be used on an unsatisfied requirement"); + switch (Req->getSatisfactionStatus()) { + case concepts::TypeRequirement::SS_Dependent: + llvm_unreachable("Diagnosing a dependent requirement"); + return; + case concepts::TypeRequirement::SS_SubstitutionFailure: { + auto *SubstDiag = Req->getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_type_requirement_substitution_error) << (int)First + << SubstDiag->SubstitutedEntity << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_type_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + return; + } + default: + llvm_unreachable("Unknown satisfaction status"); + return; + } +} + +static void diagnoseUnsatisfiedRequirement(Sema &S, + concepts::NestedRequirement *Req, + bool First) { + if (Req->isSubstitutionFailure()) { + concepts::Requirement::SubstitutionDiagnostic *SubstDiag = + Req->getSubstitutionDiagnostic(); + if (!SubstDiag->DiagMessage.empty()) + S.Diag(SubstDiag->DiagLoc, + diag::note_nested_requirement_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity + << SubstDiag->DiagMessage; + else + S.Diag(SubstDiag->DiagLoc, + diag::note_nested_requirement_unknown_substitution_error) + << (int)First << SubstDiag->SubstitutedEntity; + return; + } + S.DiagnoseUnsatisfiedConstraint(Req->getConstraintSatisfaction(), First); +} + + static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, Expr *SubstExpr, bool First = true) { @@ -412,6 +583,19 @@ static void diagnoseWellFormedUnsatisfiedConstraintExpr(Sema &S, } S.DiagnoseUnsatisfiedConstraint(CSE->getSatisfaction()); return; + } else if (auto *RE = dyn_cast<RequiresExpr>(SubstExpr)) { + for (concepts::Requirement *Req : RE->getRequirements()) + if (!Req->isDependent() && !Req->isSatisfied()) { + if (auto *E = dyn_cast<concepts::ExprRequirement>(Req)) + diagnoseUnsatisfiedRequirement(S, E, First); + else if (auto *T = dyn_cast<concepts::TypeRequirement>(Req)) + diagnoseUnsatisfiedRequirement(S, T, First); + else + diagnoseUnsatisfiedRequirement( + S, cast<concepts::NestedRequirement>(Req), First); + break; + } + return; } S.Diag(SubstExpr->getSourceRange().getBegin(), @@ -434,11 +618,11 @@ static void diagnoseUnsatisfiedConstraintExpr( Record.template get<Expr *>(), First); } -void Sema::DiagnoseUnsatisfiedConstraint( - const ConstraintSatisfaction& Satisfaction) { +void +Sema::DiagnoseUnsatisfiedConstraint(const ConstraintSatisfaction& Satisfaction, + bool First) { assert(!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint"); - bool First = true; for (auto &Pair : Satisfaction.Details) { diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); First = false; @@ -446,10 +630,10 @@ void Sema::DiagnoseUnsatisfiedConstraint( } void Sema::DiagnoseUnsatisfiedConstraint( - const ASTConstraintSatisfaction &Satisfaction) { + const ASTConstraintSatisfaction &Satisfaction, + bool First) { assert(!Satisfaction.IsSatisfied && "Attempted to diagnose a satisfied constraint"); - bool First = true; for (auto &Pair : Satisfaction) { diagnoseUnsatisfiedConstraintExpr(*this, Pair.first, Pair.second, First); First = false; @@ -523,6 +707,10 @@ static bool substituteParameterMappings(Sema &S, NormalizedConstraint &N, ArgsAsWritten->arguments().back().getSourceRange().getEnd())); if (S.SubstTemplateArguments(*Atomic.ParameterMapping, MLTAL, SubstArgs)) return true; + Atomic.ParameterMapping.emplace( + MutableArrayRef<TemplateArgumentLoc>( + new (S.Context) TemplateArgumentLoc[SubstArgs.size()], + SubstArgs.size())); std::copy(SubstArgs.arguments().begin(), SubstArgs.arguments().end(), N.getAtomicConstraint()->ParameterMapping->begin()); return false; @@ -561,19 +749,16 @@ NormalizedConstraint::fromConstraintExpr(Sema &S, NamedDecl *D, const Expr *E) { // - The normal form of an expression (E) is the normal form of E. // [...] E = E->IgnoreParenImpCasts(); - if (auto *BO = dyn_cast<const BinaryOperator>(E)) { - if (BO->getOpcode() == BO_LAnd || BO->getOpcode() == BO_LOr) { - auto LHS = fromConstraintExpr(S, D, BO->getLHS()); - if (!LHS) - return None; - auto RHS = fromConstraintExpr(S, D, BO->getRHS()); - if (!RHS) - return None; + if (LogicalBinOp BO = E) { + auto LHS = fromConstraintExpr(S, D, BO.getLHS()); + if (!LHS) + return None; + auto RHS = fromConstraintExpr(S, D, BO.getRHS()); + if (!RHS) + return None; - return NormalizedConstraint( - S.Context, std::move(*LHS), std::move(*RHS), - BO->getOpcode() == BO_LAnd ? CCK_Conjunction : CCK_Disjunction); - } + return NormalizedConstraint(S.Context, std::move(*LHS), std::move(*RHS), + BO.isAnd() ? CCK_Conjunction : CCK_Disjunction); } else if (auto *CSE = dyn_cast<const ConceptSpecializationExpr>(E)) { const NormalizedConstraint *SubNF; { @@ -826,3 +1011,67 @@ bool Sema::MaybeEmitAmbiguousAtomicConstraintsDiagnostic(NamedDecl *D1, << AmbiguousAtomic2->getSourceRange(); return true; } + +concepts::ExprRequirement::ExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + ReturnTypeRequirement Req, SatisfactionStatus Status, + ConceptSpecializationExpr *SubstitutedConstraintExpr) : + Requirement(IsSimple ? RK_Simple : RK_Compound, Status == SS_Dependent, + Status == SS_Dependent && + (E->containsUnexpandedParameterPack() || + Req.containsUnexpandedParameterPack()), + Status == SS_Satisfied), Value(E), NoexceptLoc(NoexceptLoc), + TypeReq(Req), SubstitutedConstraintExpr(SubstitutedConstraintExpr), + Status(Status) { + assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && + "Simple requirement must not have a return type requirement or a " + "noexcept specification"); + assert((Status > SS_TypeRequirementSubstitutionFailure && Req.isTypeConstraint()) == + (SubstitutedConstraintExpr != nullptr)); +} + +concepts::ExprRequirement::ExprRequirement( + SubstitutionDiagnostic *ExprSubstDiag, bool IsSimple, + SourceLocation NoexceptLoc, ReturnTypeRequirement Req) : + Requirement(IsSimple ? RK_Simple : RK_Compound, Req.isDependent(), + Req.containsUnexpandedParameterPack(), /*IsSatisfied=*/false), + Value(ExprSubstDiag), NoexceptLoc(NoexceptLoc), TypeReq(Req), + Status(SS_ExprSubstitutionFailure) { + assert((!IsSimple || (Req.isEmpty() && NoexceptLoc.isInvalid())) && + "Simple requirement must not have a return type requirement or a " + "noexcept specification"); +} + +concepts::ExprRequirement::ReturnTypeRequirement:: +ReturnTypeRequirement(TemplateParameterList *TPL) : + TypeConstraintInfo(TPL, 0) { + assert(TPL->size() == 1); + const TypeConstraint *TC = + cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint(); + assert(TC && + "TPL must have a template type parameter with a type constraint"); + auto *Constraint = + cast_or_null<ConceptSpecializationExpr>( + TC->getImmediatelyDeclaredConstraint()); + bool Dependent = false; + if (Constraint->getTemplateArgsAsWritten()) { + for (auto &ArgLoc : + Constraint->getTemplateArgsAsWritten()->arguments().drop_front(1)) { + if (ArgLoc.getArgument().isDependent()) { + Dependent = true; + break; + } + } + } + TypeConstraintInfo.setInt(Dependent ? 1 : 0); +} + +concepts::TypeRequirement::TypeRequirement(TypeSourceInfo *T) : + Requirement(RK_Type, T->getType()->isDependentType(), + T->getType()->containsUnexpandedParameterPack(), + // We reach this ctor with either dependent types (in which + // IsSatisfied doesn't matter) or with non-dependent type in + // which the existence of the type indicates satisfaction. + /*IsSatisfied=*/true + ), Value(T), + Status(T->getType()->isDependentType() ? SS_Dependent : SS_Satisfied) {} diff --git a/clang/lib/Sema/SemaCoroutine.cpp b/clang/lib/Sema/SemaCoroutine.cpp index 6dc9e342beb9..992cccac6405 100644 --- a/clang/lib/Sema/SemaCoroutine.cpp +++ b/clang/lib/Sema/SemaCoroutine.cpp @@ -24,6 +24,7 @@ #include "clang/Sema/Overload.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" +#include "llvm/ADT/SmallSet.h" using namespace clang; using namespace sema; @@ -390,7 +391,13 @@ static Expr *maybeTailCall(Sema &S, QualType RetType, Expr *E, return nullptr; Expr *JustAddress = AddressExpr.get(); - // FIXME: Check that the type of AddressExpr is void* + + // Check that the type of AddressExpr is void* + if (!JustAddress->getType().getTypePtr()->isVoidPointerType()) + S.Diag(cast<CallExpr>(JustAddress)->getCalleeDecl()->getLocation(), + diag::warn_coroutine_handle_address_invalid_return_type) + << JustAddress->getType(); + return buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_resume, JustAddress); } @@ -502,8 +509,9 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { return nullptr; auto *ScopeInfo = getCurFunction(); - // Build a list of arguments, based on the coroutine functions arguments, - // that will be passed to the promise type's constructor. + + // Build a list of arguments, based on the coroutine function's arguments, + // that if present will be passed to the promise type's constructor. llvm::SmallVector<Expr *, 4> CtorArgExprs; // Add implicit object parameter. @@ -519,6 +527,7 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { } } + // Add the coroutine function's parameters. auto &Moves = ScopeInfo->CoroutineParameterMoves; for (auto *PD : FD->parameters()) { if (PD->getType()->isDependentType()) @@ -540,28 +549,33 @@ VarDecl *Sema::buildCoroutinePromise(SourceLocation Loc) { CtorArgExprs.push_back(RefExpr.get()); } - // Create an initialization sequence for the promise type using the - // constructor arguments, wrapped in a parenthesized list expression. - Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(), - CtorArgExprs, FD->getLocation()); - InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); - InitializationKind Kind = InitializationKind::CreateForInit( - VD->getLocation(), /*DirectInit=*/true, PLE); - InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs, - /*TopLevelOfInitList=*/false, - /*TreatUnavailableAsInvalid=*/false); - - // Attempt to initialize the promise type with the arguments. - // If that fails, fall back to the promise type's default constructor. - if (InitSeq) { - ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs); - if (Result.isInvalid()) { - VD->setInvalidDecl(); - } else if (Result.get()) { - VD->setInit(MaybeCreateExprWithCleanups(Result.get())); - VD->setInitStyle(VarDecl::CallInit); - CheckCompleteVariableDeclaration(VD); - } + // If we have a non-zero number of constructor arguments, try to use them. + // Otherwise, fall back to the promise type's default constructor. + if (!CtorArgExprs.empty()) { + // Create an initialization sequence for the promise type using the + // constructor arguments, wrapped in a parenthesized list expression. + Expr *PLE = ParenListExpr::Create(Context, FD->getLocation(), + CtorArgExprs, FD->getLocation()); + InitializedEntity Entity = InitializedEntity::InitializeVariable(VD); + InitializationKind Kind = InitializationKind::CreateForInit( + VD->getLocation(), /*DirectInit=*/true, PLE); + InitializationSequence InitSeq(*this, Entity, Kind, CtorArgExprs, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); + + // Attempt to initialize the promise type with the arguments. + // If that fails, fall back to the promise type's default constructor. + if (InitSeq) { + ExprResult Result = InitSeq.Perform(*this, Entity, Kind, CtorArgExprs); + if (Result.isInvalid()) { + VD->setInvalidDecl(); + } else if (Result.get()) { + VD->setInit(MaybeCreateExprWithCleanups(Result.get())); + VD->setInitStyle(VarDecl::CallInit); + CheckCompleteVariableDeclaration(VD); + } + } else + ActOnUninitializedDecl(VD); } else ActOnUninitializedDecl(VD); @@ -597,6 +611,80 @@ static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc, return ScopeInfo; } +/// Recursively check \p E and all its children to see if any call target +/// (including constructor call) is declared noexcept. Also any value returned +/// from the call has a noexcept destructor. +static void checkNoThrow(Sema &S, const Stmt *E, + llvm::SmallPtrSetImpl<const Decl *> &ThrowingDecls) { + auto checkDeclNoexcept = [&](const Decl *D, bool IsDtor = false) { + // In the case of dtor, the call to dtor is implicit and hence we should + // pass nullptr to canCalleeThrow. + if (Sema::canCalleeThrow(S, IsDtor ? nullptr : cast<Expr>(E), D)) { + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + // co_await promise.final_suspend() could end up calling + // __builtin_coro_resume for symmetric transfer if await_suspend() + // returns a handle. In that case, even __builtin_coro_resume is not + // declared as noexcept and may throw, it does not throw _into_ the + // coroutine that just suspended, but rather throws back out from + // whoever called coroutine_handle::resume(), hence we claim that + // logically it does not throw. + if (FD->getBuiltinID() == Builtin::BI__builtin_coro_resume) + return; + } + if (ThrowingDecls.empty()) { + // First time seeing an error, emit the error message. + S.Diag(cast<FunctionDecl>(S.CurContext)->getLocation(), + diag::err_coroutine_promise_final_suspend_requires_nothrow); + } + ThrowingDecls.insert(D); + } + }; + auto SC = E->getStmtClass(); + if (SC == Expr::CXXConstructExprClass) { + auto const *Ctor = cast<CXXConstructExpr>(E)->getConstructor(); + checkDeclNoexcept(Ctor); + // Check the corresponding destructor of the constructor. + checkDeclNoexcept(Ctor->getParent()->getDestructor(), true); + } else if (SC == Expr::CallExprClass || SC == Expr::CXXMemberCallExprClass || + SC == Expr::CXXOperatorCallExprClass) { + if (!cast<CallExpr>(E)->isTypeDependent()) { + checkDeclNoexcept(cast<CallExpr>(E)->getCalleeDecl()); + auto ReturnType = cast<CallExpr>(E)->getCallReturnType(S.getASTContext()); + // Check the destructor of the call return type, if any. + if (ReturnType.isDestructedType() == + QualType::DestructionKind::DK_cxx_destructor) { + const auto *T = + cast<RecordType>(ReturnType.getCanonicalType().getTypePtr()); + checkDeclNoexcept( + dyn_cast<CXXRecordDecl>(T->getDecl())->getDestructor(), true); + } + } + } + for (const auto *Child : E->children()) { + if (!Child) + continue; + checkNoThrow(S, Child, ThrowingDecls); + } +} + +bool Sema::checkFinalSuspendNoThrow(const Stmt *FinalSuspend) { + llvm::SmallPtrSet<const Decl *, 4> ThrowingDecls; + // We first collect all declarations that should not throw but not declared + // with noexcept. We then sort them based on the location before printing. + // This is to avoid emitting the same note multiple times on the same + // declaration, and also provide a deterministic order for the messages. + checkNoThrow(*this, FinalSuspend, ThrowingDecls); + auto SortedDecls = llvm::SmallVector<const Decl *, 4>{ThrowingDecls.begin(), + ThrowingDecls.end()}; + sort(SortedDecls, [](const Decl *A, const Decl *B) { + return A->getEndLoc() < B->getEndLoc(); + }); + for (const auto *D : SortedDecls) { + Diag(D->getEndLoc(), diag::note_coroutine_function_declare_noexcept); + } + return ThrowingDecls.empty(); +} + bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, StringRef Keyword) { if (!checkCoroutineContext(*this, KWLoc, Keyword)) @@ -639,7 +727,7 @@ bool Sema::ActOnCoroutineBodyStart(Scope *SC, SourceLocation KWLoc, return true; StmtResult FinalSuspend = buildSuspends("final_suspend"); - if (FinalSuspend.isInvalid()) + if (FinalSuspend.isInvalid() || !checkFinalSuspendNoThrow(FinalSuspend.get())) return true; ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get()); diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 507e4a6cd436..3e2b61ae8cdf 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -21,6 +21,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/NonTrivialTypeVisitor.h" #include "clang/AST/StmtCXX.h" @@ -47,6 +48,7 @@ #include <algorithm> #include <cstring> #include <functional> +#include <unordered_map> using namespace clang; using namespace sema; @@ -136,6 +138,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { 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_wchar_t: @@ -747,7 +750,10 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, Diag(IILoc, IsTemplateName ? diag::err_no_member_template : diag::err_typename_nested_not_found) << II << DC << SS->getRange(); - else if (isDependentScopeSpecifier(*SS)) { + else if (SS->isValid() && SS->getScopeRep()->containsErrors()) { + SuggestedType = + ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); + } else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; if (getLangOpts().MSVCCompat && isMicrosoftMissingTypename(SS, S)) DiagID = diag::ext_typename_missing; @@ -924,7 +930,7 @@ Corrected: return NameClassification::NonType(D); } - if (getLangOpts().CPlusPlus2a && SS.isEmpty() && NextToken.is(tok::less)) { + if (getLangOpts().CPlusPlus20 && SS.isEmpty() && NextToken.is(tok::less)) { // In C++20 onwards, this could be an ADL-only call to a function // template, and we're required to assume that this is a template name. // @@ -1067,7 +1073,7 @@ Corrected: Result, /*AllowFunctionTemplates=*/true, /*AllowDependent=*/false, /*AllowNonTemplateFunctions*/ SS.isEmpty() && - getLangOpts().CPlusPlus2a))) { + getLangOpts().CPlusPlus20))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of @@ -1153,6 +1159,10 @@ Corrected: return ParsedType::make(T); } + if (isa<ConceptDecl>(FirstDecl)) + return NameClassification::Concept( + TemplateName(cast<TemplateDecl>(FirstDecl))); + // We can have a type template here if we're classifying a template argument. if (isa<TemplateDecl>(FirstDecl) && !isa<FunctionTemplateDecl>(FirstDecl) && !isa<VarTemplateDecl>(FirstDecl)) @@ -1250,47 +1260,8 @@ Sema::getTemplateNameKindForDiagnostics(TemplateName Name) { return TemplateNameKindForDiagnostics::DependentTemplate; } -// Determines the context to return to after temporarily entering a -// context. This depends in an unnecessarily complicated way on the -// exact ordering of callbacks from the parser. -DeclContext *Sema::getContainingDC(DeclContext *DC) { - - // Functions defined inline within classes aren't parsed until we've - // finished parsing the top-level class, so the top-level class is - // the context we'll need to return to. - // A Lambda call operator whose parent is a class must not be treated - // as an inline member function. A Lambda can be used legally - // either as an in-class member initializer or a default argument. These - // are parsed once the class has been marked complete and so the containing - // context would be the nested class (when the lambda is defined in one); - // If the class is not complete, then the lambda is being used in an - // ill-formed fashion (such as to specify the width of a bit-field, or - // in an array-bound) - in which case we still want to return the - // lexically containing DC (which could be a nested class). - if (isa<FunctionDecl>(DC) && !isLambdaCallOperator(DC)) { - DC = DC->getLexicalParent(); - - // A function not defined within a class will always return to its - // lexical context. - if (!isa<CXXRecordDecl>(DC)) - return DC; - - // A C++ inline method/friend is parsed *after* the topmost class - // it was declared in is fully parsed ("complete"); the topmost - // class is the context we need to return to. - while (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC->getLexicalParent())) - DC = RD; - - // Return the declaration context of the topmost class the inline method is - // declared in. - return DC; - } - - return DC->getLexicalParent(); -} - void Sema::PushDeclContext(Scope *S, DeclContext *DC) { - assert(getContainingDC(DC) == CurContext && + assert(DC->getLexicalParent() == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = DC; S->setEntity(DC); @@ -1299,7 +1270,7 @@ void Sema::PushDeclContext(Scope *S, DeclContext *DC) { void Sema::PopDeclContext() { assert(CurContext && "DeclContext imbalance!"); - CurContext = getContainingDC(CurContext); + CurContext = CurContext->getLexicalParent(); assert(CurContext && "Popped translation unit!"); } @@ -1351,6 +1322,12 @@ void Sema::EnterDeclaratorContext(Scope *S, DeclContext *DC) { CurContext = DC; S->setEntity(DC); + + if (S->getParent()->isTemplateParamScope()) { + // Also set the corresponding entities for all immediately-enclosing + // template parameter scopes. + EnterTemplatedContext(S->getParent(), DC); + } } void Sema::ExitDeclaratorContext(Scope *S) { @@ -1366,6 +1343,49 @@ void Sema::ExitDeclaratorContext(Scope *S) { // disappear. } +void Sema::EnterTemplatedContext(Scope *S, DeclContext *DC) { + assert(S->isTemplateParamScope() && + "expected to be initializing a template parameter scope"); + + // C++20 [temp.local]p7: + // In the definition of a member of a class template that appears outside + // of the class template definition, the name of a member of the class + // template hides the name of a template-parameter of any enclosing class + // templates (but not a template-parameter of the member if the member is a + // class or function template). + // C++20 [temp.local]p9: + // In the definition of a class template or in the definition of a member + // of such a template that appears outside of the template definition, for + // each non-dependent base class (13.8.2.1), if the name of the base class + // or the name of a member of the base class is the same as the name of a + // template-parameter, the base class name or member name hides the + // template-parameter name (6.4.10). + // + // This means that a template parameter scope should be searched immediately + // after searching the DeclContext for which it is a template parameter + // scope. For example, for + // template<typename T> template<typename U> template<typename V> + // void N::A<T>::B<U>::f(...) + // we search V then B<U> (and base classes) then U then A<T> (and base + // classes) then T then N then ::. + unsigned ScopeDepth = getTemplateDepth(S); + for (; S && S->isTemplateParamScope(); S = S->getParent(), --ScopeDepth) { + DeclContext *SearchDCAfterScope = DC; + for (; DC; DC = DC->getLookupParent()) { + if (const TemplateParameterList *TPL = + cast<Decl>(DC)->getDescribedTemplateParams()) { + unsigned DCDepth = TPL->getDepth() + 1; + if (DCDepth > ScopeDepth) + continue; + if (ScopeDepth == DCDepth) + SearchDCAfterScope = DC = DC->getLookupParent(); + break; + } + } + S->setLookupEntity(SearchDCAfterScope); + } +} + void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. @@ -2586,11 +2606,15 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, AMK == Sema::AMK_ProtocolImplementation)) NewAttr = nullptr; else if (const auto *UA = dyn_cast<UuidAttr>(Attr)) - NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid()); + NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl()); else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr)) NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA); else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr)) NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA); + else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr)) + NewAttr = S.mergeImportModuleAttr(D, *IMA); + else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr)) + NewAttr = S.mergeImportNameAttr(D, *INA); else if (Attr->shouldInheritEvenIfAlreadyPresent() || !DeclHasAttr(D, Attr)) NewAttr = cast<InheritableAttr>(Attr->clone(S.Context)); @@ -2707,6 +2731,18 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { --E; continue; } + } else if (isa<LoaderUninitializedAttr>(NewAttribute)) { + // If there is a C definition followed by a redeclaration with this + // attribute then there are two different definitions. In C++, prefer the + // standard diagnostics. + if (!S.getLangOpts().CPlusPlus) { + S.Diag(NewAttribute->getLocation(), + diag::err_loader_uninitialized_redeclaration); + S.Diag(Def->getLocation(), diag::note_previous_definition); + NewAttributes.erase(NewAttributes.begin() + I); + --E; + continue; + } } else if (isa<SelectAnyAttr>(NewAttribute) && cast<VarDecl>(New)->isInline() && !cast<VarDecl>(New)->isInlineSpecified()) { @@ -2716,6 +2752,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { // honored it. ++I; continue; + } else if (isa<OMPDeclareVariantAttr>(NewAttribute)) { + // We allow to add OMP[Begin]DeclareVariantAttr to be added to + // declarations after defintions. + ++I; + continue; } S.Diag(NewAttribute->getLocation(), @@ -2736,23 +2777,21 @@ static void diagnoseMissingConstinit(Sema &S, const VarDecl *InitDecl, // enough of the attribute list spelling information to extract that without // heroics. std::string SuitableSpelling; - if (S.getLangOpts().CPlusPlus2a) - SuitableSpelling = - S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit}); + if (S.getLangOpts().CPlusPlus20) + SuitableSpelling = std::string( + S.PP.getLastMacroWithSpelling(InsertLoc, {tok::kw_constinit})); if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11) - SuitableSpelling = S.PP.getLastMacroWithSpelling( - InsertLoc, - {tok::l_square, tok::l_square, S.PP.getIdentifierInfo("clang"), - tok::coloncolon, - S.PP.getIdentifierInfo("require_constant_initialization"), - tok::r_square, tok::r_square}); + SuitableSpelling = std::string(S.PP.getLastMacroWithSpelling( + InsertLoc, {tok::l_square, tok::l_square, + S.PP.getIdentifierInfo("clang"), tok::coloncolon, + S.PP.getIdentifierInfo("require_constant_initialization"), + tok::r_square, tok::r_square})); if (SuitableSpelling.empty()) - SuitableSpelling = S.PP.getLastMacroWithSpelling( - InsertLoc, - {tok::kw___attribute, tok::l_paren, tok::r_paren, - S.PP.getIdentifierInfo("require_constant_initialization"), - tok::r_paren, tok::r_paren}); - if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus2a) + SuitableSpelling = std::string(S.PP.getLastMacroWithSpelling( + InsertLoc, {tok::kw___attribute, tok::l_paren, tok::r_paren, + S.PP.getIdentifierInfo("require_constant_initialization"), + tok::r_paren, tok::r_paren})); + if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus20) SuitableSpelling = "constinit"; if (SuitableSpelling.empty() && S.getLangOpts().CPlusPlus11) SuitableSpelling = "[[clang::require_constant_initialization]]"; @@ -3884,11 +3923,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, if (!NewArray->isIncompleteArrayType() && !NewArray->isDependentType()) { for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD; PrevVD = PrevVD->getPreviousDecl()) { - const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType()); + QualType PrevVDTy = PrevVD->getType(); if (PrevVDTy->isIncompleteArrayType() || PrevVDTy->isDependentType()) continue; - if (!Context.hasSameType(NewArray, PrevVDTy)) + if (!Context.hasSameType(New->getType(), PrevVDTy)) return diagnoseVarDeclTypeMismatch(*this, New, PrevVD); } } @@ -4344,6 +4383,87 @@ void Sema::handleTagNumbering(const TagDecl *Tag, Scope *TagScope) { } } +namespace { +struct NonCLikeKind { + enum { + None, + BaseClass, + DefaultMemberInit, + Lambda, + Friend, + OtherMember, + Invalid, + } Kind = None; + SourceRange Range; + + explicit operator bool() { return Kind != None; } +}; +} + +/// Determine whether a class is C-like, according to the rules of C++ +/// [dcl.typedef] for anonymous classes with typedef names for linkage. +static NonCLikeKind getNonCLikeKindForAnonymousStruct(const CXXRecordDecl *RD) { + if (RD->isInvalidDecl()) + return {NonCLikeKind::Invalid, {}}; + + // C++ [dcl.typedef]p9: [P1766R1] + // An unnamed class with a typedef name for linkage purposes shall not + // + // -- have any base classes + if (RD->getNumBases()) + return {NonCLikeKind::BaseClass, + SourceRange(RD->bases_begin()->getBeginLoc(), + RD->bases_end()[-1].getEndLoc())}; + bool Invalid = false; + for (Decl *D : RD->decls()) { + // Don't complain about things we already diagnosed. + if (D->isInvalidDecl()) { + Invalid = true; + continue; + } + + // -- have any [...] default member initializers + if (auto *FD = dyn_cast<FieldDecl>(D)) { + if (FD->hasInClassInitializer()) { + auto *Init = FD->getInClassInitializer(); + return {NonCLikeKind::DefaultMemberInit, + Init ? Init->getSourceRange() : D->getSourceRange()}; + } + continue; + } + + // FIXME: We don't allow friend declarations. This violates the wording of + // P1766, but not the intent. + if (isa<FriendDecl>(D)) + return {NonCLikeKind::Friend, D->getSourceRange()}; + + // -- declare any members other than non-static data members, member + // enumerations, or member classes, + if (isa<StaticAssertDecl>(D) || isa<IndirectFieldDecl>(D) || + isa<EnumDecl>(D)) + continue; + auto *MemberRD = dyn_cast<CXXRecordDecl>(D); + if (!MemberRD) { + if (D->isImplicit()) + continue; + return {NonCLikeKind::OtherMember, D->getSourceRange()}; + } + + // -- contain a lambda-expression, + if (MemberRD->isLambda()) + return {NonCLikeKind::Lambda, MemberRD->getSourceRange()}; + + // and all member classes shall also satisfy these requirements + // (recursively). + if (MemberRD->isThisDeclarationADefinition()) { + if (auto Kind = getNonCLikeKindForAnonymousStruct(MemberRD)) + return Kind; + } + } + + return {Invalid ? NonCLikeKind::Invalid : NonCLikeKind::None, {}}; +} + void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, TypedefNameDecl *NewTD) { if (TagFromDeclSpec->isInvalidDecl()) @@ -4364,27 +4484,51 @@ void Sema::setTagNameForLinkagePurposes(TagDecl *TagFromDeclSpec, return; } - // If we've already computed linkage for the anonymous tag, then - // adding a typedef name for the anonymous decl can change that - // linkage, which might be a serious problem. Diagnose this as - // unsupported and ignore the typedef name. TODO: we should - // pursue this as a language defect and establish a formal rule - // for how to handle it. - if (TagFromDeclSpec->hasLinkageBeenComputed()) { - Diag(NewTD->getLocation(), diag::err_typedef_changes_linkage); + // C++ [dcl.typedef]p9: [P1766R1, applied as DR] + // An unnamed class with a typedef name for linkage purposes shall [be + // C-like]. + // + // FIXME: Also diagnose if we've already computed the linkage. That ideally + // shouldn't happen, but there are constructs that the language rule doesn't + // disallow for which we can't reasonably avoid computing linkage early. + const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TagFromDeclSpec); + NonCLikeKind NonCLike = RD ? getNonCLikeKindForAnonymousStruct(RD) + : NonCLikeKind(); + bool ChangesLinkage = TagFromDeclSpec->hasLinkageBeenComputed(); + if (NonCLike || ChangesLinkage) { + if (NonCLike.Kind == NonCLikeKind::Invalid) + return; + + unsigned DiagID = diag::ext_non_c_like_anon_struct_in_typedef; + if (ChangesLinkage) { + // If the linkage changes, we can't accept this as an extension. + if (NonCLike.Kind == NonCLikeKind::None) + DiagID = diag::err_typedef_changes_linkage; + else + DiagID = diag::err_non_c_like_anon_struct_in_typedef; + } - SourceLocation tagLoc = TagFromDeclSpec->getInnerLocStart(); - tagLoc = getLocForEndOfToken(tagLoc); + SourceLocation FixitLoc = + getLocForEndOfToken(TagFromDeclSpec->getInnerLocStart()); + llvm::SmallString<40> TextToInsert; + TextToInsert += ' '; + TextToInsert += NewTD->getIdentifier()->getName(); - llvm::SmallString<40> textToInsert; - textToInsert += ' '; - textToInsert += NewTD->getIdentifier()->getName(); - Diag(tagLoc, diag::note_typedef_changes_linkage) - << FixItHint::CreateInsertion(tagLoc, textToInsert); - return; + Diag(FixitLoc, DiagID) + << isa<TypeAliasDecl>(NewTD) + << FixItHint::CreateInsertion(FixitLoc, TextToInsert); + if (NonCLike.Kind != NonCLikeKind::None) { + Diag(NonCLike.Range.getBegin(), diag::note_non_c_like_anon_struct) + << NonCLike.Kind - 1 << NonCLike.Range; + } + Diag(NewTD->getLocation(), diag::note_typedef_for_linkage_here) + << NewTD << isa<TypeAliasDecl>(NewTD); + + if (ChangesLinkage) + return; } - // Otherwise, set this is the anon-decl typedef for the tag. + // Otherwise, set this as the anon-decl typedef for the tag. TagFromDeclSpec->setTypedefNameForAnonDecl(NewTD); } @@ -4915,6 +5059,10 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, // define non-static data members. [Note: nested types and // functions cannot be declared within an anonymous union. ] for (auto *Mem : Record->decls()) { + // Ignore invalid declarations; we already diagnosed them. + if (Mem->isInvalidDecl()) + continue; + if (auto *FD = dyn_cast<FieldDecl>(Mem)) { // C++ [class.union]p3: // An anonymous union shall not have private or protected @@ -5138,8 +5286,8 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, Chain.push_back(Anon); RecordDecl *RecordDef = Record->getDefinition(); - if (RequireCompleteType(Anon->getLocation(), RecTy, - diag::err_field_incomplete) || + if (RequireCompleteSizedType(Anon->getLocation(), RecTy, + diag::err_field_incomplete_or_sizeless) || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, AS_none, Chain)) { Anon->setInvalidDecl(); @@ -6142,6 +6290,8 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { void Sema::deduceOpenCLAddressSpace(ValueDecl *Decl) { if (Decl->getType().hasAddressSpace()) return; + if (Decl->getType()->isDependentType()) + return; if (VarDecl *Var = dyn_cast<VarDecl>(Decl)) { QualType Type = Var->getType(); if (Type->isSamplerT() || Type->isVoidType()) @@ -6468,6 +6618,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { return true; if (DC->isRecord()) return false; + if (isa<RequiresExprBodyDecl>(DC)) + return false; llvm_unreachable("Unexpected context"); } @@ -6753,28 +6905,49 @@ NamedDecl *Sema::ActOnVariableDeclarator( if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { - if (RD->isLocalClass()) + // Walk up the enclosing DeclContexts to check for any that are + // incompatible with static data members. + const DeclContext *FunctionOrMethod = nullptr; + const CXXRecordDecl *AnonStruct = nullptr; + for (DeclContext *Ctxt = DC; Ctxt; Ctxt = Ctxt->getParent()) { + if (Ctxt->isFunctionOrMethod()) { + FunctionOrMethod = Ctxt; + break; + } + const CXXRecordDecl *ParentDecl = dyn_cast<CXXRecordDecl>(Ctxt); + if (ParentDecl && !ParentDecl->getDeclName()) { + AnonStruct = ParentDecl; + break; + } + } + if (FunctionOrMethod) { + // C++ [class.static.data]p5: A local class shall not have static data + // members. Diag(D.getIdentifierLoc(), diag::err_static_data_member_not_allowed_in_local_class) - << Name << RD->getDeclName(); - - // C++98 [class.union]p1: If a union contains a static data member, - // the program is ill-formed. C++11 drops this restriction. - if (RD->isUnion()) + << Name << RD->getDeclName() << RD->getTagKind(); + } else if (AnonStruct) { + // C++ [class.static.data]p4: Unnamed classes and classes contained + // directly or indirectly within unnamed classes shall not contain + // static data members. + Diag(D.getIdentifierLoc(), + diag::err_static_data_member_not_allowed_in_anon_struct) + << Name << AnonStruct->getTagKind(); + Invalid = true; + } else if (RD->isUnion()) { + // C++98 [class.union]p1: If a union contains a static data member, + // the program is ill-formed. C++11 drops this restriction. Diag(D.getIdentifierLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_static_data_member_in_union : diag::ext_static_data_member_in_union) << Name; - // We conservatively disallow static data members in anonymous structs. - else if (!RD->getDeclName()) - Diag(D.getIdentifierLoc(), - diag::err_static_data_member_not_allowed_in_anon_struct) - << Name << RD->isUnion(); + } } } // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. + bool InvalidScope = false; TemplateParams = MatchTemplateParametersToScopeSpecifier( D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), D.getCXXScopeSpec(), @@ -6782,7 +6955,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( ? D.getName().TemplateId : nullptr, TemplateParamLists, - /*never a friend*/ false, IsMemberSpecialization, Invalid); + /*never a friend*/ false, IsMemberSpecialization, InvalidScope); + Invalid |= InvalidScope; if (TemplateParams) { if (!TemplateParams->size() && @@ -6918,7 +7092,8 @@ NamedDecl *Sema::ActOnVariableDeclarator( diag::err_thread_non_global) << DeclSpec::getSpecifierName(TSCS); else if (!Context.getTargetInfo().isTLSSupported()) { - if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + getLangOpts().SYCLIsDevice) { // Postpone error emission until we've collected attributes required to // figure out whether it's a host or device variable and whether the // error should be ignored. @@ -6946,6 +7121,7 @@ NamedDecl *Sema::ActOnVariableDeclarator( case CSK_constexpr: NewVD->setConstexpr(true); + MaybeAddCUDAConstantAttr(NewVD); // C++1z [dcl.spec.constexpr]p1: // A static data member declared with the constexpr specifier is // implicitly an inline variable. @@ -7019,13 +7195,18 @@ NamedDecl *Sema::ActOnVariableDeclarator( // Handle attributes prior to checking for duplicates in MergeVarDecl ProcessDeclAttributes(S, NewVD, D); - if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice) { + if (getLangOpts().CUDA || getLangOpts().OpenMPIsDevice || + getLangOpts().SYCLIsDevice) { if (EmitTLSUnsupportedError && ((getLangOpts().CUDA && DeclAttrsMatchCUDAMode(getLangOpts(), NewVD)) || (getLangOpts().OpenMPIsDevice && OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(NewVD)))) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_thread_unsupported); + + if (EmitTLSUnsupportedError && + (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice))) + targetDiag(D.getIdentifierLoc(), diag::err_thread_unsupported); // CUDA B.2.5: "__shared__ and __constant__ variables have implied static // storage [duration]." if (SC == SC_None && S->getFnParent() != nullptr && @@ -7680,6 +7861,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() || NewVD->hasExternalStorage()) { if (!T->isSamplerT() && + !T->isDependentType() && !(T.getAddressSpace() == LangAS::opencl_constant || (T.getAddressSpace() == LangAS::opencl_global && (getLangOpts().OpenCLVersion == 200 || @@ -7822,6 +8004,12 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } + if (!NewVD->hasLocalStorage() && T->isSizelessType()) { + Diag(NewVD->getLocation(), diag::err_sizeless_nonlocal) << T; + NewVD->setInvalidDecl(); + return; + } + if (isVM && NewVD->hasAttr<BlocksAttr>()) { Diag(NewVD->getLocation(), diag::err_block_on_vm); NewVD->setInvalidDecl(); @@ -7909,30 +8097,8 @@ struct FindOverriddenMethod { return false; } }; - -enum OverrideErrorKind { OEK_All, OEK_NonDeleted, OEK_Deleted }; } // end anonymous namespace -/// Report an error regarding overriding, along with any relevant -/// overridden methods. -/// -/// \param DiagID the primary error to report. -/// \param MD the overriding method. -/// \param OEK which overrides to include as notes. -static void ReportOverrides(Sema& S, unsigned DiagID, const CXXMethodDecl *MD, - OverrideErrorKind OEK = OEK_All) { - S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); - for (const CXXMethodDecl *O : MD->overridden_methods()) { - // This check (& the OEK parameter) could be replaced by a predicate, but - // without lambdas that would be overkill. This is still nicer than writing - // out the diag loop 3 times. - if ((OEK == OEK_All) || - (OEK == OEK_NonDeleted && !O->isDeleted()) || - (OEK == OEK_Deleted && O->isDeleted())) - S.Diag(O->getLocation(), diag::note_overridden_virtual_function); - } -} - /// AddOverriddenMethods - See if a method overrides any in the base classes, /// and if so, check that it's a valid override and remember it. bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { @@ -7941,8 +8107,6 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { FindOverriddenMethod FOM; FOM.Method = MD; FOM.S = this; - bool hasDeletedOverridenMethods = false; - bool hasNonDeletedOverridenMethods = false; bool AddedAny = false; if (DC->lookupInBases(FOM, Paths)) { for (auto *I : Paths.found_decls()) { @@ -7952,21 +8116,12 @@ bool Sema::AddOverriddenMethods(CXXRecordDecl *DC, CXXMethodDecl *MD) { !CheckOverridingFunctionAttributes(MD, OldMD) && !CheckOverridingFunctionExceptionSpec(MD, OldMD) && !CheckIfOverriddenFunctionIsMarkedFinal(MD, OldMD)) { - hasDeletedOverridenMethods |= OldMD->isDeleted(); - hasNonDeletedOverridenMethods |= !OldMD->isDeleted(); AddedAny = true; } } } } - if (hasDeletedOverridenMethods && !MD->isDeleted()) { - ReportOverrides(*this, diag::err_non_deleted_override, MD, OEK_Deleted); - } - if (hasNonDeletedOverridenMethods && MD->isDeleted()) { - ReportOverrides(*this, diag::err_deleted_override, MD, OEK_NonDeleted); - } - return AddedAny; } @@ -8654,11 +8809,24 @@ static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, + MultiTemplateParamsArg TemplateParamListsRef, bool &AddToScope) { QualType R = TInfo->getType(); assert(R->isFunctionType()); + if (R.getCanonicalType()->castAs<FunctionType>()->getCmseNSCallAttr()) + Diag(D.getIdentifierLoc(), diag::err_function_decl_cmse_ns_call); + + SmallVector<TemplateParameterList *, 4> TemplateParamLists; + for (TemplateParameterList *TPL : TemplateParamListsRef) + TemplateParamLists.push_back(TPL); + if (TemplateParameterList *Invented = D.getInventedTemplateParameterList()) { + if (!TemplateParamLists.empty() && + Invented->getDepth() == TemplateParamLists.back()->getDepth()) + TemplateParamLists.back() = Invented; + else + TemplateParamLists.push_back(Invented); + } // TODO: consider using NameInfo for diagnostic. DeclarationNameInfo NameInfo = GetNameForDeclarator(D); @@ -8738,15 +8906,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Match up the template parameter lists with the scope specifier, then // determine whether we have a template or a template specialization. bool Invalid = false; - if (TemplateParameterList *TemplateParams = - MatchTemplateParametersToScopeSpecifier( - D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), - D.getCXXScopeSpec(), - D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId - ? D.getName().TemplateId - : nullptr, - TemplateParamLists, isFriend, isMemberSpecialization, - Invalid)) { + TemplateParameterList *TemplateParams = + MatchTemplateParametersToScopeSpecifier( + D.getDeclSpec().getBeginLoc(), D.getIdentifierLoc(), + D.getCXXScopeSpec(), + D.getName().getKind() == UnqualifiedIdKind::IK_TemplateId + ? D.getName().TemplateId + : nullptr, + TemplateParamLists, isFriend, isMemberSpecialization, + Invalid); + if (TemplateParams) { if (TemplateParams->size() > 0) { // This is a function template @@ -8779,7 +8948,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // For source fidelity, store the other template param lists. if (TemplateParamLists.size() > 1) { NewFD->setTemplateParameterListsInfo(Context, - TemplateParamLists.drop_back(1)); + ArrayRef<TemplateParameterList *>(TemplateParamLists) + .drop_back(1)); } } else { // This is a function template specialization. @@ -8914,9 +9084,24 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++11 [dcl.constexpr]p3: functions declared constexpr are required to // be either constructors or to return a literal type. Therefore, // destructors cannot be declared constexpr. - if (isa<CXXDestructorDecl>(NewFD) && !getLangOpts().CPlusPlus2a) { + if (isa<CXXDestructorDecl>(NewFD) && + (!getLangOpts().CPlusPlus20 || ConstexprKind == CSK_consteval)) { Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_constexpr_dtor) << ConstexprKind; + NewFD->setConstexprKind(getLangOpts().CPlusPlus20 ? CSK_unspecified : CSK_constexpr); + } + // C++20 [dcl.constexpr]p2: An allocation function, or a + // deallocation function shall not be declared with the consteval + // specifier. + if (ConstexprKind == CSK_consteval && + (NewFD->getOverloadedOperator() == OO_New || + NewFD->getOverloadedOperator() == OO_Array_New || + NewFD->getOverloadedOperator() == OO_Delete || + NewFD->getOverloadedOperator() == OO_Array_Delete)) { + Diag(D.getDeclSpec().getConstexprSpecLoc(), + diag::err_invalid_consteval_decl_kind) + << NewFD; + NewFD->setConstexprKind(CSK_constexpr); } } @@ -8945,8 +9130,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // If a function is defined as defaulted or deleted, mark it as such now. - // FIXME: Does this ever happen? ActOnStartOfFunctionDef forces the function - // definition kind to FDK_Definition. + // We'll do the relevant checks on defaulted / deleted functions later. switch (D.getFunctionDefinitionKind()) { case FDK_Declaration: case FDK_Definition: @@ -9808,6 +9992,18 @@ static bool CheckMultiVersionValue(Sema &S, const FunctionDecl *FD) { return false; } +// Provide a white-list of attributes that are allowed to be combined with +// multiversion functions. +static bool AttrCompatibleWithMultiVersion(attr::Kind Kind, + MultiVersionKind MVType) { + switch (Kind) { + default: + return false; + case attr::Used: + return MVType == MultiVersionKind::Target; + } +} + static bool HasNonMultiVersionAttributes(const FunctionDecl *FD, MultiVersionKind MVType) { for (const Attr *A : FD->attrs()) { @@ -9823,7 +10019,9 @@ static bool HasNonMultiVersionAttributes(const FunctionDecl *FD, return true; break; default: - return true; + if (!AttrCompatibleWithMultiVersion(A->getKind(), MVType)) + return true; + break; } } return false; @@ -10562,9 +10760,6 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, return Redeclaration; } } - } else if (CXXConversionDecl *Conversion - = dyn_cast<CXXConversionDecl>(NewFD)) { - ActOnConversionDeclarator(Conversion); } else if (auto *Guide = dyn_cast<CXXDeductionGuideDecl>(NewFD)) { if (auto *TD = Guide->getDescribedFunctionTemplate()) CheckDeductionGuideTemplate(TD); @@ -10581,12 +10776,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, if (!Method->isFunctionTemplateSpecialization() && !Method->getDescribedFunctionTemplate() && Method->isCanonicalDecl()) { - if (AddOverriddenMethods(Method->getParent(), Method)) { - // If the function was marked as "static", we have a problem. - if (NewFD->getStorageClass() == SC_Static) { - ReportOverrides(*this, diag::err_static_overrides_virtual, Method); - } - } + AddOverriddenMethods(Method->getParent(), Method); } if (Method->isVirtual() && NewFD->getTrailingRequiresClause()) // C++2a [class.virtual]p6 @@ -10598,6 +10788,9 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, checkThisInStaticMemberFunctionType(Method); } + if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(NewFD)) + ActOnConversionDeclarator(Conversion); + // Extra checking for C++ overloaded operators (C++ [over.oper]). if (NewFD->isOverloadedOperator() && CheckOverloadedOperatorDeclaration(NewFD)) { @@ -11363,6 +11556,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, Expr *Init) { + assert(!Init || !Init->containsErrors()); QualType DeducedType = deduceVarTypeFromInitializer( VDecl, VDecl->getDeclName(), VDecl->getType(), VDecl->getTypeSourceInfo(), VDecl->getSourceRange(), DirectInit, Init); @@ -11396,6 +11590,9 @@ bool Sema::DeduceVariableDeclarationType(VarDecl *VDecl, bool DirectInit, void Sema::checkNonTrivialCUnionInInitializer(const Expr *Init, SourceLocation Loc) { + if (auto *EWC = dyn_cast<ExprWithCleanups>(Init)) + Init = EWC->getSubExpr(); + if (auto *CE = dyn_cast<ConstantExpr>(Init)) Init = CE->getSubExpr(); @@ -11698,7 +11895,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // TypoExpr. ExprResult Res = CorrectDelayedTyposInExpr(Init, VDecl); if (!Res.isUsable()) { + // There are unresolved typos in Init, just drop them. + // FIXME: improve the recovery strategy to preserve the Init. + RealDecl->setInvalidDecl(); + return; + } + if (Res.get()->containsErrors()) { + // Invalidate the decl as we don't know the type for recovery-expr yet. RealDecl->setInvalidDecl(); + VDecl->setInit(Res.get()); return; } Init = Res.get(); @@ -11790,6 +11995,13 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { return; } + // The LoaderUninitialized attribute acts as a definition (of undef). + if (VDecl->hasAttr<LoaderUninitializedAttr>()) { + Diag(VDecl->getLocation(), diag::err_loader_uninitialized_cant_init); + VDecl->setInvalidDecl(); + return; + } + // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; @@ -11821,7 +12033,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { // Try to correct any TypoExprs in the initialization arguments. for (size_t Idx = 0; Idx < Args.size(); ++Idx) { ExprResult Res = CorrectDelayedTyposInExpr( - Args[Idx], VDecl, [this, Entity, Kind](Expr *E) { + Args[Idx], VDecl, /*RecoverUncorrectedTypos=*/false, + [this, Entity, Kind](Expr *E) { InitializationSequence Init(*this, Entity, Kind, MultiExprArg(E)); return Init.Failed() ? ExprError() : E; }); @@ -11839,7 +12052,12 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { - VDecl->setInvalidDecl(); + // If the provied initializer fails to initialize the var decl, + // we attach a recovery expr for better recovery. + auto RecoveryExpr = + CreateRecoveryExpr(Init->getBeginLoc(), Init->getEndLoc(), Args); + if (RecoveryExpr.get()) + VDecl->setInit(RecoveryExpr.get()); return; } @@ -12100,6 +12318,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) { VDecl->setInitStyle(VarDecl::ListInit); } + if (LangOpts.OpenMP && VDecl->isFileVarDecl()) + DeclsToCheckForDeferredDiags.push_back(VDecl); CheckCompleteVariableDeclaration(VDecl); } @@ -12120,7 +12340,7 @@ void Sema::ActOnInitializerError(Decl *D) { BD->setInvalidDecl(); // Auto types are meaningless if we can't make sense of the initializer. - if (ParsingInitForAutoVars.count(D)) { + if (VD->getType()->isUndeducedType()) { D->setInvalidDecl(); return; } @@ -12203,6 +12423,22 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { return; } + if (!Var->isInvalidDecl() && RealDecl->hasAttr<LoaderUninitializedAttr>()) { + if (CXXRecordDecl *RD = Var->getType()->getAsCXXRecordDecl()) { + if (!RD->hasTrivialDefaultConstructor()) { + Diag(Var->getLocation(), diag::err_loader_uninitialized_trivial_ctor); + Var->setInvalidDecl(); + return; + } + } + if (Var->getStorageClass() == SC_Extern) { + Diag(Var->getLocation(), diag::err_loader_uninitialized_extern_decl) + << Var; + Var->setInvalidDecl(); + return; + } + } + VarDecl::DefinitionKind DefKind = Var->isThisDeclarationADefinition(); if (!Var->isInvalidDecl() && DefKind != VarDecl::DeclarationOnly && Var->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion()) @@ -12260,9 +12496,9 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { if (!Var->isInvalidDecl()) { if (const IncompleteArrayType *ArrayT = Context.getAsIncompleteArrayType(Type)) { - if (RequireCompleteType(Var->getLocation(), - ArrayT->getElementType(), - diag::err_illegal_decl_array_incomplete_type)) + if (RequireCompleteSizedType( + Var->getLocation(), ArrayT->getElementType(), + diag::err_array_incomplete_or_sizeless_type)) Var->setInvalidDecl(); } else if (Var->getStorageClass() == SC_Static) { // C99 6.9.2p3: If the declaration of an identifier for an object is @@ -12378,12 +12614,18 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) { InitializationSequence InitSeq(*this, Entity, Kind, None); ExprResult Init = InitSeq.Perform(*this, Entity, Kind, None); - if (Init.isInvalid()) - Var->setInvalidDecl(); - else if (Init.get()) { + + if (Init.get()) { Var->setInit(MaybeCreateExprWithCleanups(Init.get())); // This is important for template substitution. Var->setInitStyle(VarDecl::CallInit); + } else if (Init.isInvalid()) { + // If default-init fails, attach a recovery-expr initializer to track + // that initialization was attempted and failed. + auto RecoveryExpr = + CreateRecoveryExpr(Var->getLocation(), Var->getLocation(), {}); + if (RecoveryExpr.get()) + Var->setInit(RecoveryExpr.get()); } CheckCompleteVariableDeclaration(Var); @@ -12507,6 +12749,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { var->getDeclContext()->getRedeclContext()->isFileContext() && var->isExternallyVisible() && var->hasLinkage() && !var->isInline() && !var->getDescribedVarTemplate() && + !isa<VarTemplatePartialSpecializationDecl>(var) && !isTemplateInstantiation(var->getTemplateSpecializationKind()) && !getDiagnostics().isIgnored(diag::warn_missing_variable_declarations, var->getLocation())) { @@ -12559,7 +12802,7 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (GlobalStorage && var->isThisDeclarationADefinition() && !inTemplateInstantiation()) { PragmaStack<StringLiteral *> *Stack = nullptr; - int SectionFlags = ASTContext::PSF_Implicit | ASTContext::PSF_Read; + int SectionFlags = ASTContext::PSF_Read; if (var->getType().isConstQualified()) Stack = &ConstSegStack; else if (!var->getInit()) { @@ -12569,14 +12812,19 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Stack = &DataSegStack; SectionFlags |= ASTContext::PSF_Write; } - if (Stack->CurrentValue && !var->hasAttr<SectionAttr>()) + if (const SectionAttr *SA = var->getAttr<SectionAttr>()) { + if (SA->getSyntax() == AttributeCommonInfo::AS_Declspec) + SectionFlags |= ASTContext::PSF_Implicit; + UnifySection(SA->getName(), SectionFlags, var); + } else if (Stack->CurrentValue) { + SectionFlags |= ASTContext::PSF_Implicit; + auto SectionName = Stack->CurrentValue->getString(); var->addAttr(SectionAttr::CreateImplicit( - Context, Stack->CurrentValue->getString(), - Stack->CurrentPragmaLocation, AttributeCommonInfo::AS_Pragma, - SectionAttr::Declspec_allocate)); - if (const SectionAttr *SA = var->getAttr<SectionAttr>()) - if (UnifySection(SA->getName(), SectionFlags, var)) + Context, SectionName, Stack->CurrentPragmaLocation, + AttributeCommonInfo::AS_Pragma, SectionAttr::Declspec_allocate)); + if (UnifySection(SectionName, SectionFlags, var)) var->dropAttr<SectionAttr>(); + } // Apply the init_seg attribute if this has an initializer. If the // initializer turns out to not be dynamic, we'll end up ignoring this @@ -13013,13 +13261,15 @@ Sema::BuildDeclaratorGroup(MutableArrayRef<Decl *> Group) { DeducedDecl = D; } else if (!Context.hasSameType(DT->getDeducedType(), Deduced)) { auto *AT = dyn_cast<AutoType>(DT); - Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), - diag::err_auto_different_deductions) - << (AT ? (unsigned)AT->getKeyword() : 3) - << Deduced << DeducedDecl->getDeclName() - << DT->getDeducedType() << D->getDeclName() - << DeducedDecl->getInit()->getSourceRange() - << D->getInit()->getSourceRange(); + auto Dia = Diag(D->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + diag::err_auto_different_deductions) + << (AT ? (unsigned)AT->getKeyword() : 3) << Deduced + << DeducedDecl->getDeclName() << DT->getDeducedType() + << D->getDeclName(); + if (DeducedDecl->hasInit()) + Dia << DeducedDecl->getInit()->getSourceRange(); + if (D->getInit()) + Dia << D->getInit()->getSourceRange(); D->setInvalidDecl(); break; } @@ -13398,9 +13648,28 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, assert(D.isFunctionDeclarator() && "Not a function declarator!"); Scope *ParentScope = FnBodyScope->getParent(); + // Check if we are in an `omp begin/end declare variant` scope. If we are, and + // we define a non-templated function definition, we will create a declaration + // instead (=BaseFD), and emit the definition with a mangled name afterwards. + // The base function declaration will have the equivalent of an `omp declare + // variant` annotation which specifies the mangled definition as a + // specialization function under the OpenMP context defined as part of the + // `omp begin declare variant`. + FunctionDecl *BaseFD = nullptr; + if (LangOpts.OpenMP && isInOpenMPDeclareVariantScope() && + TemplateParameterLists.empty()) + BaseFD = ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope( + ParentScope, D); + D.setFunctionDefinitionKind(FDK_Definition); Decl *DP = HandleDeclarator(ParentScope, D, TemplateParameterLists); - return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); + Decl *Dcl = ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); + + if (BaseFD) + ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + cast<FunctionDecl>(Dcl), BaseFD); + + return Dcl; } void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) { @@ -13593,13 +13862,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, VarDecl *VD = C.getCapturedVar(); if (VD->isInitCapture()) S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); - QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), - CaptureType, /*Invalid*/false); + I->getType(), /*Invalid*/false); } else if (C.capturesThis()) { LSI->addThisCapture(/*Nested*/ false, C.getLocation(), I->getType(), @@ -13632,7 +13900,9 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // Do not push if it is a lambda because one is already pushed when building // the lambda in ActOnStartOfLambdaDefinition(). if (!isLambdaCallOperator(FD)) - PushExpressionEvaluationContext(ExprEvalContexts.back().Context); + PushExpressionEvaluationContext( + FD->isConsteval() ? ExpressionEvaluationContext::ConstantEvaluated + : ExprEvalContexts.back().Context); // Check for defining attributes before the check for redefinition. if (const auto *Attr = FD->getAttr<AliasAttr>()) { @@ -13996,11 +14266,48 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, : FixItHint{}); } } else { + // Returns true if the token beginning at this Loc is `const`. + auto isLocAtConst = [&](SourceLocation Loc, const SourceManager &SM, + const LangOptions &LangOpts) { + std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); + if (LocInfo.first.isInvalid()) + return false; + + bool Invalid = false; + StringRef Buffer = SM.getBufferData(LocInfo.first, &Invalid); + if (Invalid) + return false; + + if (LocInfo.second > Buffer.size()) + return false; + + const char *LexStart = Buffer.data() + LocInfo.second; + StringRef StartTok(LexStart, Buffer.size() - LocInfo.second); + + return StartTok.consume_front("const") && + (StartTok.empty() || isWhitespace(StartTok[0]) || + StartTok.startswith("/*") || StartTok.startswith("//")); + }; + + auto findBeginLoc = [&]() { + // If the return type has `const` qualifier, we want to insert + // `static` before `const` (and not before the typename). + if ((FD->getReturnType()->isAnyPointerType() && + FD->getReturnType()->getPointeeType().isConstQualified()) || + FD->getReturnType().isConstQualified()) { + // But only do this if we can determine where the `const` is. + + if (isLocAtConst(FD->getBeginLoc(), getSourceManager(), + getLangOpts())) + + return FD->getBeginLoc(); + } + return FD->getTypeSpecStartLoc(); + }; Diag(FD->getTypeSpecStartLoc(), diag::note_static_for_internal_linkage) << /* function */ 1 << (FD->getStorageClass() == SC_None - ? FixItHint::CreateInsertion(FD->getTypeSpecStartLoc(), - "static ") + ? FixItHint::CreateInsertion(findBeginLoc(), "static ") : FixItHint{}); } @@ -14008,11 +14315,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Warn if K&R function is defined without a previous declaration. // This warning is issued only if the definition itself does not provide // a prototype. Only K&R definitions do not provide a prototype. - // An empty list in a function declarator that is part of a definition - // of that function specifies that the function has no parameters - // (C99 6.7.5.3p14) - if (!FD->hasWrittenPrototype() && FD->getNumParams() > 0 && - !LangOpts.CPlusPlus) { + if (!FD->hasWrittenPrototype()) { TypeSourceInfo *TI = FD->getTypeSourceInfo(); TypeLoc TL = TI->getTypeLoc(); FunctionTypeLoc FTL = TL.getAsAdjusted<FunctionTypeLoc>(); @@ -14142,7 +14445,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (getDiagnostics().hasErrorOccurred() || + if (getDiagnostics().hasUncompilableErrorOccurred() || getDiagnostics().getSuppressAllDiagnostics()) { DiscardCleanupsInEvaluationContext(); } @@ -14198,10 +14501,17 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. - if (getDiagnostics().hasErrorOccurred()) { + if (getDiagnostics().hasUncompilableErrorOccurred()) { DiscardCleanupsInEvaluationContext(); } + if (LangOpts.OpenMP || LangOpts.CUDA || LangOpts.SYCLIsDevice) { + auto ES = getEmissionStatus(FD); + if (ES == Sema::FunctionEmissionStatus::Emitted || + ES == Sema::FunctionEmissionStatus::Unknown) + DeclsToCheckForDeferredDiags.push_back(FD); + } + return dcl; } @@ -14333,6 +14643,77 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, return FD; } +/// If this function is a C++ replaceable global allocation function +/// (C++2a [basic.stc.dynamic.allocation], C++2a [new.delete]), +/// adds any function attributes that we know a priori based on the standard. +/// +/// We need to check for duplicate attributes both here and where user-written +/// attributes are applied to declarations. +void Sema::AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction( + FunctionDecl *FD) { + if (FD->isInvalidDecl()) + return; + + if (FD->getDeclName().getCXXOverloadedOperator() != OO_New && + FD->getDeclName().getCXXOverloadedOperator() != OO_Array_New) + return; + + Optional<unsigned> AlignmentParam; + bool IsNothrow = false; + if (!FD->isReplaceableGlobalAllocationFunction(&AlignmentParam, &IsNothrow)) + return; + + // C++2a [basic.stc.dynamic.allocation]p4: + // An allocation function that has a non-throwing exception specification + // indicates failure by returning a null pointer value. Any other allocation + // function never returns a null pointer value and indicates failure only by + // throwing an exception [...] + if (!IsNothrow && !FD->hasAttr<ReturnsNonNullAttr>()) + FD->addAttr(ReturnsNonNullAttr::CreateImplicit(Context, FD->getLocation())); + + // C++2a [basic.stc.dynamic.allocation]p2: + // An allocation function attempts to allocate the requested amount of + // storage. [...] If the request succeeds, the value returned by a + // replaceable allocation function is a [...] pointer value p0 different + // from any previously returned value p1 [...] + // + // However, this particular information is being added in codegen, + // because there is an opt-out switch for it (-fno-assume-sane-operator-new) + + // C++2a [basic.stc.dynamic.allocation]p2: + // An allocation function attempts to allocate the requested amount of + // storage. If it is successful, it returns the address of the start of a + // block of storage whose length in bytes is at least as large as the + // requested size. + if (!FD->hasAttr<AllocSizeAttr>()) { + FD->addAttr(AllocSizeAttr::CreateImplicit( + Context, /*ElemSizeParam=*/ParamIdx(1, FD), + /*NumElemsParam=*/ParamIdx(), FD->getLocation())); + } + + // C++2a [basic.stc.dynamic.allocation]p3: + // For an allocation function [...], the pointer returned on a successful + // call shall represent the address of storage that is aligned as follows: + // (3.1) If the allocation function takes an argument of type + // std​::​align_Âval_Ât, the storage will have the alignment + // specified by the value of this argument. + if (AlignmentParam.hasValue() && !FD->hasAttr<AllocAlignAttr>()) { + FD->addAttr(AllocAlignAttr::CreateImplicit( + Context, ParamIdx(AlignmentParam.getValue(), FD), FD->getLocation())); + } + + // FIXME: + // C++2a [basic.stc.dynamic.allocation]p3: + // For an allocation function [...], the pointer returned on a successful + // call shall represent the address of storage that is aligned as follows: + // (3.2) Otherwise, if the allocation function is named operator new[], + // the storage is aligned for any object that does not have + // new-extended alignment ([basic.align]) and is no larger than the + // requested size. + // (3.3) Otherwise, the storage is aligned for any object that does not + // have new-extended alignment and is of the requested size. +} + /// Adds any function attributes that we know a priori based on /// the declaration of this function. /// @@ -14433,6 +14814,8 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } } + AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD); + // If C++ exceptions are enabled but we are told extern "C" functions cannot // throw, add an implicit nothrow attribute to any extern "C" function we come // across. @@ -14538,12 +14921,16 @@ bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { if (T->isDependentType()) return false; + // This doesn't use 'isIntegralType' despite the error message mentioning + // integral type because isIntegralType would also allow enum types in C. if (const BuiltinType *BT = T->getAs<BuiltinType>()) if (BT->isInteger()) return false; - Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T; - return true; + if (T->isExtIntType()) + return false; + + return Diag(UnderlyingLoc, diag::err_enum_invalid_underlying) << T; } /// Check whether this is a valid redeclaration of a previous enumeration. @@ -15302,16 +15689,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) { const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl); - - // If this is an elaborated-type-specifier for a scoped enumeration, - // the 'class' keyword is not necessary and not permitted. - if (TUK == TUK_Reference || TUK == TUK_Friend) { - if (ScopedEnum) - Diag(ScopedEnumKWLoc, diag::err_enum_class_reference) - << PrevEnum->isScoped() - << FixItHint::CreateRemoval(ScopedEnumKWLoc); + if (TUK == TUK_Reference || TUK == TUK_Friend) return PrevTagDecl; - } QualType EnumUnderlyingTy; if (TypeSourceInfo *TI = EnumUnderlying.dyn_cast<TypeSourceInfo*>()) @@ -15789,7 +16168,7 @@ Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { assert(isa<ObjCContainerDecl>(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast<DeclContext>(IDecl); - assert(getContainingDC(OCD) == CurContext && + assert(OCD->getLexicalParent() == CurContext && "The next DeclContext should be lexically contained in the current one."); CurContext = OCD; return IDecl; @@ -15900,6 +16279,10 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, IdentifierInfo *FieldName, QualType FieldTy, bool IsMsStruct, Expr *BitWidth, bool *ZeroWidth) { + assert(BitWidth); + if (BitWidth->containsErrors()) + return ExprError(); + // Default to true; that shouldn't confuse checks for emptiness if (ZeroWidth) *ZeroWidth = true; @@ -15907,8 +16290,9 @@ ExprResult Sema::VerifyBitField(SourceLocation FieldLoc, // C99 6.7.2.1p4 - verify the field type. // C++ 9.6p3: A bit-field shall have integral or enumeration type. if (!FieldTy->isDependentType() && !FieldTy->isIntegralOrEnumerationType()) { - // Handle incomplete types with specific error. - if (RequireCompleteType(FieldLoc, FieldTy, diag::err_field_incomplete)) + // Handle incomplete and sizeless types with a specific error. + if (RequireCompleteSizedType(FieldLoc, FieldTy, + diag::err_field_incomplete_or_sizeless)) return ExprError(); if (FieldName) return Diag(FieldLoc, diag::err_not_integral_type_bitfield) @@ -16118,14 +16502,15 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, // If we receive a broken type, recover by assuming 'int' and // marking this declaration as invalid. - if (T.isNull()) { + if (T.isNull() || T->containsErrors()) { InvalidDecl = true; T = Context.IntTy; } QualType EltTy = Context.getBaseElementType(T); - if (!EltTy->isDependentType()) { - if (RequireCompleteType(Loc, EltTy, diag::err_field_incomplete)) { + if (!EltTy->isDependentType() && !EltTy->containsErrors()) { + if (RequireCompleteSizedType(Loc, EltTy, + diag::err_field_incomplete_or_sizeless)) { // Fields of incomplete type force their record to be invalid. Record->setInvalidDecl(); InvalidDecl = true; @@ -16214,6 +16599,14 @@ FieldDecl *Sema::CheckFieldDecl(DeclarationName Name, QualType T, BitWidth = nullptr; ZeroWidth = false; } + + // Only data members can have in-class initializers. + if (BitWidth && !II && InitStyle) { + Diag(Loc, diag::err_anon_bitfield_init); + InvalidDecl = true; + BitWidth = nullptr; + ZeroWidth = false; + } } // Check that 'mutable' is consistent with the type of the declaration. @@ -16669,8 +17062,9 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, // elsewhere, after synthesized ivars are known. } } else if (!FDTy->isDependentType() && - RequireCompleteType(FD->getLocation(), FD->getType(), - diag::err_field_incomplete)) { + RequireCompleteSizedType( + FD->getLocation(), FD->getType(), + diag::err_field_incomplete_or_sizeless)) { // Incomplete type FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); @@ -16728,8 +17122,8 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Context, "", UnavailableAttr::IR_ARCFieldWithOwnership, FD->getLocation())); } else if (getLangOpts().ObjC && - getLangOpts().getGC() != LangOptions::NonGC && - Record && !Record->hasObjectMember()) { + getLangOpts().getGC() != LangOptions::NonGC && Record && + !Record->hasObjectMember()) { if (FD->getType()->isObjCObjectPointerType() || FD->getType().isObjCGCStrong()) Record->setHasObjectMember(true); @@ -16793,10 +17187,10 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, I.setAccess((*I)->getAccess()); } - if (!CXXRecord->isDependentType()) { - // Add any implicitly-declared members to this class. - AddImplicitlyDeclaredMembersToClass(CXXRecord); + // Add any implicitly-declared members to this class. + AddImplicitlyDeclaredMembersToClass(CXXRecord); + if (!CXXRecord->isDependentType()) { if (!CXXRecord->isInvalidDecl()) { // If we have virtual base classes, we may end up finding multiple // final overriders for a given virtual function. Check for this @@ -17355,9 +17749,11 @@ static void CheckForDuplicateEnumValues(Sema &S, ArrayRef<Decl *> Elements, typedef SmallVector<std::unique_ptr<ECDVector>, 3> DuplicatesVector; typedef llvm::PointerUnion<EnumConstantDecl*, ECDVector*> DeclOrVector; + + // DenseMaps cannot contain the all ones int64_t value, so use unordered_map. typedef std::unordered_map<int64_t, DeclOrVector> ValueToVectorMap; - // Use int64_t as a key to avoid needing special handling for DenseMap keys. + // Use int64_t as a key to avoid needing special handling for map keys. auto EnumConstantToKey = [](const EnumConstantDecl *D) { llvm::APSInt Val = D->getInitVal(); return Val.isSigned() ? Val.getSExtValue() : Val.getZExtValue(); @@ -17787,7 +18183,13 @@ Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); } -Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { +Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD, + bool Final) { + // SYCL functions can be template, so we check if they have appropriate + // attribute prior to checking if it is a template. + if (LangOpts.SYCLIsDevice && FD->hasAttr<SYCLKernelAttr>()) + return FunctionEmissionStatus::Emitted; + // Templates are emitted when they're instantiated. if (FD->isDependentContext()) return FunctionEmissionStatus::TemplateDiscarded; @@ -17799,8 +18201,10 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { if (DevTy.hasValue()) { if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host) OMPES = FunctionEmissionStatus::OMPDiscarded; - else if (DeviceKnownEmittedFns.count(FD) > 0) + else if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost || + *DevTy == OMPDeclareTargetDeclAttr::DT_Any) { OMPES = FunctionEmissionStatus::Emitted; + } } } else if (LangOpts.OpenMP) { // In OpenMP 4.5 all the functions are host functions. @@ -17816,10 +18220,11 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { if (DevTy.hasValue()) { if (*DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { OMPES = FunctionEmissionStatus::OMPDiscarded; - } else if (DeviceKnownEmittedFns.count(FD) > 0) { + } else if (*DevTy == OMPDeclareTargetDeclAttr::DT_Host || + *DevTy == OMPDeclareTargetDeclAttr::DT_Any) OMPES = FunctionEmissionStatus::Emitted; - } - } + } else if (Final) + OMPES = FunctionEmissionStatus::Emitted; } } if (OMPES == FunctionEmissionStatus::OMPDiscarded || @@ -17854,9 +18259,7 @@ Sema::FunctionEmissionStatus Sema::getEmissionStatus(FunctionDecl *FD) { // Otherwise, the function is known-emitted if it's in our set of // known-emitted functions. - return (DeviceKnownEmittedFns.count(FD) > 0) - ? FunctionEmissionStatus::Emitted - : FunctionEmissionStatus::Unknown; + return FunctionEmissionStatus::Unknown; } bool Sema::shouldIgnoreInHostDeviceCheck(FunctionDecl *Callee) { diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 5c51b0f9b8cb..1a0594512a60 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -225,8 +225,7 @@ static bool checkAttributeAtMostNumArgs(Sema &S, const ParsedAttr &AL, /// A helper function to provide Attribute Location for the Attr types /// AND the ParsedAttr. template <typename AttrInfo> -static typename std::enable_if<std::is_base_of<Attr, AttrInfo>::value, - SourceLocation>::type +static std::enable_if_t<std::is_base_of<Attr, AttrInfo>::value, SourceLocation> getAttrLoc(const AttrInfo &AL) { return AL.getLocation(); } @@ -1100,7 +1099,7 @@ static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) { AddBuiltinName(BuiltinName); else S.Diag(LiteralLoc, diag::warn_attribute_no_builtin_invalid_builtin_name) - << BuiltinName << AL.getAttrName()->getName(); + << BuiltinName << AL; } // Repeating the same attribute is fine. @@ -1111,7 +1110,7 @@ static void handleNoBuiltinAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (HasWildcard && Names.size() > 1) S.Diag(D->getLocation(), diag::err_attribute_no_builtin_wildcard_or_builtin_name) - << AL.getAttrName()->getName(); + << AL; if (D->hasAttr<NoBuiltinAttr>()) D->dropAttr<NoBuiltinAttr>(); @@ -1177,8 +1176,7 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, if (const CXXRecordDecl *RD = ThisType->getAsCXXRecordDecl()) { if (!RD->hasAttr<ConsumableAttr>()) { - S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << - RD->getNameAsString(); + S.Diag(AL.getLoc(), diag::warn_attr_on_unconsumable_class) << RD; return false; } @@ -1625,6 +1623,10 @@ void Sema::AddAssumeAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, << E->getSourceRange(); return; } + + if (I > Sema::MaximumAlignment) + Diag(CI.getLoc(), diag::warn_assume_aligned_too_great) + << CI.getRange() << Sema::MaximumAlignment; } if (OE) { @@ -1663,7 +1665,8 @@ void Sema::AddAllocAlignAttr(Decl *D, const AttributeCommonInfo &CI, return; QualType Ty = getFunctionOrMethodParamType(D, Idx.getASTIndex()); - if (!Ty->isDependentType() && !Ty->isIntegralType(Context)) { + if (!Ty->isDependentType() && !Ty->isIntegralType(Context) && + !Ty->isAlignValT()) { Diag(ParamExpr->getBeginLoc(), diag::err_attribute_integers_only) << &TmpAttr << FuncDecl->getParamDecl(Idx.getASTIndex())->getSourceRange(); @@ -1989,6 +1992,21 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) { D->addAttr(CA); } +static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + if (S.LangOpts.CPlusPlus && !D->getDeclContext()->isExternCContext()) { + S.Diag(AL.getLoc(), diag::err_attribute_not_clinkage) << AL; + return; + } + + const auto *FD = cast<FunctionDecl>(D); + if (!FD->isExternallyVisible()) { + S.Diag(AL.getLoc(), diag::warn_attribute_cmse_entry_static); + return; + } + + D->addAttr(::new (S.Context) CmseNSEntryAttr(S.Context, AL)); +} + static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL)) return; @@ -2809,6 +2827,12 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { StringRef Str; if ((AL.isCXX11Attribute() || AL.isC2xAttribute()) && !AL.getScopeName()) { + // The standard attribute cannot be applied to variable declarations such + // as a function pointer. + if (isa<VarDecl>(D)) + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) + << AL << "functions, classes, or enumerations"; + // If this is spelled as the standard C++17 attribute, but not in C++17, // warn about using it as an extension. If there are attribute arguments, // then claim it's a C++2a extension instead. @@ -2816,8 +2840,8 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { // extension warning for C2x mode. const LangOptions &LO = S.getLangOpts(); if (AL.getNumArgs() == 1) { - if (LO.CPlusPlus && !LO.CPlusPlus2a) - S.Diag(AL.getLoc(), diag::ext_cxx2a_attr) << AL; + if (LO.CPlusPlus && !LO.CPlusPlus20) + S.Diag(AL.getLoc(), diag::ext_cxx20_attr) << AL; // Since this this is spelled [[nodiscard]], get the optional string // literal. If in C++ mode, but not in C++2a mode, diagnose as an @@ -3672,7 +3696,7 @@ void Sema::AddAlignValueAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E) { if (!T->isDependentType() && !T->isAnyPointerType() && !T->isReferenceType() && !T->isMemberPointerType()) { Diag(AttrLoc, diag::warn_attribute_pointer_or_reference_only) - << &TmpAttr /*TmpAttr.getName()*/ << T << D->getSourceRange(); + << &TmpAttr << T << D->getSourceRange(); return; } @@ -3809,13 +3833,12 @@ void Sema::AddAlignedAttr(Decl *D, const AttributeCommonInfo &CI, Expr *E, } } - // Alignment calculations can wrap around if it's greater than 2**28. - unsigned MaxValidAlignment = - Context.getTargetInfo().getTriple().isOSBinFormatCOFF() ? 8192 - : 268435456; - if (AlignVal > MaxValidAlignment) { - Diag(AttrLoc, diag::err_attribute_aligned_too_great) << MaxValidAlignment - << E->getSourceRange(); + unsigned MaximumAlignment = Sema::MaximumAlignment; + if (Context.getTargetInfo().getTriple().isOSBinFormatCOFF()) + MaximumAlignment = std::min(MaximumAlignment, 8192u); + if (AlignVal > MaximumAlignment) { + Diag(AttrLoc, diag::err_attribute_aligned_too_great) + << MaximumAlignment << E->getSourceRange(); return; } @@ -3865,6 +3888,7 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { // not specify an alignment that is less strict than the alignment that // would otherwise be required for the entity being declared. AlignedAttr *AlignasAttr = nullptr; + AlignedAttr *LastAlignedAttr = nullptr; unsigned Align = 0; for (auto *I : D->specific_attrs<AlignedAttr>()) { if (I->isAlignmentDependent()) @@ -3872,9 +3896,13 @@ void Sema::CheckAlignasUnderalignment(Decl *D) { if (I->isAlignas()) AlignasAttr = I; Align = std::max(Align, I->getAlignment(Context)); + LastAlignedAttr = I; } - if (AlignasAttr && Align) { + if (Align && DiagTy->isSizelessType()) { + Diag(LastAlignedAttr->getLocation(), diag::err_attribute_sizeless_type) + << LastAlignedAttr << DiagTy; + } else if (AlignasAttr && Align) { CharUnits RequestedAlign = Context.toCharUnitsFromBits(Align); CharUnits NaturalAlign = Context.getTypeAlignInChars(UnderlyingTy); if (NaturalAlign > RequestedAlign) @@ -3907,15 +3935,15 @@ bool Sema::checkMSInheritanceAttrOnDefinition( Diag(Range.getBegin(), diag::err_mismatched_ms_inheritance) << 0 /*definition*/; - Diag(RD->getDefinition()->getLocation(), diag::note_defined_here) - << RD->getNameAsString(); + Diag(RD->getDefinition()->getLocation(), diag::note_defined_here) << RD; return true; } /// parseModeAttrArg - Parses attribute mode string and returns parsed type /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, - bool &IntegerMode, bool &ComplexMode) { + bool &IntegerMode, bool &ComplexMode, + bool &ExplicitIEEE) { IntegerMode = true; ComplexMode = false; switch (Str.size()) { @@ -3936,7 +3964,12 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, case 'X': DestWidth = 96; break; + case 'K': // KFmode - IEEE quad precision (__float128) + ExplicitIEEE = true; + DestWidth = Str[1] == 'I' ? 0 : 128; + break; case 'T': + ExplicitIEEE = false; DestWidth = 128; break; } @@ -3997,6 +4030,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, unsigned DestWidth = 0; bool IntegerMode = true; bool ComplexMode = false; + bool ExplicitIEEE = false; llvm::APInt VectorSize(64, 0); if (Str.size() >= 4 && Str[0] == 'V') { // Minimal length of vector mode is 4: 'V' + NUMBER(>=1) + TYPE(>=2). @@ -4009,7 +4043,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, - IntegerMode, ComplexMode); + IntegerMode, ComplexMode, ExplicitIEEE); // Avoid duplicate warning from template instantiation. if (!InInstantiation) Diag(AttrLoc, diag::warn_vector_mode_deprecated); @@ -4019,7 +4053,8 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, } if (!VectorSize) - parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode); + parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode, + ExplicitIEEE); // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t // and friends, at least with glibc. @@ -4061,8 +4096,9 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << CI.getRange(); return; } - bool IntegralOrAnyEnumType = - OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>(); + bool IntegralOrAnyEnumType = (OldElemTy->isIntegralOrEnumerationType() && + !OldElemTy->isExtIntType()) || + OldElemTy->getAs<EnumType>(); if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() && !IntegralOrAnyEnumType) @@ -4084,7 +4120,7 @@ void Sema::AddModeAttr(Decl *D, const AttributeCommonInfo &CI, NewElemTy = Context.getIntTypeForBitwidth(DestWidth, OldElemTy->isSignedIntegerType()); else - NewElemTy = Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth, ExplicitIEEE); if (NewElemTy.isNull()) { Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; @@ -4333,6 +4369,12 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(FD->getBeginLoc(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) CUDAGlobalAttr(S.Context, AL)); + // In host compilation the kernel is emitted as a stub function, which is + // a helper function for launching the kernel. The instructions in the helper + // function has nothing to do with the source code of the kernel. Do not emit + // debug info for the stub function to avoid confusing the debugger. + if (S.LangOpts.HIP && !S.LangOpts.CUDAIsDevice) + D->addAttr(NoDebugAttr::CreateImplicit(S.Context)); } static void handleGNUInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -4924,9 +4966,9 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, Expr *Arg = AL.getArgAsExpr(1); if (!checkUInt32Argument(S, AL, Arg, Offset, 1, true)) return; - if (Offset) { + if (Count < Offset) { S.Diag(getAttrLoc(AL), diag::err_attribute_argument_out_of_range) - << &AL << 0 << 0 << Arg->getBeginLoc(); + << &AL << 0 << Count << Arg->getBeginLoc(); return; } } @@ -4934,17 +4976,58 @@ static void handlePatchableFunctionEntryAttr(Sema &S, Decl *D, PatchableFunctionEntryAttr(S.Context, AL, Count, Offset)); } -static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { +namespace { +struct IntrinToName { + uint32_t Id; + int32_t FullName; + int32_t ShortName; +}; +} // unnamed namespace + +static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName, + ArrayRef<IntrinToName> Map, + const char *IntrinNames) { if (AliasName.startswith("__arm_")) AliasName = AliasName.substr(6); - switch (BuiltinID) { + const IntrinToName *It = std::lower_bound( + Map.begin(), Map.end(), BuiltinID, + [](const IntrinToName &L, unsigned Id) { return L.Id < Id; }); + if (It == Map.end() || It->Id != BuiltinID) + return false; + StringRef FullName(&IntrinNames[It->FullName]); + if (AliasName == FullName) + return true; + if (It->ShortName == -1) + return false; + StringRef ShortName(&IntrinNames[It->ShortName]); + return AliasName == ShortName; +} + +static bool ArmMveAliasValid(unsigned BuiltinID, StringRef AliasName) { #include "clang/Basic/arm_mve_builtin_aliases.inc" + // The included file defines: + // - ArrayRef<IntrinToName> Map + // - const char IntrinNames[] + return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); +} + +static bool ArmCdeAliasValid(unsigned BuiltinID, StringRef AliasName) { +#include "clang/Basic/arm_cde_builtin_aliases.inc" + return ArmBuiltinAliasValid(BuiltinID, AliasName, Map, IntrinNames); +} + +static bool ArmSveAliasValid(unsigned BuiltinID, StringRef AliasName) { + switch (BuiltinID) { default: return false; +#define GET_SVE_BUILTINS +#define BUILTIN(name, types, attr) case SVE::BI##name: +#include "clang/Basic/arm_sve_builtins.inc" + return true; } } -static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleArmBuiltinAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!AL.isArgIdent(0)) { S.Diag(AL.getLoc(), diag::err_attribute_argument_n_type) << AL << 1 << AANT_ArgumentIdentifier; @@ -4953,14 +5036,17 @@ static void handleArmMveAliasAttr(Sema &S, Decl *D, const ParsedAttr &AL) { IdentifierInfo *Ident = AL.getArgAsIdent(0)->Ident; unsigned BuiltinID = Ident->getBuiltinID(); + StringRef AliasName = cast<FunctionDecl>(D)->getIdentifier()->getName(); - if (!ArmMveAliasValid(BuiltinID, - cast<FunctionDecl>(D)->getIdentifier()->getName())) { - S.Diag(AL.getLoc(), diag::err_attribute_arm_mve_alias); + bool IsAArch64 = S.Context.getTargetInfo().getTriple().isAArch64(); + if ((IsAArch64 && !ArmSveAliasValid(BuiltinID, AliasName)) || + (!IsAArch64 && !ArmMveAliasValid(BuiltinID, AliasName) && + !ArmCdeAliasValid(BuiltinID, AliasName))) { + S.Diag(AL.getLoc(), diag::err_attribute_arm_builtin_alias); return; } - D->addAttr(::new (S.Context) ArmMveAliasAttr(S.Context, AL, Ident)); + D->addAttr(::new (S.Context) ArmBuiltinAliasAttr(S.Context, AL, Ident)); } //===----------------------------------------------------------------------===// @@ -5407,9 +5493,9 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, //===----------------------------------------------------------------------===// UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, - StringRef Uuid) { + StringRef UuidAsWritten, MSGuidDecl *GuidDecl) { if (const auto *UA = D->getAttr<UuidAttr>()) { - if (UA->getGuid().equals_lower(Uuid)) + if (declaresSameEntity(UA->getGuidDecl(), GuidDecl)) return nullptr; if (!UA->getGuid().empty()) { Diag(UA->getLocation(), diag::err_mismatched_uuid); @@ -5418,7 +5504,7 @@ UuidAttr *Sema::mergeUuidAttr(Decl *D, const AttributeCommonInfo &CI, } } - return ::new (Context) UuidAttr(Context, CI, Uuid); + return ::new (Context) UuidAttr(Context, CI, UuidAsWritten, GuidDecl); } static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { @@ -5428,13 +5514,14 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { return; } - StringRef StrRef; + StringRef OrigStrRef; SourceLocation LiteralLoc; - if (!S.checkStringLiteralArgumentAttr(AL, 0, StrRef, &LiteralLoc)) + if (!S.checkStringLiteralArgumentAttr(AL, 0, OrigStrRef, &LiteralLoc)) return; // GUID format is "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX" or // "{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}", normalize to the former. + StringRef StrRef = OrigStrRef; if (StrRef.size() == 38 && StrRef.front() == '{' && StrRef.back() == '}') StrRef = StrRef.drop_front().drop_back(); @@ -5456,6 +5543,16 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } + // Convert to our parsed format and canonicalize. + MSGuidDecl::Parts Parsed; + StrRef.substr(0, 8).getAsInteger(16, Parsed.Part1); + StrRef.substr(9, 4).getAsInteger(16, Parsed.Part2); + StrRef.substr(14, 4).getAsInteger(16, Parsed.Part3); + for (unsigned i = 0; i != 8; ++i) + StrRef.substr(19 + 2 * i + (i >= 2 ? 1 : 0), 2) + .getAsInteger(16, Parsed.Part4And5[i]); + MSGuidDecl *Guid = S.Context.getMSGuidDecl(Parsed); + // FIXME: It'd be nice to also emit a fixit removing uuid(...) (and, if it's // the only thing in the [] list, the [] too), and add an insertion of // __declspec(uuid(...)). But sadly, neither the SourceLocs of the commas @@ -5465,7 +5562,7 @@ static void handleUuidAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isMicrosoftAttribute()) // Check for [uuid(...)] spelling. S.Diag(AL.getLoc(), diag::warn_atl_uuid_deprecated); - UuidAttr *UA = S.mergeUuidAttr(D, AL, StrRef); + UuidAttr *UA = S.mergeUuidAttr(D, AL, OrigStrRef, Guid); if (UA) D->addAttr(UA); } @@ -5795,45 +5892,75 @@ static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr & D->addAttr(UsedAttr::CreateImplicit(S.Context)); } -static void handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'import_module'" << ExpectedFunction; - return; +WebAssemblyImportModuleAttr * +Sema::mergeImportModuleAttr(Decl *D, const WebAssemblyImportModuleAttr &AL) { + auto *FD = cast<FunctionDecl>(D); + + if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportModuleAttr>()) { + if (ExistingAttr->getImportModule() == AL.getImportModule()) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 0 + << ExistingAttr->getImportModule() << AL.getImportModule(); + Diag(AL.getLoc(), diag::note_previous_attribute); + return nullptr; } + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; + return nullptr; + } + return ::new (Context) WebAssemblyImportModuleAttr(Context, AL, + AL.getImportModule()); +} +WebAssemblyImportNameAttr * +Sema::mergeImportNameAttr(Decl *D, const WebAssemblyImportNameAttr &AL) { auto *FD = cast<FunctionDecl>(D); - if (FD->isThisDeclarationADefinition()) { - S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; - return; + + if (const auto *ExistingAttr = FD->getAttr<WebAssemblyImportNameAttr>()) { + if (ExistingAttr->getImportName() == AL.getImportName()) + return nullptr; + Diag(ExistingAttr->getLocation(), diag::warn_mismatched_import) << 1 + << ExistingAttr->getImportName() << AL.getImportName(); + Diag(AL.getLoc(), diag::note_previous_attribute); + return nullptr; + } + if (FD->hasBody()) { + Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; + return nullptr; } + return ::new (Context) WebAssemblyImportNameAttr(Context, AL, + AL.getImportName()); +} + +static void +handleWebAssemblyImportModuleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { + auto *FD = cast<FunctionDecl>(D); StringRef Str; SourceLocation ArgLoc; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; + if (FD->hasBody()) { + S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 0; + return; + } FD->addAttr(::new (S.Context) WebAssemblyImportModuleAttr(S.Context, AL, Str)); } -static void handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (!isFunctionOrMethod(D)) { - S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'import_name'" << ExpectedFunction; - return; - } - +static void +handleWebAssemblyImportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { auto *FD = cast<FunctionDecl>(D); - if (FD->isThisDeclarationADefinition()) { - S.Diag(D->getLocation(), diag::err_alias_is_definition) << FD << 0; - return; - } StringRef Str; SourceLocation ArgLoc; if (!S.checkStringLiteralArgumentAttr(AL, 0, Str, &ArgLoc)) return; + if (FD->hasBody()) { + S.Diag(AL.getLoc(), diag::warn_import_on_definition) << 1; + return; + } FD->addAttr(::new (S.Context) WebAssemblyImportNameAttr(S.Context, AL, Str)); } @@ -6199,11 +6326,6 @@ static void handleCapabilityAttr(Sema &S, Decl *D, const ParsedAttr &AL) { !S.checkStringLiteralArgumentAttr(AL, 0, N, &LiteralLoc)) return; - // Currently, there are only two names allowed for a capability: role and - // mutex (case insensitive). Diagnose other capability names. - if (!N.equals_lower("mutex") && !N.equals_lower("role")) - S.Diag(LiteralLoc, diag::warn_invalid_capability_name) << N; - D->addAttr(::new (S.Context) CapabilityAttr(S.Context, AL, N)); } @@ -6567,7 +6689,9 @@ static void handleObjCExternallyRetainedAttr(Sema &S, Decl *D, // If D is a function-like declaration (method, block, or function), then we // make every parameter psuedo-strong. - for (unsigned I = 0, E = getFunctionOrMethodNumParams(D); I != E; ++I) { + unsigned NumParams = + hasFunctionProto(D) ? getFunctionOrMethodNumParams(D) : 0; + for (unsigned I = 0; I != NumParams; ++I) { auto *PVD = const_cast<ParmVarDecl *>(getFunctionOrMethodParam(D, I)); QualType Ty = PVD->getType(); @@ -6620,7 +6744,7 @@ static void handleMSAllocatorAttr(Sema &S, Decl *D, const ParsedAttr &AL) { handleSimpleAttribute<MSAllocatorAttr>(S, D, AL); } -static void handeAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleAcquireHandleAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (AL.isUsedAsTypeAttr()) return; // Warn if the parameter is definitely not an output parameter. @@ -6700,6 +6824,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, switch (AL.getKind()) { default: + if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled) + break; if (!AL.isStmtAttr()) { // Type attributes are handled elsewhere; silently move on. assert(AL.isTypeAttr() && "Non-type attribute not handled"); @@ -6722,15 +6848,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr, MipsInterruptAttr>(S, D, AL); break; - case ParsedAttr::AT_NoMips16: - handleSimpleAttribute<NoMips16Attr>(S, D, AL); - break; case ParsedAttr::AT_MicroMips: handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL); break; - case ParsedAttr::AT_NoMicroMips: - handleSimpleAttribute<NoMicroMipsAttr>(S, D, AL); - break; case ParsedAttr::AT_MipsLongCall: handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>( S, D, AL); @@ -6766,9 +6886,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_WebAssemblyImportName: handleWebAssemblyImportNameAttr(S, D, AL); break; - case ParsedAttr::AT_IBAction: - handleSimpleAttribute<IBActionAttr>(S, D, AL); - break; case ParsedAttr::AT_IBOutlet: handleIBOutlet(S, D, AL); break; @@ -6793,9 +6910,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AlwaysInline: handleAlwaysInlineAttr(S, D, AL); break; - case ParsedAttr::AT_Artificial: - handleSimpleAttribute<ArtificialAttr>(S, D, AL); - break; case ParsedAttr::AT_AnalyzerNoReturn: handleAnalyzerNoReturnAttr(S, D, AL); break; @@ -6825,16 +6939,20 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handlePassObjectSizeAttr(S, D, AL); break; case ParsedAttr::AT_Constructor: - handleConstructorAttr(S, D, AL); - break; - case ParsedAttr::AT_CXX11NoReturn: - handleSimpleAttribute<CXX11NoReturnAttr>(S, D, AL); + if (S.Context.getTargetInfo().getTriple().isOSAIX()) + llvm::report_fatal_error( + "'constructor' attribute is not yet supported on AIX"); + else + handleConstructorAttr(S, D, AL); break; case ParsedAttr::AT_Deprecated: handleDeprecatedAttr(S, D, AL); break; case ParsedAttr::AT_Destructor: - handleDestructorAttr(S, D, AL); + if (S.Context.getTargetInfo().getTriple().isOSAIX()) + llvm::report_fatal_error("'destructor' attribute is not yet supported on AIX"); + else + handleDestructorAttr(S, D, AL); break; case ParsedAttr::AT_EnableIf: handleEnableIfAttr(S, D, AL); @@ -6857,15 +6975,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_OptimizeNone: handleOptimizeNoneAttr(S, D, AL); break; - case ParsedAttr::AT_FlagEnum: - handleSimpleAttribute<FlagEnumAttr>(S, D, AL); - break; case ParsedAttr::AT_EnumExtensibility: handleEnumExtensibilityAttr(S, D, AL); break; - case ParsedAttr::AT_Flatten: - handleSimpleAttribute<FlattenAttr>(S, D, AL); - break; case ParsedAttr::AT_SYCLKernel: handleSYCLKernelAttr(S, D, AL); break; @@ -6888,9 +7000,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_CUDAHost: handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL); break; - case ParsedAttr::AT_HIPPinnedShadow: - handleSimpleAttributeWithExclusions<HIPPinnedShadowAttr, CUDADeviceAttr, - CUDAConstantAttr>(S, D, AL); + case ParsedAttr::AT_CUDADeviceBuiltinSurfaceType: + handleSimpleAttributeWithExclusions<CUDADeviceBuiltinSurfaceTypeAttr, + CUDADeviceBuiltinTextureTypeAttr>(S, D, + AL); + break; + case ParsedAttr::AT_CUDADeviceBuiltinTextureType: + handleSimpleAttributeWithExclusions<CUDADeviceBuiltinTextureTypeAttr, + CUDADeviceBuiltinSurfaceTypeAttr>(S, D, + AL); break; case ParsedAttr::AT_GNUInline: handleGNUInlineAttr(S, D, AL); @@ -6901,27 +7019,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Restrict: handleRestrictAttr(S, D, AL); break; - case ParsedAttr::AT_LifetimeBound: - handleSimpleAttribute<LifetimeBoundAttr>(S, D, AL); - break; - case ParsedAttr::AT_MayAlias: - handleSimpleAttribute<MayAliasAttr>(S, D, AL); - break; case ParsedAttr::AT_Mode: handleModeAttr(S, D, AL); break; - case ParsedAttr::AT_NoAlias: - handleSimpleAttribute<NoAliasAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoCommon: - handleSimpleAttribute<NoCommonAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoSplitStack: - handleSimpleAttribute<NoSplitStackAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoUniqueAddress: - handleSimpleAttribute<NoUniqueAddressAttr>(S, D, AL); - break; case ParsedAttr::AT_NonNull: if (auto *PVD = dyn_cast<ParmVarDecl>(D)) handleNonNullAttrParameter(S, PVD, AL); @@ -6940,9 +7040,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AllocAlign: handleAllocAlignAttr(S, D, AL); break; - case ParsedAttr::AT_Overloadable: - handleSimpleAttribute<OverloadableAttr>(S, D, AL); - break; case ParsedAttr::AT_Ownership: handleOwnershipAttr(S, D, AL); break; @@ -6998,9 +7095,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_ObjCRuntimeName: handleObjCRuntimeName(S, D, AL); break; - case ParsedAttr::AT_ObjCRuntimeVisible: - handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, AL); - break; case ParsedAttr::AT_ObjCBoxable: handleObjCBoxable(S, D, AL); break; @@ -7018,12 +7112,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, S.AddXConsumedAttr(D, AL, parsedAttrToRetainOwnershipKind(AL), /*IsTemplateInstantiation=*/false); break; - case ParsedAttr::AT_NSConsumesSelf: - handleSimpleAttribute<NSConsumesSelfAttr>(S, D, AL); - break; - case ParsedAttr::AT_OSConsumesThis: - handleSimpleAttribute<OSConsumesThisAttr>(S, D, AL); - break; case ParsedAttr::AT_OSReturnsRetainedOnZero: handleSimpleAttributeOrDiagnose<OSReturnsRetainedOnZeroAttr>( S, D, AL, isValidOSObjectOutParameter(D), @@ -7057,11 +7145,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_VecTypeHint: handleVecTypeHint(S, D, AL); break; - case ParsedAttr::AT_ConstInit: - handleSimpleAttribute<ConstInitAttr>(S, D, AL); - break; case ParsedAttr::AT_InitPriority: - handleInitPriorityAttr(S, D, AL); + if (S.Context.getTargetInfo().getTriple().isOSAIX()) + llvm::report_fatal_error( + "'init_priority' attribute is not yet supported on AIX"); + else + handleInitPriorityAttr(S, D, AL); break; case ParsedAttr::AT_Packed: handlePackedAttr(S, D, AL); @@ -7090,12 +7179,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Unavailable: handleAttrWithMessage<UnavailableAttr>(S, D, AL); break; - case ParsedAttr::AT_ArcWeakrefUnavailable: - handleSimpleAttribute<ArcWeakrefUnavailableAttr>(S, D, AL); - break; - case ParsedAttr::AT_ObjCRootClass: - handleSimpleAttribute<ObjCRootClassAttr>(S, D, AL); - break; case ParsedAttr::AT_ObjCDirect: handleObjCDirectAttr(S, D, AL); break; @@ -7103,27 +7186,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleObjCDirectMembersAttr(S, D, AL); handleSimpleAttribute<ObjCDirectMembersAttr>(S, D, AL); break; - case ParsedAttr::AT_ObjCNonLazyClass: - handleSimpleAttribute<ObjCNonLazyClassAttr>(S, D, AL); - break; - case ParsedAttr::AT_ObjCSubclassingRestricted: - handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, AL); - break; - case ParsedAttr::AT_ObjCClassStub: - handleSimpleAttribute<ObjCClassStubAttr>(S, D, AL); - break; case ParsedAttr::AT_ObjCExplicitProtocolImpl: handleObjCSuppresProtocolAttr(S, D, AL); break; - case ParsedAttr::AT_ObjCRequiresPropertyDefs: - handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, AL); - break; case ParsedAttr::AT_Unused: handleUnusedAttr(S, D, AL); break; - case ParsedAttr::AT_ReturnsTwice: - handleSimpleAttribute<ReturnsTwiceAttr>(S, D, AL); - break; case ParsedAttr::AT_NotTailCalled: handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>( S, D, AL); @@ -7132,24 +7200,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D, AL); break; - case ParsedAttr::AT_Used: - handleSimpleAttribute<UsedAttr>(S, D, AL); - break; case ParsedAttr::AT_Visibility: handleVisibilityAttr(S, D, AL, false); break; case ParsedAttr::AT_TypeVisibility: handleVisibilityAttr(S, D, AL, true); break; - case ParsedAttr::AT_WarnUnused: - handleSimpleAttribute<WarnUnusedAttr>(S, D, AL); - break; case ParsedAttr::AT_WarnUnusedResult: handleWarnUnusedResult(S, D, AL); break; - case ParsedAttr::AT_Weak: - handleSimpleAttribute<WeakAttr>(S, D, AL); - break; case ParsedAttr::AT_WeakRef: handleWeakRefAttr(S, D, AL); break; @@ -7159,9 +7218,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_TransparentUnion: handleTransparentUnionAttr(S, D, AL); break; - case ParsedAttr::AT_ObjCException: - handleSimpleAttribute<ObjCExceptionAttr>(S, D, AL); - break; case ParsedAttr::AT_ObjCMethodFamily: handleObjCMethodFamilyAttr(S, D, AL); break; @@ -7177,36 +7233,14 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Sentinel: handleSentinelAttr(S, D, AL); break; - case ParsedAttr::AT_Const: - handleSimpleAttribute<ConstAttr>(S, D, AL); - break; - case ParsedAttr::AT_Pure: - handleSimpleAttribute<PureAttr>(S, D, AL); - break; case ParsedAttr::AT_Cleanup: handleCleanupAttr(S, D, AL); break; case ParsedAttr::AT_NoDebug: handleNoDebugAttr(S, D, AL); break; - case ParsedAttr::AT_NoDuplicate: - handleSimpleAttribute<NoDuplicateAttr>(S, D, AL); - break; - case ParsedAttr::AT_Convergent: - handleSimpleAttribute<ConvergentAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoInline: - handleSimpleAttribute<NoInlineAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoInstrumentFunction: // Interacts with -pg. - handleSimpleAttribute<NoInstrumentFunctionAttr>(S, D, AL); - break; - case ParsedAttr::AT_NoStackProtector: - // Interacts with -fstack-protector options. - handleSimpleAttribute<NoStackProtectorAttr>(S, D, AL); - break; - case ParsedAttr::AT_CFICanonicalJumpTable: - handleSimpleAttribute<CFICanonicalJumpTableAttr>(S, D, AL); + case ParsedAttr::AT_CmseNSEntry: + handleCmseNSEntryAttr(S, D, AL); break; case ParsedAttr::AT_StdCall: case ParsedAttr::AT_CDecl: @@ -7232,9 +7266,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Pointer: handleLifetimeCategoryAttr(S, D, AL); break; - case ParsedAttr::AT_OpenCLKernel: - handleSimpleAttribute<OpenCLKernelAttr>(S, D, AL); - break; case ParsedAttr::AT_OpenCLAccess: handleOpenCLAccessAttr(S, D, AL); break; @@ -7253,38 +7284,17 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_InternalLinkage: handleInternalLinkageAttr(S, D, AL); break; - case ParsedAttr::AT_ExcludeFromExplicitInstantiation: - handleSimpleAttribute<ExcludeFromExplicitInstantiationAttr>(S, D, AL); - break; - case ParsedAttr::AT_LTOVisibilityPublic: - handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, AL); - break; // Microsoft attributes: - case ParsedAttr::AT_EmptyBases: - handleSimpleAttribute<EmptyBasesAttr>(S, D, AL); - break; case ParsedAttr::AT_LayoutVersion: handleLayoutVersion(S, D, AL); break; - case ParsedAttr::AT_TrivialABI: - handleSimpleAttribute<TrivialABIAttr>(S, D, AL); - break; - case ParsedAttr::AT_MSNoVTable: - handleSimpleAttribute<MSNoVTableAttr>(S, D, AL); - break; - case ParsedAttr::AT_MSStruct: - handleSimpleAttribute<MSStructAttr>(S, D, AL); - break; case ParsedAttr::AT_Uuid: handleUuidAttr(S, D, AL); break; case ParsedAttr::AT_MSInheritance: handleMSInheritanceAttr(S, D, AL); break; - case ParsedAttr::AT_SelectAny: - handleSimpleAttribute<SelectAnyAttr>(S, D, AL); - break; case ParsedAttr::AT_Thread: handleDeclspecThreadAttr(S, D, AL); break; @@ -7303,24 +7313,15 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_AssertSharedLock: handleAssertSharedLockAttr(S, D, AL); break; - case ParsedAttr::AT_GuardedVar: - handleSimpleAttribute<GuardedVarAttr>(S, D, AL); - break; case ParsedAttr::AT_PtGuardedVar: handlePtGuardedVarAttr(S, D, AL); break; - case ParsedAttr::AT_ScopedLockable: - handleSimpleAttribute<ScopedLockableAttr>(S, D, AL); - break; case ParsedAttr::AT_NoSanitize: handleNoSanitizeAttr(S, D, AL); break; case ParsedAttr::AT_NoSanitizeSpecific: handleNoSanitizeSpecificAttr(S, D, AL); break; - case ParsedAttr::AT_NoThreadSafetyAnalysis: - handleSimpleAttribute<NoThreadSafetyAnalysisAttr>(S, D, AL); - break; case ParsedAttr::AT_GuardedBy: handleGuardedByAttr(S, D, AL); break; @@ -7372,12 +7373,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_Consumable: handleConsumableAttr(S, D, AL); break; - case ParsedAttr::AT_ConsumableAutoCast: - handleSimpleAttribute<ConsumableAutoCastAttr>(S, D, AL); - break; - case ParsedAttr::AT_ConsumableSetOnRead: - handleSimpleAttribute<ConsumableSetOnReadAttr>(S, D, AL); - break; case ParsedAttr::AT_CallableWhen: handleCallableWhenAttr(S, D, AL); break; @@ -7401,16 +7396,8 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case ParsedAttr::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, AL); break; - case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: - handleSimpleAttribute<AnyX86NoCallerSavedRegistersAttr>(S, D, AL); - break; - case ParsedAttr::AT_RenderScriptKernel: - handleSimpleAttribute<RenderScriptKernelAttr>(S, D, AL); - break; + // XRay attributes. - case ParsedAttr::AT_XRayInstrument: - handleSimpleAttribute<XRayInstrumentAttr>(S, D, AL); - break; case ParsedAttr::AT_XRayLogArgs: handleXRayLogArgsAttr(S, D, AL); break; @@ -7419,11 +7406,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handlePatchableFunctionEntryAttr(S, D, AL); break; - // Move semantics attribute. - case ParsedAttr::AT_Reinitializes: - handleSimpleAttribute<ReinitializesAttr>(S, D, AL); - break; - case ParsedAttr::AT_AlwaysDestroy: case ParsedAttr::AT_NoDestroy: handleDestroyAttr(S, D, AL); @@ -7433,6 +7415,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleUninitializedAttr(S, D, AL); break; + case ParsedAttr::AT_LoaderUninitialized: + handleSimpleAttribute<LoaderUninitializedAttr>(S, D, AL); + break; + case ParsedAttr::AT_ObjCExternallyRetained: handleObjCExternallyRetainedAttr(S, D, AL); break; @@ -7445,12 +7431,12 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleMSAllocatorAttr(S, D, AL); break; - case ParsedAttr::AT_ArmMveAlias: - handleArmMveAliasAttr(S, D, AL); + case ParsedAttr::AT_ArmBuiltinAlias: + handleArmBuiltinAliasAttr(S, D, AL); break; case ParsedAttr::AT_AcquireHandle: - handeAcquireHandleAttr(S, D, AL); + handleAcquireHandleAttr(S, D, AL); break; case ParsedAttr::AT_ReleaseHandle: @@ -7782,534 +7768,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &DD, DD.Triggered = true; } -static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, - const Decl *D) { - // Check each AvailabilityAttr to find the one for this platform. - for (const auto *A : D->attrs()) { - if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { - // FIXME: this is copied from CheckAvailability. We should try to - // de-duplicate. - - // Check if this is an App Extension "platform", and if so chop off - // the suffix for matching with the actual platform. - StringRef ActualPlatform = Avail->getPlatform()->getName(); - StringRef RealizedPlatform = ActualPlatform; - if (Context.getLangOpts().AppExt) { - size_t suffix = RealizedPlatform.rfind("_app_extension"); - if (suffix != StringRef::npos) - RealizedPlatform = RealizedPlatform.slice(0, suffix); - } - - StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); - - // Match the platform name. - if (RealizedPlatform == TargetPlatform) - return Avail; - } - } - return nullptr; -} - -/// The diagnostic we should emit for \c D, and the declaration that -/// originated it, or \c AR_Available. -/// -/// \param D The declaration to check. -/// \param Message If non-null, this will be populated with the message from -/// the availability attribute that is selected. -/// \param ClassReceiver If we're checking the the method of a class message -/// send, the class. Otherwise nullptr. -static std::pair<AvailabilityResult, const NamedDecl *> -ShouldDiagnoseAvailabilityOfDecl(Sema &S, const NamedDecl *D, - std::string *Message, - ObjCInterfaceDecl *ClassReceiver) { - AvailabilityResult Result = D->getAvailability(Message); - - // For typedefs, if the typedef declaration appears available look - // to the underlying type to see if it is more restrictive. - while (const auto *TD = dyn_cast<TypedefNameDecl>(D)) { - if (Result == AR_Available) { - if (const auto *TT = TD->getUnderlyingType()->getAs<TagType>()) { - D = TT->getDecl(); - Result = D->getAvailability(Message); - continue; - } - } - break; - } - - // Forward class declarations get their attributes from their definition. - if (const auto *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { - if (IDecl->getDefinition()) { - D = IDecl->getDefinition(); - Result = D->getAvailability(Message); - } - } - - if (const auto *ECD = dyn_cast<EnumConstantDecl>(D)) - if (Result == AR_Available) { - const DeclContext *DC = ECD->getDeclContext(); - if (const auto *TheEnumDecl = dyn_cast<EnumDecl>(DC)) { - Result = TheEnumDecl->getAvailability(Message); - D = TheEnumDecl; - } - } - - // For +new, infer availability from -init. - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (S.NSAPIObj && ClassReceiver) { - ObjCMethodDecl *Init = ClassReceiver->lookupInstanceMethod( - S.NSAPIObj->getInitSelector()); - if (Init && Result == AR_Available && MD->isClassMethod() && - MD->getSelector() == S.NSAPIObj->getNewSelector() && - MD->definedInNSObject(S.getASTContext())) { - Result = Init->getAvailability(Message); - D = Init; - } - } - } - - return {Result, D}; -} - - -/// whether we should emit a diagnostic for \c K and \c DeclVersion in -/// the context of \c Ctx. For example, we should emit an unavailable diagnostic -/// in a deprecated context, but not the other way around. -static bool -ShouldDiagnoseAvailabilityInContext(Sema &S, AvailabilityResult K, - VersionTuple DeclVersion, Decl *Ctx, - const NamedDecl *OffendingDecl) { - assert(K != AR_Available && "Expected an unavailable declaration here!"); - - // Checks if we should emit the availability diagnostic in the context of C. - auto CheckContext = [&](const Decl *C) { - if (K == AR_NotYetIntroduced) { - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, C)) - if (AA->getIntroduced() >= DeclVersion) - return true; - } else if (K == AR_Deprecated) { - if (C->isDeprecated()) - return true; - } else if (K == AR_Unavailable) { - // It is perfectly fine to refer to an 'unavailable' Objective-C method - // when it is referenced from within the @implementation itself. In this - // context, we interpret unavailable as a form of access control. - if (const auto *MD = dyn_cast<ObjCMethodDecl>(OffendingDecl)) { - if (const auto *Impl = dyn_cast<ObjCImplDecl>(C)) { - if (MD->getClassInterface() == Impl->getClassInterface()) - return true; - } - } - } - - if (C->isUnavailable()) - return true; - return false; - }; - - do { - if (CheckContext(Ctx)) - return false; - - // An implementation implicitly has the availability of the interface. - // Unless it is "+load" method. - if (const auto *MethodD = dyn_cast<ObjCMethodDecl>(Ctx)) - if (MethodD->isClassMethod() && - MethodD->getSelector().getAsString() == "load") - return true; - - if (const auto *CatOrImpl = dyn_cast<ObjCImplDecl>(Ctx)) { - if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) - if (CheckContext(Interface)) - return false; - } - // A category implicitly has the availability of the interface. - else if (const auto *CatD = dyn_cast<ObjCCategoryDecl>(Ctx)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - if (CheckContext(Interface)) - return false; - } while ((Ctx = cast_or_null<Decl>(Ctx->getDeclContext()))); - - return true; -} - -static bool -shouldDiagnoseAvailabilityByDefault(const ASTContext &Context, - const VersionTuple &DeploymentVersion, - const VersionTuple &DeclVersion) { - const auto &Triple = Context.getTargetInfo().getTriple(); - VersionTuple ForceAvailabilityFromVersion; - switch (Triple.getOS()) { - case llvm::Triple::IOS: - case llvm::Triple::TvOS: - ForceAvailabilityFromVersion = VersionTuple(/*Major=*/11); - break; - case llvm::Triple::WatchOS: - ForceAvailabilityFromVersion = VersionTuple(/*Major=*/4); - break; - case llvm::Triple::Darwin: - case llvm::Triple::MacOSX: - ForceAvailabilityFromVersion = VersionTuple(/*Major=*/10, /*Minor=*/13); - break; - default: - // New targets should always warn about availability. - return Triple.getVendor() == llvm::Triple::Apple; - } - return DeploymentVersion >= ForceAvailabilityFromVersion || - DeclVersion >= ForceAvailabilityFromVersion; -} - -static NamedDecl *findEnclosingDeclToAnnotate(Decl *OrigCtx) { - for (Decl *Ctx = OrigCtx; Ctx; - Ctx = cast_or_null<Decl>(Ctx->getDeclContext())) { - if (isa<TagDecl>(Ctx) || isa<FunctionDecl>(Ctx) || isa<ObjCMethodDecl>(Ctx)) - return cast<NamedDecl>(Ctx); - if (auto *CD = dyn_cast<ObjCContainerDecl>(Ctx)) { - if (auto *Imp = dyn_cast<ObjCImplDecl>(Ctx)) - return Imp->getClassInterface(); - return CD; - } - } - - return dyn_cast<NamedDecl>(OrigCtx); -} - -namespace { - -struct AttributeInsertion { - StringRef Prefix; - SourceLocation Loc; - StringRef Suffix; - - static AttributeInsertion createInsertionAfter(const NamedDecl *D) { - return {" ", D->getEndLoc(), ""}; - } - static AttributeInsertion createInsertionAfter(SourceLocation Loc) { - return {" ", Loc, ""}; - } - static AttributeInsertion createInsertionBefore(const NamedDecl *D) { - return {"", D->getBeginLoc(), "\n"}; - } -}; - -} // end anonymous namespace - -/// Tries to parse a string as ObjC method name. -/// -/// \param Name The string to parse. Expected to originate from availability -/// attribute argument. -/// \param SlotNames The vector that will be populated with slot names. In case -/// of unsuccessful parsing can contain invalid data. -/// \returns A number of method parameters if parsing was successful, None -/// otherwise. -static Optional<unsigned> -tryParseObjCMethodName(StringRef Name, SmallVectorImpl<StringRef> &SlotNames, - const LangOptions &LangOpts) { - // Accept replacements starting with - or + as valid ObjC method names. - if (!Name.empty() && (Name.front() == '-' || Name.front() == '+')) - Name = Name.drop_front(1); - if (Name.empty()) - return None; - Name.split(SlotNames, ':'); - unsigned NumParams; - if (Name.back() == ':') { - // Remove an empty string at the end that doesn't represent any slot. - SlotNames.pop_back(); - NumParams = SlotNames.size(); - } else { - if (SlotNames.size() != 1) - // Not a valid method name, just a colon-separated string. - return None; - NumParams = 0; - } - // Verify all slot names are valid. - bool AllowDollar = LangOpts.DollarIdents; - for (StringRef S : SlotNames) { - if (S.empty()) - continue; - if (!isValidIdentifier(S, AllowDollar)) - return None; - } - return NumParams; -} - -/// Returns a source location in which it's appropriate to insert a new -/// attribute for the given declaration \D. -static Optional<AttributeInsertion> -createAttributeInsertion(const NamedDecl *D, const SourceManager &SM, - const LangOptions &LangOpts) { - if (isa<ObjCPropertyDecl>(D)) - return AttributeInsertion::createInsertionAfter(D); - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (MD->hasBody()) - return None; - return AttributeInsertion::createInsertionAfter(D); - } - if (const auto *TD = dyn_cast<TagDecl>(D)) { - SourceLocation Loc = - Lexer::getLocForEndOfToken(TD->getInnerLocStart(), 0, SM, LangOpts); - if (Loc.isInvalid()) - return None; - // Insert after the 'struct'/whatever keyword. - return AttributeInsertion::createInsertionAfter(Loc); - } - return AttributeInsertion::createInsertionBefore(D); -} - -/// Actually emit an availability diagnostic for a reference to an unavailable -/// decl. -/// -/// \param Ctx The context that the reference occurred in -/// \param ReferringDecl The exact declaration that was referenced. -/// \param OffendingDecl A related decl to \c ReferringDecl that has an -/// availability attribute corresponding to \c K attached to it. Note that this -/// may not be the same as ReferringDecl, i.e. if an EnumDecl is annotated and -/// we refer to a member EnumConstantDecl, ReferringDecl is the EnumConstantDecl -/// and OffendingDecl is the EnumDecl. -static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, - Decl *Ctx, const NamedDecl *ReferringDecl, - const NamedDecl *OffendingDecl, - StringRef Message, - ArrayRef<SourceLocation> Locs, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess) { - // Diagnostics for deprecated or unavailable. - unsigned diag, diag_message, diag_fwdclass_message; - unsigned diag_available_here = diag::note_availability_specified_here; - SourceLocation NoteLocation = OffendingDecl->getLocation(); - - // Matches 'diag::note_property_attribute' options. - unsigned property_note_select; - - // Matches diag::note_availability_specified_here. - unsigned available_here_select_kind; - - VersionTuple DeclVersion; - if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, OffendingDecl)) - DeclVersion = AA->getIntroduced(); - - if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx, - OffendingDecl)) - return; - - SourceLocation Loc = Locs.front(); - - // The declaration can have multiple availability attributes, we are looking - // at one of them. - const AvailabilityAttr *A = getAttrForPlatform(S.Context, OffendingDecl); - if (A && A->isInherited()) { - for (const Decl *Redecl = OffendingDecl->getMostRecentDecl(); Redecl; - Redecl = Redecl->getPreviousDecl()) { - const AvailabilityAttr *AForRedecl = - getAttrForPlatform(S.Context, Redecl); - if (AForRedecl && !AForRedecl->isInherited()) { - // If D is a declaration with inherited attributes, the note should - // point to the declaration with actual attributes. - NoteLocation = Redecl->getLocation(); - break; - } - } - } - - switch (K) { - case AR_NotYetIntroduced: { - // We would like to emit the diagnostic even if -Wunguarded-availability is - // not specified for deployment targets >= to iOS 11 or equivalent or - // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or - // later. - const AvailabilityAttr *AA = - getAttrForPlatform(S.getASTContext(), OffendingDecl); - VersionTuple Introduced = AA->getIntroduced(); - - bool UseNewWarning = shouldDiagnoseAvailabilityByDefault( - S.Context, S.Context.getTargetInfo().getPlatformMinVersion(), - Introduced); - unsigned Warning = UseNewWarning ? diag::warn_unguarded_availability_new - : diag::warn_unguarded_availability; - - std::string PlatformName = AvailabilityAttr::getPrettyPlatformName( - S.getASTContext().getTargetInfo().getPlatformName()); - - S.Diag(Loc, Warning) << OffendingDecl << PlatformName - << Introduced.getAsString(); - - S.Diag(OffendingDecl->getLocation(), - diag::note_partial_availability_specified_here) - << OffendingDecl << PlatformName << Introduced.getAsString() - << S.Context.getTargetInfo().getPlatformMinVersion().getAsString(); - - if (const auto *Enclosing = findEnclosingDeclToAnnotate(Ctx)) { - if (const auto *TD = dyn_cast<TagDecl>(Enclosing)) - if (TD->getDeclName().isEmpty()) { - S.Diag(TD->getLocation(), - diag::note_decl_unguarded_availability_silence) - << /*Anonymous*/ 1 << TD->getKindName(); - return; - } - auto FixitNoteDiag = - S.Diag(Enclosing->getLocation(), - diag::note_decl_unguarded_availability_silence) - << /*Named*/ 0 << Enclosing; - // Don't offer a fixit for declarations with availability attributes. - if (Enclosing->hasAttr<AvailabilityAttr>()) - return; - if (!S.getPreprocessor().isMacroDefined("API_AVAILABLE")) - return; - Optional<AttributeInsertion> Insertion = createAttributeInsertion( - Enclosing, S.getSourceManager(), S.getLangOpts()); - if (!Insertion) - return; - std::string PlatformName = - AvailabilityAttr::getPlatformNameSourceSpelling( - S.getASTContext().getTargetInfo().getPlatformName()) - .lower(); - std::string Introduced = - OffendingDecl->getVersionIntroduced().getAsString(); - FixitNoteDiag << FixItHint::CreateInsertion( - Insertion->Loc, - (llvm::Twine(Insertion->Prefix) + "API_AVAILABLE(" + PlatformName + - "(" + Introduced + "))" + Insertion->Suffix) - .str()); - } - return; - } - case AR_Deprecated: - diag = !ObjCPropertyAccess ? diag::warn_deprecated - : diag::warn_property_method_deprecated; - diag_message = diag::warn_deprecated_message; - diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; - property_note_select = /* deprecated */ 0; - available_here_select_kind = /* deprecated */ 2; - if (const auto *AL = OffendingDecl->getAttr<DeprecatedAttr>()) - NoteLocation = AL->getLocation(); - break; - - case AR_Unavailable: - diag = !ObjCPropertyAccess ? diag::err_unavailable - : diag::err_property_method_unavailable; - diag_message = diag::err_unavailable_message; - diag_fwdclass_message = diag::warn_unavailable_fwdclass_message; - property_note_select = /* unavailable */ 1; - available_here_select_kind = /* unavailable */ 0; - - if (auto AL = OffendingDecl->getAttr<UnavailableAttr>()) { - if (AL->isImplicit() && AL->getImplicitReason()) { - // Most of these failures are due to extra restrictions in ARC; - // reflect that in the primary diagnostic when applicable. - auto flagARCError = [&] { - if (S.getLangOpts().ObjCAutoRefCount && - S.getSourceManager().isInSystemHeader( - OffendingDecl->getLocation())) - diag = diag::err_unavailable_in_arc; - }; - - switch (AL->getImplicitReason()) { - case UnavailableAttr::IR_None: break; - - case UnavailableAttr::IR_ARCForbiddenType: - flagARCError(); - diag_available_here = diag::note_arc_forbidden_type; - break; - - case UnavailableAttr::IR_ForbiddenWeak: - if (S.getLangOpts().ObjCWeakRuntime) - diag_available_here = diag::note_arc_weak_disabled; - else - diag_available_here = diag::note_arc_weak_no_runtime; - break; - - case UnavailableAttr::IR_ARCForbiddenConversion: - flagARCError(); - diag_available_here = diag::note_performs_forbidden_arc_conversion; - break; - - case UnavailableAttr::IR_ARCInitReturnsUnrelated: - flagARCError(); - diag_available_here = diag::note_arc_init_returns_unrelated; - break; - - case UnavailableAttr::IR_ARCFieldWithOwnership: - flagARCError(); - diag_available_here = diag::note_arc_field_with_ownership; - break; - } - } - } - break; - - case AR_Available: - llvm_unreachable("Warning for availability of available declaration?"); - } - - SmallVector<FixItHint, 12> FixIts; - if (K == AR_Deprecated) { - StringRef Replacement; - if (auto AL = OffendingDecl->getAttr<DeprecatedAttr>()) - Replacement = AL->getReplacement(); - if (auto AL = getAttrForPlatform(S.Context, OffendingDecl)) - Replacement = AL->getReplacement(); - - CharSourceRange UseRange; - if (!Replacement.empty()) - UseRange = - CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); - if (UseRange.isValid()) { - if (const auto *MethodDecl = dyn_cast<ObjCMethodDecl>(ReferringDecl)) { - Selector Sel = MethodDecl->getSelector(); - SmallVector<StringRef, 12> SelectorSlotNames; - Optional<unsigned> NumParams = tryParseObjCMethodName( - Replacement, SelectorSlotNames, S.getLangOpts()); - if (NumParams && NumParams.getValue() == Sel.getNumArgs()) { - assert(SelectorSlotNames.size() == Locs.size()); - for (unsigned I = 0; I < Locs.size(); ++I) { - if (!Sel.getNameForSlot(I).empty()) { - CharSourceRange NameRange = CharSourceRange::getCharRange( - Locs[I], S.getLocForEndOfToken(Locs[I])); - FixIts.push_back(FixItHint::CreateReplacement( - NameRange, SelectorSlotNames[I])); - } else - FixIts.push_back( - FixItHint::CreateInsertion(Locs[I], SelectorSlotNames[I])); - } - } else - FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); - } else - FixIts.push_back(FixItHint::CreateReplacement(UseRange, Replacement)); - } - } - - if (!Message.empty()) { - S.Diag(Loc, diag_message) << ReferringDecl << Message << FixIts; - if (ObjCProperty) - S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) - << ObjCProperty->getDeclName() << property_note_select; - } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << ReferringDecl << FixIts; - if (ObjCProperty) - S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) - << ObjCProperty->getDeclName() << property_note_select; - } else { - S.Diag(Loc, diag_fwdclass_message) << ReferringDecl << FixIts; - S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); - } - - S.Diag(NoteLocation, diag_available_here) - << OffendingDecl << available_here_select_kind; -} - -static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, - Decl *Ctx) { - assert(DD.Kind == DelayedDiagnostic::Availability && - "Expected an availability diagnostic here"); - - DD.Triggered = true; - DoEmitAvailabilityWarning( - S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityReferringDecl(), - DD.getAvailabilityOffendingDecl(), DD.getAvailabilityMessage(), - DD.getAvailabilitySelectorLocs(), DD.getUnknownObjCClass(), - DD.getObjCProperty(), false); -} void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { assert(DelayedDiagnostics.getCurrentPool()); @@ -8343,7 +7801,7 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { // Don't bother giving deprecation/unavailable diagnostics if // the decl is invalid. if (!decl->isInvalidDecl()) - handleDelayedAvailabilityCheck(*this, diag, decl); + handleDelayedAvailabilityCheck(diag, decl); break; case DelayedDiagnostic::Access: @@ -8373,415 +7831,3 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { assert(curPool && "re-emitting in undelayed context not supported"); curPool->steal(pool); } - -static void EmitAvailabilityWarning(Sema &S, AvailabilityResult AR, - const NamedDecl *ReferringDecl, - const NamedDecl *OffendingDecl, - StringRef Message, - ArrayRef<SourceLocation> Locs, - const ObjCInterfaceDecl *UnknownObjCClass, - const ObjCPropertyDecl *ObjCProperty, - bool ObjCPropertyAccess) { - // Delay if we're currently parsing a declaration. - if (S.DelayedDiagnostics.shouldDelayDiagnostics()) { - S.DelayedDiagnostics.add( - DelayedDiagnostic::makeAvailability( - AR, Locs, ReferringDecl, OffendingDecl, UnknownObjCClass, - ObjCProperty, Message, ObjCPropertyAccess)); - return; - } - - Decl *Ctx = cast<Decl>(S.getCurLexicalContext()); - DoEmitAvailabilityWarning(S, AR, Ctx, ReferringDecl, OffendingDecl, - Message, Locs, UnknownObjCClass, ObjCProperty, - ObjCPropertyAccess); -} - -namespace { - -/// Returns true if the given statement can be a body-like child of \p Parent. -bool isBodyLikeChildStmt(const Stmt *S, const Stmt *Parent) { - switch (Parent->getStmtClass()) { - case Stmt::IfStmtClass: - return cast<IfStmt>(Parent)->getThen() == S || - cast<IfStmt>(Parent)->getElse() == S; - case Stmt::WhileStmtClass: - return cast<WhileStmt>(Parent)->getBody() == S; - case Stmt::DoStmtClass: - return cast<DoStmt>(Parent)->getBody() == S; - case Stmt::ForStmtClass: - return cast<ForStmt>(Parent)->getBody() == S; - case Stmt::CXXForRangeStmtClass: - return cast<CXXForRangeStmt>(Parent)->getBody() == S; - case Stmt::ObjCForCollectionStmtClass: - return cast<ObjCForCollectionStmt>(Parent)->getBody() == S; - case Stmt::CaseStmtClass: - case Stmt::DefaultStmtClass: - return cast<SwitchCase>(Parent)->getSubStmt() == S; - default: - return false; - } -} - -class StmtUSEFinder : public RecursiveASTVisitor<StmtUSEFinder> { - const Stmt *Target; - -public: - bool VisitStmt(Stmt *S) { return S != Target; } - - /// Returns true if the given statement is present in the given declaration. - static bool isContained(const Stmt *Target, const Decl *D) { - StmtUSEFinder Visitor; - Visitor.Target = Target; - return !Visitor.TraverseDecl(const_cast<Decl *>(D)); - } -}; - -/// Traverses the AST and finds the last statement that used a given -/// declaration. -class LastDeclUSEFinder : public RecursiveASTVisitor<LastDeclUSEFinder> { - const Decl *D; - -public: - bool VisitDeclRefExpr(DeclRefExpr *DRE) { - if (DRE->getDecl() == D) - return false; - return true; - } - - static const Stmt *findLastStmtThatUsesDecl(const Decl *D, - const CompoundStmt *Scope) { - LastDeclUSEFinder Visitor; - Visitor.D = D; - for (auto I = Scope->body_rbegin(), E = Scope->body_rend(); I != E; ++I) { - const Stmt *S = *I; - if (!Visitor.TraverseStmt(const_cast<Stmt *>(S))) - return S; - } - return nullptr; - } -}; - -/// This class implements -Wunguarded-availability. -/// -/// This is done with a traversal of the AST of a function that makes reference -/// to a partially available declaration. Whenever we encounter an \c if of the -/// form: \c if(@available(...)), we use the version from the condition to visit -/// the then statement. -class DiagnoseUnguardedAvailability - : public RecursiveASTVisitor<DiagnoseUnguardedAvailability> { - typedef RecursiveASTVisitor<DiagnoseUnguardedAvailability> Base; - - Sema &SemaRef; - Decl *Ctx; - - /// Stack of potentially nested 'if (@available(...))'s. - SmallVector<VersionTuple, 8> AvailabilityStack; - SmallVector<const Stmt *, 16> StmtStack; - - void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range, - ObjCInterfaceDecl *ClassReceiver = nullptr); - -public: - DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) - : SemaRef(SemaRef), Ctx(Ctx) { - AvailabilityStack.push_back( - SemaRef.Context.getTargetInfo().getPlatformMinVersion()); - } - - bool TraverseDecl(Decl *D) { - // Avoid visiting nested functions to prevent duplicate warnings. - if (!D || isa<FunctionDecl>(D)) - return true; - return Base::TraverseDecl(D); - } - - bool TraverseStmt(Stmt *S) { - if (!S) - return true; - StmtStack.push_back(S); - bool Result = Base::TraverseStmt(S); - StmtStack.pop_back(); - return Result; - } - - void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } - - bool TraverseIfStmt(IfStmt *If); - - bool TraverseLambdaExpr(LambdaExpr *E) { return true; } - - // for 'case X:' statements, don't bother looking at the 'X'; it can't lead - // to any useful diagnostics. - bool TraverseCaseStmt(CaseStmt *CS) { return TraverseStmt(CS->getSubStmt()); } - - bool VisitObjCPropertyRefExpr(ObjCPropertyRefExpr *PRE) { - if (PRE->isClassReceiver()) - DiagnoseDeclAvailability(PRE->getClassReceiver(), PRE->getReceiverLocation()); - return true; - } - - bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { - if (ObjCMethodDecl *D = Msg->getMethodDecl()) { - ObjCInterfaceDecl *ID = nullptr; - QualType ReceiverTy = Msg->getClassReceiver(); - if (!ReceiverTy.isNull() && ReceiverTy->getAsObjCInterfaceType()) - ID = ReceiverTy->getAsObjCInterfaceType()->getInterface(); - - DiagnoseDeclAvailability( - D, SourceRange(Msg->getSelectorStartLoc(), Msg->getEndLoc()), ID); - } - return true; - } - - bool VisitDeclRefExpr(DeclRefExpr *DRE) { - DiagnoseDeclAvailability(DRE->getDecl(), - SourceRange(DRE->getBeginLoc(), DRE->getEndLoc())); - return true; - } - - bool VisitMemberExpr(MemberExpr *ME) { - DiagnoseDeclAvailability(ME->getMemberDecl(), - SourceRange(ME->getBeginLoc(), ME->getEndLoc())); - return true; - } - - bool VisitObjCAvailabilityCheckExpr(ObjCAvailabilityCheckExpr *E) { - SemaRef.Diag(E->getBeginLoc(), diag::warn_at_available_unchecked_use) - << (!SemaRef.getLangOpts().ObjC); - return true; - } - - bool VisitTypeLoc(TypeLoc Ty); -}; - -void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( - NamedDecl *D, SourceRange Range, ObjCInterfaceDecl *ReceiverClass) { - AvailabilityResult Result; - const NamedDecl *OffendingDecl; - std::tie(Result, OffendingDecl) = - ShouldDiagnoseAvailabilityOfDecl(SemaRef, D, nullptr, ReceiverClass); - if (Result != AR_Available) { - // All other diagnostic kinds have already been handled in - // DiagnoseAvailabilityOfDecl. - if (Result != AR_NotYetIntroduced) - return; - - const AvailabilityAttr *AA = - getAttrForPlatform(SemaRef.getASTContext(), OffendingDecl); - VersionTuple Introduced = AA->getIntroduced(); - - if (AvailabilityStack.back() >= Introduced) - return; - - // If the context of this function is less available than D, we should not - // emit a diagnostic. - if (!ShouldDiagnoseAvailabilityInContext(SemaRef, Result, Introduced, Ctx, - OffendingDecl)) - return; - - // We would like to emit the diagnostic even if -Wunguarded-availability is - // not specified for deployment targets >= to iOS 11 or equivalent or - // for declarations that were introduced in iOS 11 (macOS 10.13, ...) or - // later. - unsigned DiagKind = - shouldDiagnoseAvailabilityByDefault( - SemaRef.Context, - SemaRef.Context.getTargetInfo().getPlatformMinVersion(), Introduced) - ? diag::warn_unguarded_availability_new - : diag::warn_unguarded_availability; - - std::string PlatformName = AvailabilityAttr::getPrettyPlatformName( - SemaRef.getASTContext().getTargetInfo().getPlatformName()); - - SemaRef.Diag(Range.getBegin(), DiagKind) - << Range << D << PlatformName << Introduced.getAsString(); - - SemaRef.Diag(OffendingDecl->getLocation(), - diag::note_partial_availability_specified_here) - << OffendingDecl << PlatformName << Introduced.getAsString() - << SemaRef.Context.getTargetInfo() - .getPlatformMinVersion() - .getAsString(); - - auto FixitDiag = - SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) - << Range << D - << (SemaRef.getLangOpts().ObjC ? /*@available*/ 0 - : /*__builtin_available*/ 1); - - // Find the statement which should be enclosed in the if @available check. - if (StmtStack.empty()) - return; - const Stmt *StmtOfUse = StmtStack.back(); - const CompoundStmt *Scope = nullptr; - for (const Stmt *S : llvm::reverse(StmtStack)) { - if (const auto *CS = dyn_cast<CompoundStmt>(S)) { - Scope = CS; - break; - } - if (isBodyLikeChildStmt(StmtOfUse, S)) { - // The declaration won't be seen outside of the statement, so we don't - // have to wrap the uses of any declared variables in if (@available). - // Therefore we can avoid setting Scope here. - break; - } - StmtOfUse = S; - } - const Stmt *LastStmtOfUse = nullptr; - if (isa<DeclStmt>(StmtOfUse) && Scope) { - for (const Decl *D : cast<DeclStmt>(StmtOfUse)->decls()) { - if (StmtUSEFinder::isContained(StmtStack.back(), D)) { - LastStmtOfUse = LastDeclUSEFinder::findLastStmtThatUsesDecl(D, Scope); - break; - } - } - } - - const SourceManager &SM = SemaRef.getSourceManager(); - SourceLocation IfInsertionLoc = - SM.getExpansionLoc(StmtOfUse->getBeginLoc()); - SourceLocation StmtEndLoc = - SM.getExpansionRange( - (LastStmtOfUse ? LastStmtOfUse : StmtOfUse)->getEndLoc()) - .getEnd(); - if (SM.getFileID(IfInsertionLoc) != SM.getFileID(StmtEndLoc)) - return; - - StringRef Indentation = Lexer::getIndentationForLine(IfInsertionLoc, SM); - const char *ExtraIndentation = " "; - std::string FixItString; - llvm::raw_string_ostream FixItOS(FixItString); - FixItOS << "if (" << (SemaRef.getLangOpts().ObjC ? "@available" - : "__builtin_available") - << "(" - << AvailabilityAttr::getPlatformNameSourceSpelling( - SemaRef.getASTContext().getTargetInfo().getPlatformName()) - << " " << Introduced.getAsString() << ", *)) {\n" - << Indentation << ExtraIndentation; - FixitDiag << FixItHint::CreateInsertion(IfInsertionLoc, FixItOS.str()); - SourceLocation ElseInsertionLoc = Lexer::findLocationAfterToken( - StmtEndLoc, tok::semi, SM, SemaRef.getLangOpts(), - /*SkipTrailingWhitespaceAndNewLine=*/false); - if (ElseInsertionLoc.isInvalid()) - ElseInsertionLoc = - Lexer::getLocForEndOfToken(StmtEndLoc, 0, SM, SemaRef.getLangOpts()); - FixItOS.str().clear(); - FixItOS << "\n" - << Indentation << "} else {\n" - << Indentation << ExtraIndentation - << "// Fallback on earlier versions\n" - << Indentation << "}"; - FixitDiag << FixItHint::CreateInsertion(ElseInsertionLoc, FixItOS.str()); - } -} - -bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { - const Type *TyPtr = Ty.getTypePtr(); - SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()}; - - if (Range.isInvalid()) - return true; - - if (const auto *TT = dyn_cast<TagType>(TyPtr)) { - TagDecl *TD = TT->getDecl(); - DiagnoseDeclAvailability(TD, Range); - - } else if (const auto *TD = dyn_cast<TypedefType>(TyPtr)) { - TypedefNameDecl *D = TD->getDecl(); - DiagnoseDeclAvailability(D, Range); - - } else if (const auto *ObjCO = dyn_cast<ObjCObjectType>(TyPtr)) { - if (NamedDecl *D = ObjCO->getInterface()) - DiagnoseDeclAvailability(D, Range); - } - - return true; -} - -bool DiagnoseUnguardedAvailability::TraverseIfStmt(IfStmt *If) { - VersionTuple CondVersion; - if (auto *E = dyn_cast<ObjCAvailabilityCheckExpr>(If->getCond())) { - CondVersion = E->getVersion(); - - // If we're using the '*' case here or if this check is redundant, then we - // use the enclosing version to check both branches. - if (CondVersion.empty() || CondVersion <= AvailabilityStack.back()) - return TraverseStmt(If->getThen()) && TraverseStmt(If->getElse()); - } else { - // This isn't an availability checking 'if', we can just continue. - return Base::TraverseIfStmt(If); - } - - AvailabilityStack.push_back(CondVersion); - bool ShouldContinue = TraverseStmt(If->getThen()); - AvailabilityStack.pop_back(); - - return ShouldContinue && TraverseStmt(If->getElse()); -} - -} // end anonymous namespace - -void Sema::DiagnoseUnguardedAvailabilityViolations(Decl *D) { - Stmt *Body = nullptr; - - if (auto *FD = D->getAsFunction()) { - // FIXME: We only examine the pattern decl for availability violations now, - // but we should also examine instantiated templates. - if (FD->isTemplateInstantiation()) - return; - - Body = FD->getBody(); - } else if (auto *MD = dyn_cast<ObjCMethodDecl>(D)) - Body = MD->getBody(); - else if (auto *BD = dyn_cast<BlockDecl>(D)) - Body = BD->getBody(); - - assert(Body && "Need a body here!"); - - DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); -} - -void Sema::DiagnoseAvailabilityOfDecl(NamedDecl *D, - ArrayRef<SourceLocation> Locs, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess, - bool AvoidPartialAvailabilityChecks, - ObjCInterfaceDecl *ClassReceiver) { - std::string Message; - AvailabilityResult Result; - const NamedDecl* OffendingDecl; - // See if this declaration is unavailable, deprecated, or partial. - std::tie(Result, OffendingDecl) = - ShouldDiagnoseAvailabilityOfDecl(*this, D, &Message, ClassReceiver); - if (Result == AR_Available) - return; - - if (Result == AR_NotYetIntroduced) { - if (AvoidPartialAvailabilityChecks) - return; - - // We need to know the @available context in the current function to - // diagnose this use, let DiagnoseUnguardedAvailabilityViolations do that - // when we're done parsing the current function. - if (getCurFunctionOrMethodDecl()) { - getEnclosingFunction()->HasPotentialAvailabilityViolations = true; - return; - } else if (getCurBlock() || getCurLambda()) { - getCurFunction()->HasPotentialAvailabilityViolations = true; - return; - } - } - - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { - if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { - AvailabilityResult PDeclResult = PD->getAvailability(nullptr); - if (PDeclResult == Result) - ObjCPDecl = PD; - } - } - - EmitAvailabilityWarning(*this, Result, D, OffendingDecl, Message, Locs, - UnknownObjCClass, ObjCPDecl, ObjCPropertyAccess); -} diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 9916d3be77e1..22bf35dbd0cb 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -38,8 +38,9 @@ #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringExtras.h" #include <map> #include <set> @@ -51,102 +52,109 @@ using namespace clang; //===----------------------------------------------------------------------===// namespace { - /// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses - /// the default argument of a parameter to determine whether it - /// contains any ill-formed subexpressions. For example, this will - /// diagnose the use of local variables or parameters within the - /// default argument expression. - class CheckDefaultArgumentVisitor - : public StmtVisitor<CheckDefaultArgumentVisitor, bool> { - Expr *DefaultArg; - Sema *S; +/// CheckDefaultArgumentVisitor - C++ [dcl.fct.default] Traverses +/// the default argument of a parameter to determine whether it +/// contains any ill-formed subexpressions. For example, this will +/// diagnose the use of local variables or parameters within the +/// default argument expression. +class CheckDefaultArgumentVisitor + : public ConstStmtVisitor<CheckDefaultArgumentVisitor, bool> { + Sema &S; + const Expr *DefaultArg; - public: - CheckDefaultArgumentVisitor(Expr *defarg, Sema *s) - : DefaultArg(defarg), S(s) {} - - bool VisitExpr(Expr *Node); - bool VisitDeclRefExpr(DeclRefExpr *DRE); - bool VisitCXXThisExpr(CXXThisExpr *ThisE); - bool VisitLambdaExpr(LambdaExpr *Lambda); - bool VisitPseudoObjectExpr(PseudoObjectExpr *POE); - }; +public: + CheckDefaultArgumentVisitor(Sema &S, const Expr *DefaultArg) + : S(S), DefaultArg(DefaultArg) {} + + bool VisitExpr(const Expr *Node); + bool VisitDeclRefExpr(const DeclRefExpr *DRE); + bool VisitCXXThisExpr(const CXXThisExpr *ThisE); + bool VisitLambdaExpr(const LambdaExpr *Lambda); + bool VisitPseudoObjectExpr(const PseudoObjectExpr *POE); +}; - /// VisitExpr - Visit all of the children of this expression. - bool CheckDefaultArgumentVisitor::VisitExpr(Expr *Node) { - bool IsInvalid = false; - for (Stmt *SubStmt : Node->children()) - IsInvalid |= Visit(SubStmt); - return IsInvalid; - } - - /// VisitDeclRefExpr - Visit a reference to a declaration, to - /// determine whether this declaration can be used in the default - /// argument expression. - bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(DeclRefExpr *DRE) { - NamedDecl *Decl = DRE->getDecl(); - if (ParmVarDecl *Param = dyn_cast<ParmVarDecl>(Decl)) { - // C++ [dcl.fct.default]p9 - // Default arguments are evaluated each time the function is - // called. The order of evaluation of function arguments is - // unspecified. Consequently, parameters of a function shall not - // be used in default argument expressions, even if they are not - // evaluated. Parameters of a function declared before a default - // argument expression are in scope and can hide namespace and - // class member names. - return S->Diag(DRE->getBeginLoc(), - diag::err_param_default_argument_references_param) +/// VisitExpr - Visit all of the children of this expression. +bool CheckDefaultArgumentVisitor::VisitExpr(const Expr *Node) { + bool IsInvalid = false; + for (const Stmt *SubStmt : Node->children()) + IsInvalid |= Visit(SubStmt); + return IsInvalid; +} + +/// VisitDeclRefExpr - Visit a reference to a declaration, to +/// determine whether this declaration can be used in the default +/// argument expression. +bool CheckDefaultArgumentVisitor::VisitDeclRefExpr(const DeclRefExpr *DRE) { + const NamedDecl *Decl = DRE->getDecl(); + if (const auto *Param = dyn_cast<ParmVarDecl>(Decl)) { + // C++ [dcl.fct.default]p9: + // [...] parameters of a function shall not be used in default + // argument expressions, even if they are not evaluated. [...] + // + // C++17 [dcl.fct.default]p9 (by CWG 2082): + // [...] A parameter shall not appear as a potentially-evaluated + // expression in a default argument. [...] + // + if (DRE->isNonOdrUse() != NOUR_Unevaluated) + return S.Diag(DRE->getBeginLoc(), + diag::err_param_default_argument_references_param) << Param->getDeclName() << DefaultArg->getSourceRange(); - } else if (VarDecl *VDecl = dyn_cast<VarDecl>(Decl)) { - // C++ [dcl.fct.default]p7 - // Local variables shall not be used in default argument - // expressions. - if (VDecl->isLocalVarDecl()) - return S->Diag(DRE->getBeginLoc(), - diag::err_param_default_argument_references_local) - << VDecl->getDeclName() << DefaultArg->getSourceRange(); - } - - return false; - } - - /// VisitCXXThisExpr - Visit a C++ "this" expression. - bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(CXXThisExpr *ThisE) { - // C++ [dcl.fct.default]p8: - // The keyword this shall not be used in a default argument of a - // member function. - return S->Diag(ThisE->getBeginLoc(), - diag::err_param_default_argument_references_this) - << ThisE->getSourceRange(); + } else if (const auto *VDecl = dyn_cast<VarDecl>(Decl)) { + // C++ [dcl.fct.default]p7: + // Local variables shall not be used in default argument + // expressions. + // + // C++17 [dcl.fct.default]p7 (by CWG 2082): + // A local variable shall not appear as a potentially-evaluated + // expression in a default argument. + // + // C++20 [dcl.fct.default]p7 (DR as part of P0588R1, see also CWG 2346): + // Note: A local variable cannot be odr-used (6.3) in a default argument. + // + if (VDecl->isLocalVarDecl() && !DRE->isNonOdrUse()) + return S.Diag(DRE->getBeginLoc(), + diag::err_param_default_argument_references_local) + << VDecl->getDeclName() << DefaultArg->getSourceRange(); } - bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr(PseudoObjectExpr *POE) { - bool Invalid = false; - for (PseudoObjectExpr::semantics_iterator - i = POE->semantics_begin(), e = POE->semantics_end(); i != e; ++i) { - Expr *E = *i; + return false; +} - // Look through bindings. - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) { - E = OVE->getSourceExpr(); - assert(E && "pseudo-object binding without source expression?"); - } +/// VisitCXXThisExpr - Visit a C++ "this" expression. +bool CheckDefaultArgumentVisitor::VisitCXXThisExpr(const CXXThisExpr *ThisE) { + // C++ [dcl.fct.default]p8: + // The keyword this shall not be used in a default argument of a + // member function. + return S.Diag(ThisE->getBeginLoc(), + diag::err_param_default_argument_references_this) + << ThisE->getSourceRange(); +} - Invalid |= Visit(E); +bool CheckDefaultArgumentVisitor::VisitPseudoObjectExpr( + const PseudoObjectExpr *POE) { + bool Invalid = false; + for (const Expr *E : POE->semantics()) { + // Look through bindings. + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) { + E = OVE->getSourceExpr(); + assert(E && "pseudo-object binding without source expression?"); } - return Invalid; + + Invalid |= Visit(E); } + return Invalid; +} - bool CheckDefaultArgumentVisitor::VisitLambdaExpr(LambdaExpr *Lambda) { - // C++11 [expr.lambda.prim]p13: - // A lambda-expression appearing in a default argument shall not - // implicitly or explicitly capture any entity. - if (Lambda->capture_begin() == Lambda->capture_end()) - return false; +bool CheckDefaultArgumentVisitor::VisitLambdaExpr(const LambdaExpr *Lambda) { + // C++11 [expr.lambda.prim]p13: + // A lambda-expression appearing in a default argument shall not + // implicitly or explicitly capture any entity. + if (Lambda->capture_begin() == Lambda->capture_end()) + return false; - return S->Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg); - } + return S.Diag(Lambda->getBeginLoc(), diag::err_lambda_capture_default_arg); } +} // namespace void Sema::ImplicitExceptionSpecification::CalledDecl(SourceLocation CallLoc, @@ -246,14 +254,12 @@ void Sema::ImplicitExceptionSpecification::CalledStmt(Stmt *S) { ComputedEST = EST_None; } -bool -Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, - SourceLocation EqualLoc) { +ExprResult Sema::ConvertParamDefaultArgument(const ParmVarDecl *Param, + Expr *Arg, + SourceLocation EqualLoc) { if (RequireCompleteType(Param->getLocation(), Param->getType(), - diag::err_typecheck_decl_incomplete_type)) { - Param->setInvalidDecl(); + diag::err_typecheck_decl_incomplete_type)) return true; - } // C++ [dcl.fct.default]p5 // A default argument expression is implicitly converted (clause @@ -274,7 +280,12 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, CheckCompletedExpr(Arg, EqualLoc); Arg = MaybeCreateExprWithCleanups(Arg); - // Okay: add the default argument to the parameter + return Arg; +} + +void Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, + SourceLocation EqualLoc) { + // Add the default argument to the parameter Param->setDefaultArg(Arg); // We have already instantiated this parameter; provide each of the @@ -288,8 +299,6 @@ Sema::SetParamDefaultArgument(ParmVarDecl *Param, Expr *Arg, // We're done tracking this parameter's instantiations. UnparsedDefaultArgInstantiations.erase(InstPos); } - - return false; } /// ActOnParamDefaultArgument - Check whether the default argument @@ -304,18 +313,22 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, ParmVarDecl *Param = cast<ParmVarDecl>(param); UnparsedDefaultArgLocs.erase(Param); + auto Fail = [&] { + Param->setInvalidDecl(); + Param->setDefaultArg(new (Context) OpaqueValueExpr( + EqualLoc, Param->getType().getNonReferenceType(), VK_RValue)); + }; + // Default arguments are only permitted in C++ if (!getLangOpts().CPlusPlus) { Diag(EqualLoc, diag::err_param_default_argument) << DefaultArg->getSourceRange(); - Param->setInvalidDecl(); - return; + return Fail(); } // Check for unexpanded parameter packs. if (DiagnoseUnexpandedParameterPack(DefaultArg, UPPC_DefaultArgument)) { - Param->setInvalidDecl(); - return; + return Fail(); } // C++11 [dcl.fct.default]p3 @@ -324,15 +337,21 @@ Sema::ActOnParamDefaultArgument(Decl *param, SourceLocation EqualLoc, if (Param->isParameterPack()) { Diag(EqualLoc, diag::err_param_default_argument_on_parameter_pack) << DefaultArg->getSourceRange(); + // Recover by discarding the default argument. + Param->setDefaultArg(nullptr); return; } + ExprResult Result = ConvertParamDefaultArgument(Param, DefaultArg, EqualLoc); + if (Result.isInvalid()) + return Fail(); + + DefaultArg = Result.getAs<Expr>(); + // Check that the default argument is well-formed - CheckDefaultArgumentVisitor DefaultArgChecker(DefaultArg, this); - if (DefaultArgChecker.Visit(DefaultArg)) { - Param->setInvalidDecl(); - return; - } + CheckDefaultArgumentVisitor DefaultArgChecker(*this, DefaultArg); + if (DefaultArgChecker.Visit(DefaultArg)) + return Fail(); SetParamDefaultArgument(Param, DefaultArg, EqualLoc); } @@ -419,14 +438,9 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { } static bool functionDeclHasDefaultArgument(const FunctionDecl *FD) { - for (unsigned NumParams = FD->getNumParams(); NumParams > 0; --NumParams) { - const ParmVarDecl *PVD = FD->getParamDecl(NumParams-1); - if (!PVD->hasDefaultArg()) - return false; - if (!PVD->hasInheritedDefaultArg()) - return true; - } - return false; + return std::any_of(FD->param_begin(), FD->param_end(), [](ParmVarDecl *P) { + return P->hasDefaultArg() && !P->hasInheritedDefaultArg(); + }); } /// MergeCXXFunctionDecl - Merge two declarations of the same C++ @@ -664,7 +678,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, // for the same class template shall not have equivalent // parameter-declaration-clauses. if (isa<CXXDeductionGuideDecl>(New) && - !New->isFunctionTemplateSpecialization()) { + !New->isFunctionTemplateSpecialization() && isVisible(Old)) { Diag(New->getLocation(), diag::err_deduction_guide_redeclared); Diag(Old->getLocation(), diag::note_previous_declaration); } @@ -761,7 +775,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, Err << SourceRange(Loc, Loc); } else if (!CPlusPlus20Specifiers.empty()) { auto &&Warn = Diag(CPlusPlus20SpecifierLocs.front(), - getLangOpts().CPlusPlus2a + getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_decomp_decl_spec : diag::ext_decomp_decl_spec); Warn << (int)CPlusPlus20Specifiers.size() @@ -778,7 +792,7 @@ Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, // C++2a [dcl.struct.bind]p1: // A cv that includes volatile is deprecated if ((DS.getTypeQualifiers() & DeclSpec::TQ_volatile) && - getLangOpts().CPlusPlus2a) + getLangOpts().CPlusPlus20) Diag(DS.getVolatileSpecLoc(), diag::warn_deprecated_volatile_structured_binding); @@ -952,7 +966,7 @@ static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, Arg.getArgument().print(PrintingPolicy, OS); First = false; } - return OS.str(); + return std::string(OS.str()); } static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, @@ -1052,7 +1066,7 @@ static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, TemplateArgumentListInfo &Args; ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args) : R(R), Args(Args) {} - void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) { + void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) override { S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) << printTemplateArgs(S.Context.getPrintingPolicy(), Args); } @@ -1100,16 +1114,17 @@ static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, } namespace { -struct BindingDiagnosticTrap { +struct InitializingBinding { Sema &S; - DiagnosticErrorTrap Trap; - BindingDecl *BD; - - BindingDiagnosticTrap(Sema &S, BindingDecl *BD) - : S(S), Trap(S.Diags), BD(BD) {} - ~BindingDiagnosticTrap() { - if (Trap.hasErrorOccurred()) - S.Diag(BD->getLocation(), diag::note_in_binding_decl_init) << BD; + InitializingBinding(Sema &S, BindingDecl *BD) : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::InitializingStructuredBinding; + Ctx.PointOfInstantiation = BD->getLocation(); + Ctx.Entity = BD; + S.pushCodeSynthesisContext(Ctx); + } + ~InitializingBinding() { + S.popCodeSynthesisContext(); } }; } @@ -1158,7 +1173,7 @@ static bool checkTupleLikeDecomposition(Sema &S, unsigned I = 0; for (auto *B : Bindings) { - BindingDiagnosticTrap Trap(S, B); + InitializingBinding InitContext(S, B); SourceLocation Loc = B->getLocation(); ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); @@ -1528,25 +1543,34 @@ void Sema::MergeVarDeclExceptionSpecs(VarDecl *New, VarDecl *Old) { /// [dcl.fct.default]. void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { unsigned NumParams = FD->getNumParams(); - unsigned p; + unsigned ParamIdx = 0; + + // This checking doesn't make sense for explicit specializations; their + // default arguments are determined by the declaration we're specializing, + // not by FD. + if (FD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) + return; + if (auto *FTD = FD->getDescribedFunctionTemplate()) + if (FTD->isMemberSpecialization()) + return; // Find first parameter with a default argument - for (p = 0; p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); + for (; ParamIdx < NumParams; ++ParamIdx) { + ParmVarDecl *Param = FD->getParamDecl(ParamIdx); if (Param->hasDefaultArg()) break; } - // C++11 [dcl.fct.default]p4: + // C++20 [dcl.fct.default]p4: // In a given function declaration, each parameter subsequent to a parameter // with a default argument shall have a default argument supplied in this or - // a previous declaration or shall be a function parameter pack. A default - // argument shall not be redefined by a later declaration (not even to the - // same value). - unsigned LastMissingDefaultArg = 0; - for (; p < NumParams; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - if (!Param->hasDefaultArg() && !Param->isParameterPack()) { + // a previous declaration, unless the parameter was expanded from a + // parameter pack, or shall be a function parameter pack. + for (; ParamIdx < NumParams; ++ParamIdx) { + ParmVarDecl *Param = FD->getParamDecl(ParamIdx); + if (!Param->hasDefaultArg() && !Param->isParameterPack() && + !(CurrentInstantiationScope && + CurrentInstantiationScope->isLocalPackExpansion(Param))) { if (Param->isInvalidDecl()) /* We already complained about this parameter. */; else if (Param->getIdentifier()) @@ -1556,21 +1580,6 @@ void Sema::CheckCXXDefaultArguments(FunctionDecl *FD) { else Diag(Param->getLocation(), diag::err_param_default_argument_missing); - - LastMissingDefaultArg = p; - } - } - - if (LastMissingDefaultArg > 0) { - // Some default arguments were missing. Clear out all of the - // default arguments up to (and including) the last missing - // default argument, so that we leave the function parameters - // in a semantically valid state. - for (p = 0; p <= LastMissingDefaultArg; ++p) { - ParmVarDecl *Param = FD->getParamDecl(p); - if (Param->hasDefaultArg()) { - Param->setDefaultArg(nullptr); - } } } } @@ -1716,7 +1725,7 @@ bool Sema::CheckConstexprFunctionDefinition(const FunctionDecl *NewFD, // - it shall not be virtual; (removed in C++20) const CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD); if (Method && Method->isVirtual()) { - if (getLangOpts().CPlusPlus2a) { + if (getLangOpts().CPlusPlus20) { if (Kind == CheckConstexprKind::Diagnose) Diag(Method->getLocation(), diag::warn_cxx17_compat_constexpr_virtual); } else { @@ -1856,11 +1865,11 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag( VD->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_local_var_no_init : diag::ext_constexpr_local_var_no_init) << isa<CXXConstructorDecl>(Dcl); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } continue; @@ -1919,7 +1928,7 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, Sema::CheckConstexprKind Kind) { // In C++20 onwards, there's nothing to check for validity. if (Kind == Sema::CheckConstexprKind::CheckValid && - SemaRef.getLangOpts().CPlusPlus2a) + SemaRef.getLangOpts().CPlusPlus20) return true; if (Field->isInvalidDecl()) @@ -1941,14 +1950,14 @@ static bool CheckConstexprCtorInitializer(Sema &SemaRef, if (Kind == Sema::CheckConstexprKind::Diagnose) { if (!Diagnosed) { SemaRef.Diag(Dcl->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_ctor_missing_init : diag::ext_constexpr_ctor_missing_init); Diagnosed = true; } SemaRef.Diag(Field->getLocation(), diag::note_constexpr_ctor_missing_init); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } } else if (Field->isAnonymousStructOrUnion()) { @@ -2132,14 +2141,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, // apply the general constexpr rules. switch (Kind) { case Sema::CheckConstexprKind::CheckValid: - if (!SemaRef.getLangOpts().CPlusPlus2a) + if (!SemaRef.getLangOpts().CPlusPlus20) return false; break; case Sema::CheckConstexprKind::Diagnose: SemaRef.Diag(Body->getBeginLoc(), - !SemaRef.getLangOpts().CPlusPlus2a - ? diag::ext_constexpr_function_try_block_cxx2a + !SemaRef.getLangOpts().CPlusPlus20 + ? diag::ext_constexpr_function_try_block_cxx20 : diag::warn_cxx17_compat_constexpr_function_try_block) << isa<CXXConstructorDecl>(Dcl); break; @@ -2162,14 +2171,14 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::CheckValid) { // If this is only valid as an extension, report that we don't satisfy the // constraints of the current language. - if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus2a) || + if ((Cxx2aLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus20) || (Cxx1yLoc.isValid() && !SemaRef.getLangOpts().CPlusPlus17)) return false; } else if (Cxx2aLoc.isValid()) { SemaRef.Diag(Cxx2aLoc, - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_body_invalid_stmt - : diag::ext_constexpr_body_invalid_stmt_cxx2a) + : diag::ext_constexpr_body_invalid_stmt_cxx20) << isa<CXXConstructorDecl>(Dcl); } else if (Cxx1yLoc.isValid()) { SemaRef.Diag(Cxx1yLoc, @@ -2194,10 +2203,10 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, if (Kind == Sema::CheckConstexprKind::Diagnose) { SemaRef.Diag( Dcl->getLocation(), - SemaRef.getLangOpts().CPlusPlus2a + SemaRef.getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_constexpr_union_ctor_no_init : diag::ext_constexpr_union_ctor_no_init); - } else if (!SemaRef.getLangOpts().CPlusPlus2a) { + } else if (!SemaRef.getLangOpts().CPlusPlus20) { return false; } } @@ -2306,7 +2315,7 @@ static bool CheckConstexprFunctionBody(Sema &SemaRef, const FunctionDecl *Dcl, !Expr::isPotentialConstantExpr(Dcl, Diags)) { SemaRef.Diag(Dcl->getLocation(), diag::ext_constexpr_function_never_constant_expr) - << isa<CXXConstructorDecl>(Dcl); + << isa<CXXConstructorDecl>(Dcl) << Dcl->isConsteval(); for (size_t I = 0, N = Diags.size(); I != N; ++I) SemaRef.Diag(Diags[I].first, Diags[I].second); // Don't return false here: we allow this for compatibility in @@ -2417,7 +2426,10 @@ Sema::CheckBaseSpecifier(CXXRecordDecl *Class, TypeSourceInfo *TInfo, SourceLocation EllipsisLoc) { QualType BaseType = TInfo->getType(); - + if (BaseType->containsErrors()) { + // Already emitted a diagnostic when parsing the error type. + return nullptr; + } // C++ [class.union]p1: // A union shall not have base classes. if (Class->isUnion()) { @@ -2821,13 +2833,13 @@ void Sema::BuildBasePathArray(const CXXBasePaths &Paths, /// if there is an error, and Range is the source range to highlight /// if there is an error. /// -/// If either InaccessibleBaseID or AmbigiousBaseConvID are 0, then the +/// If either InaccessibleBaseID or AmbiguousBaseConvID are 0, then the /// diagnostic for the respective type of error will be suppressed, but the /// check for ill-formed code will still be performed. bool Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, unsigned InaccessibleBaseID, - unsigned AmbigiousBaseConvID, + unsigned AmbiguousBaseConvID, SourceLocation Loc, SourceRange Range, DeclarationName Name, CXXCastPath *BasePath, @@ -2853,7 +2865,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, for (const CXXBasePath &PossiblePath : Paths) { if (PossiblePath.size() == 1) { Path = &PossiblePath; - if (AmbigiousBaseConvID) + if (AmbiguousBaseConvID) Diag(Loc, diag::ext_ms_ambiguous_direct_base) << Base << Derived << Range; break; @@ -2881,7 +2893,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, return false; } - if (AmbigiousBaseConvID) { + if (AmbiguousBaseConvID) { // We know that the derived-to-base conversion is ambiguous, and // we're going to produce a diagnostic. Perform the derived-to-base // search just one more time to compute all of the possible paths so @@ -2900,7 +2912,7 @@ Sema::CheckDerivedToBaseConversion(QualType Derived, QualType Base, // to each base class subobject. std::string PathDisplayStr = getAmbiguousPathsDisplayString(Paths); - Diag(Loc, AmbigiousBaseConvID) + Diag(Loc, AmbiguousBaseConvID) << Derived << Base << PathDisplayStr << Range << Name; } return true; @@ -3033,7 +3045,7 @@ void Sema::CheckOverrideControl(NamedDecl *D) { << MD->getDeclName(); } -void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { +void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D, bool Inconsistent) { if (D->isInvalidDecl() || D->hasAttr<OverrideAttr>()) return; CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(D); @@ -3049,12 +3061,22 @@ void Sema::DiagnoseAbsenceOfOverrideControl(NamedDecl *D) { return; if (MD->size_overridden_methods() > 0) { - unsigned DiagID = isa<CXXDestructorDecl>(MD) - ? diag::warn_destructor_marked_not_override_overriding - : diag::warn_function_marked_not_override_overriding; - Diag(MD->getLocation(), DiagID) << MD->getDeclName(); - const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); - Diag(OMD->getLocation(), diag::note_overridden_virtual_function); + auto EmitDiag = [&](unsigned DiagInconsistent, unsigned DiagSuggest) { + unsigned DiagID = + Inconsistent && !Diags.isIgnored(DiagInconsistent, MD->getLocation()) + ? DiagInconsistent + : DiagSuggest; + Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + const CXXMethodDecl *OMD = *MD->begin_overridden_methods(); + Diag(OMD->getLocation(), diag::note_overridden_virtual_function); + }; + if (isa<CXXDestructorDecl>(MD)) + EmitDiag( + diag::warn_inconsistent_destructor_marked_not_override_overriding, + diag::warn_suggest_destructor_marked_not_override_overriding); + else + EmitDiag(diag::warn_inconsistent_function_marked_not_override_overriding, + diag::warn_suggest_function_marked_not_override_overriding); } } @@ -5443,6 +5465,15 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, // subobjects. bool VisitVirtualBases = !ClassDecl->isAbstract(); + // If the destructor exists and has already been marked used in the MS ABI, + // then virtual base destructors have already been checked and marked used. + // Skip checking them again to avoid duplicate diagnostics. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + CXXDestructorDecl *Dtor = ClassDecl->getDestructor(); + if (Dtor && Dtor->isUsed()) + VisitVirtualBases = false; + } + llvm::SmallPtrSet<const RecordType *, 8> DirectVirtualBases; // Bases. @@ -5477,16 +5508,21 @@ Sema::MarkBaseAndMemberDestructorsReferenced(SourceLocation Location, DiagnoseUseOfDecl(Dtor, Location); } - if (!VisitVirtualBases) - return; + if (VisitVirtualBases) + MarkVirtualBaseDestructorsReferenced(Location, ClassDecl, + &DirectVirtualBases); +} +void Sema::MarkVirtualBaseDestructorsReferenced( + SourceLocation Location, CXXRecordDecl *ClassDecl, + llvm::SmallPtrSetImpl<const RecordType *> *DirectVirtualBases) { // Virtual bases. for (const auto &VBase : ClassDecl->vbases()) { // Bases are always records in a well-formed non-dependent class. const RecordType *RT = VBase.getType()->castAs<RecordType>(); - // Ignore direct virtual bases. - if (DirectVirtualBases.count(RT)) + // Ignore already visited direct virtual bases. + if (DirectVirtualBases && DirectVirtualBases->count(RT)) continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(RT->getDecl()); @@ -5788,6 +5824,23 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // declaration. return; + // Add a context note to explain how we got to any diagnostics produced below. + struct MarkingClassDllexported { + Sema &S; + MarkingClassDllexported(Sema &S, CXXRecordDecl *Class, + SourceLocation AttrLoc) + : S(S) { + Sema::CodeSynthesisContext Ctx; + Ctx.Kind = Sema::CodeSynthesisContext::MarkingClassDllexported; + Ctx.PointOfInstantiation = AttrLoc; + Ctx.Entity = Class; + S.pushCodeSynthesisContext(Ctx); + } + ~MarkingClassDllexported() { + S.popCodeSynthesisContext(); + } + } MarkingDllexportedContext(S, Class, ClassAttr->getLocation()); + if (S.Context.getTargetInfo().getTriple().isWindowsGNUEnvironment()) S.MarkVTableUsed(Class->getLocation(), Class, true); @@ -5823,13 +5876,7 @@ static void ReferenceDllExportedMembers(Sema &S, CXXRecordDecl *Class) { // defaulted methods, and the copy and move assignment operators. The // latter are exported even if they are trivial, because the address of // an operator can be taken and should compare equal across libraries. - DiagnosticErrorTrap Trap(S.Diags); S.MarkFunctionReferenced(Class->getLocation(), MD); - if (Trap.hasErrorOccurred()) { - S.Diag(ClassAttr->getLocation(), diag::note_due_to_dllexported_class) - << Class << !S.getLangOpts().CPlusPlus11; - break; - } // There is no later point when we will see the definition of this // function, so pass it to the consumer now. @@ -5877,6 +5924,123 @@ static void checkForMultipleExportedDefaultConstructors(Sema &S, } } +static void checkCUDADeviceBuiltinSurfaceClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*surface*/ 0 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*surface*/ 0 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 2) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 2; + } + if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } +} + +static void checkCUDADeviceBuiltinTextureClassTemplate(Sema &S, + CXXRecordDecl *Class) { + bool ErrorReported = false; + auto reportIllegalClassTemplate = [&ErrorReported](Sema &S, + ClassTemplateDecl *TD) { + if (ErrorReported) + return; + S.Diag(TD->getLocation(), + diag::err_cuda_device_builtin_surftex_cls_template) + << /*texture*/ 1 << TD; + ErrorReported = true; + }; + + ClassTemplateDecl *TD = Class->getDescribedClassTemplate(); + if (!TD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(Class); + if (!SD) { + S.Diag(Class->getLocation(), + diag::err_cuda_device_builtin_surftex_ref_decl) + << /*texture*/ 1 << Class; + S.Diag(Class->getLocation(), + diag::note_cuda_device_builtin_surftex_should_be_template_class) + << Class; + return; + } + TD = SD->getSpecializedTemplate(); + } + + TemplateParameterList *Params = TD->getTemplateParameters(); + unsigned N = Params->size(); + + if (N != 3) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_n_args) + << TD << 3; + } + if (N > 0 && !isa<TemplateTypeParmDecl>(Params->getParam(0))) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*1st*/ 0 << /*type*/ 0; + } + if (N > 1) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*2nd*/ 1 << /*integer*/ 1; + } + } + if (N > 2) { + auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(2)); + if (!NTTP || !NTTP->getType()->isIntegralOrEnumerationType()) { + reportIllegalClassTemplate(S, TD); + S.Diag(TD->getLocation(), + diag::note_cuda_device_builtin_surftex_cls_should_have_match_arg) + << TD << /*3rd*/ 2 << /*integer*/ 1; + } + } +} + void Sema::checkClassLevelCodeSegAttribute(CXXRecordDecl *Class) { // Mark any compiler-generated routines with the implicit code_seg attribute. for (auto *Method : Class->methods()) { @@ -6151,7 +6315,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { case OO_Spaceship: // No point allowing this if <=> doesn't exist in the current language mode. - if (!getLangOpts().CPlusPlus2a) + if (!getLangOpts().CPlusPlus20) break; return DefaultedComparisonKind::ThreeWay; @@ -6160,7 +6324,7 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { case OO_Greater: case OO_GreaterEqual: // No point allowing this if <=> doesn't exist in the current language mode. - if (!getLangOpts().CPlusPlus2a) + if (!getLangOpts().CPlusPlus20) break; return DefaultedComparisonKind::Relational; @@ -6172,27 +6336,31 @@ Sema::getDefaultedFunctionKind(const FunctionDecl *FD) { return DefaultedFunctionKind(); } -static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, - SourceLocation DefaultLoc) { - switch (S.getSpecialMember(MD)) { +static void DefineDefaultedFunction(Sema &S, FunctionDecl *FD, + SourceLocation DefaultLoc) { + Sema::DefaultedFunctionKind DFK = S.getDefaultedFunctionKind(FD); + if (DFK.isComparison()) + return S.DefineDefaultedComparison(DefaultLoc, FD, DFK.asComparison()); + + switch (DFK.asSpecialMember()) { case Sema::CXXDefaultConstructor: S.DefineImplicitDefaultConstructor(DefaultLoc, - cast<CXXConstructorDecl>(MD)); + cast<CXXConstructorDecl>(FD)); break; case Sema::CXXCopyConstructor: - S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD)); break; case Sema::CXXCopyAssignment: - S.DefineImplicitCopyAssignment(DefaultLoc, MD); + S.DefineImplicitCopyAssignment(DefaultLoc, cast<CXXMethodDecl>(FD)); break; case Sema::CXXDestructor: - S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD)); + S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(FD)); break; case Sema::CXXMoveConstructor: - S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(FD)); break; case Sema::CXXMoveAssignment: - S.DefineImplicitMoveAssignment(DefaultLoc, MD); + S.DefineImplicitMoveAssignment(DefaultLoc, cast<CXXMethodDecl>(FD)); break; case Sema::CXXInvalid: llvm_unreachable("Invalid special member."); @@ -6313,6 +6481,27 @@ static bool canPassInRegisters(Sema &S, CXXRecordDecl *D, return HasNonDeletedCopyOrMove; } +/// Report an error regarding overriding, along with any relevant +/// overridden methods. +/// +/// \param DiagID the primary error to report. +/// \param MD the overriding method. +static bool +ReportOverrides(Sema &S, unsigned DiagID, const CXXMethodDecl *MD, + llvm::function_ref<bool(const CXXMethodDecl *)> Report) { + bool IssuedDiagnostic = false; + for (const CXXMethodDecl *O : MD->overridden_methods()) { + if (Report(O)) { + if (!IssuedDiagnostic) { + S.Diag(MD->getLocation(), DiagID) << MD->getDeclName(); + IssuedDiagnostic = true; + } + S.Diag(O->getLocation(), diag::note_overridden_virtual_function); + } + } + return IssuedDiagnostic; +} + /// Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -6427,21 +6616,64 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // primary comparison functions (==, <=>). llvm::SmallVector<FunctionDecl*, 5> DefaultedSecondaryComparisons; - auto CheckForDefaultedFunction = [&](FunctionDecl *FD) { - if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted()) + // Perform checks that can't be done until we know all the properties of a + // member function (whether it's defaulted, deleted, virtual, overriding, + // ...). + auto CheckCompletedMemberFunction = [&](CXXMethodDecl *MD) { + // A static function cannot override anything. + if (MD->getStorageClass() == SC_Static) { + if (ReportOverrides(*this, diag::err_static_overrides_virtual, MD, + [](const CXXMethodDecl *) { return true; })) + return; + } + + // A deleted function cannot override a non-deleted function and vice + // versa. + if (ReportOverrides(*this, + MD->isDeleted() ? diag::err_deleted_override + : diag::err_non_deleted_override, + MD, [&](const CXXMethodDecl *V) { + return MD->isDeleted() != V->isDeleted(); + })) { + if (MD->isDefaulted() && MD->isDeleted()) + // Explain why this defaulted function was deleted. + DiagnoseDeletedDefaultedFunction(MD); return; + } + + // A consteval function cannot override a non-consteval function and vice + // versa. + if (ReportOverrides(*this, + MD->isConsteval() ? diag::err_consteval_override + : diag::err_non_consteval_override, + MD, [&](const CXXMethodDecl *V) { + return MD->isConsteval() != V->isConsteval(); + })) { + if (MD->isDefaulted() && MD->isDeleted()) + // Explain why this defaulted function was deleted. + DiagnoseDeletedDefaultedFunction(MD); + return; + } + }; + + auto CheckForDefaultedFunction = [&](FunctionDecl *FD) -> bool { + if (!FD || FD->isInvalidDecl() || !FD->isExplicitlyDefaulted()) + return false; DefaultedFunctionKind DFK = getDefaultedFunctionKind(FD); if (DFK.asComparison() == DefaultedComparisonKind::NotEqual || - DFK.asComparison() == DefaultedComparisonKind::Relational) + DFK.asComparison() == DefaultedComparisonKind::Relational) { DefaultedSecondaryComparisons.push_back(FD); - else - CheckExplicitlyDefaultedFunction(S, FD); + return true; + } + + CheckExplicitlyDefaultedFunction(S, FD); + return false; }; auto CompleteMemberFunction = [&](CXXMethodDecl *M) { // Check whether the explicitly-defaulted members are valid. - CheckForDefaultedFunction(M); + bool Incomplete = CheckForDefaultedFunction(M); // Skip the rest of the checks for a member of a dependent class. if (Record->isDependentType()) @@ -6488,7 +6720,10 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // function right away. // FIXME: We can defer doing this until the vtable is marked as used. if (M->isDefaulted() && M->isConstexpr() && M->size_overridden_methods()) - DefineImplicitSpecialMember(*this, M, M->getLocation()); + DefineDefaultedFunction(*this, M, M->getLocation()); + + if (!Incomplete) + CheckCompletedMemberFunction(M); }; // Check the destructor before any other member function. We need to @@ -6524,19 +6759,21 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { } } - if (HasMethodWithOverrideControl && - HasOverridingMethodWithoutOverrideControl) { - // At least one method has the 'override' control declared. - // Diagnose all other overridden methods which do not have 'override' - // specified on them. + if (HasOverridingMethodWithoutOverrideControl) { + bool HasInconsistentOverrideControl = HasMethodWithOverrideControl; for (auto *M : Record->methods()) - DiagnoseAbsenceOfOverrideControl(M); + DiagnoseAbsenceOfOverrideControl(M, HasInconsistentOverrideControl); } // Check the defaulted secondary comparisons after any other member functions. - for (FunctionDecl *FD : DefaultedSecondaryComparisons) + for (FunctionDecl *FD : DefaultedSecondaryComparisons) { CheckExplicitlyDefaultedFunction(S, FD); + // If this is a member function, we deferred checking it until now. + if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) + CheckCompletedMemberFunction(MD); + } + // ms_struct is a request to use the same ABI rules as MSVC. Check // whether this class uses any C++ features that are implemented // completely differently in MSVC, and if so, emit a diagnostic. @@ -6546,7 +6783,11 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // headers, sweeping up a bunch of types that the project doesn't // really rely on MSVC-compatible layout for. We must therefore // support "ms_struct except for C++ stuff" as a secondary ABI. - if (Record->isMsStruct(Context) && + // Don't emit this diagnostic if the feature was enabled as a + // language option (as opposed to via a pragma or attribute), as + // the option -mms-bitfields otherwise essentially makes it impossible + // to build C++ code, unless this diagnostic is turned off. + if (Record->isMsStruct(Context) && !Context.getLangOpts().MSBitfields && (Record->isPolymorphic() || Record->getNumBases())) { Diag(Record->getLocation(), diag::warn_cxx_ms_struct); } @@ -6581,6 +6822,13 @@ void Sema::CheckCompletedCXXClass(Scope *S, CXXRecordDecl *Record) { // is especially required for cases like vtable assumption loads. MarkVTableUsed(Record->getInnerLocStart(), Record); } + + if (getLangOpts().CUDA) { + if (Record->hasAttr<CUDADeviceBuiltinSurfaceTypeAttr>()) + checkCUDADeviceBuiltinSurfaceClassTemplate(*this, Record); + else if (Record->hasAttr<CUDADeviceBuiltinTextureTypeAttr>()) + checkCUDADeviceBuiltinTextureClassTemplate(*this, Record); + } } /// Look up the special member function that would be called by a special @@ -6955,7 +7203,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // C++2a changes the second bullet to instead delete the function if it's // defaulted on its first declaration, unless it's "an assignment operator, // and its return type differs or its parameter type is not a reference". - bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus2a && First; + bool DeleteOnTypeMismatch = getLangOpts().CPlusPlus20 && First; bool ShouldDeleteForTypeMismatch = false; unsigned ExpectedParams = 1; if (CSM == CXXDefaultConstructor || CSM == CXXDestructor) @@ -7065,7 +7313,7 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // FIXME: This should not apply if the member is deleted. bool Constexpr = defaultedSpecialMemberIsConstexpr(*this, RD, CSM, HasConstParam); - if ((getLangOpts().CPlusPlus2a || + if ((getLangOpts().CPlusPlus20 || (getLangOpts().CPlusPlus14 ? !isa<CXXDestructorDecl>(MD) : isa<CXXConstructorDecl>(MD))) && MD->isConstexpr() && !Constexpr && @@ -7083,7 +7331,9 @@ bool Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD, // If a function is explicitly defaulted on its first declaration, it is // implicitly considered to be constexpr if the implicit declaration // would be. - MD->setConstexprKind(Constexpr ? CSK_constexpr : CSK_unspecified); + MD->setConstexprKind( + Constexpr ? (MD->isConsteval() ? CSK_consteval : CSK_constexpr) + : CSK_unspecified); if (!Type->hasExceptionSpec()) { // C++2a [except.spec]p3: @@ -7373,7 +7623,14 @@ private: /// resolution [...] CandidateSet.exclude(FD); - S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); + if (Args[0]->getType()->isOverloadableType()) + S.LookupOverloadedBinOp(CandidateSet, OO, Fns, Args); + else { + // FIXME: We determine whether this is a valid expression by checking to + // see if there's a viable builtin operator candidate for it. That isn't + // really what the rules ask us to do, but should give the right results. + S.AddBuiltinOperatorCandidates(OO, FD->getLocation(), Args, CandidateSet); + } Result R; @@ -7438,6 +7695,31 @@ private: if (OO == OO_Spaceship && FD->getReturnType()->isUndeducedAutoType()) { if (auto *BestFD = Best->Function) { + // If any callee has an undeduced return type, deduce it now. + // FIXME: It's not clear how a failure here should be handled. For + // now, we produce an eager diagnostic, because that is forward + // compatible with most (all?) other reasonable options. + if (BestFD->getReturnType()->isUndeducedType() && + S.DeduceReturnType(BestFD, FD->getLocation(), + /*Diagnose=*/false)) { + // Don't produce a duplicate error when asked to explain why the + // comparison is deleted: we diagnosed that when initially checking + // the defaulted operator. + if (Diagnose == NoDiagnostics) { + S.Diag( + FD->getLocation(), + diag::err_defaulted_comparison_cannot_deduce_undeduced_auto) + << Subobj.Kind << Subobj.Decl; + S.Diag( + Subobj.Loc, + diag::note_defaulted_comparison_cannot_deduce_undeduced_auto) + << Subobj.Kind << Subobj.Decl; + S.Diag(BestFD->getLocation(), + diag::note_defaulted_comparison_cannot_deduce_callee) + << Subobj.Kind << Subobj.Decl; + } + return Result::deleted(); + } if (auto *Info = S.Context.CompCategories.lookupInfoForType( BestFD->getCallResultType())) { R.Category = Info->Kind; @@ -7826,10 +8108,14 @@ private: return StmtError(); OverloadedOperatorKind OO = FD->getOverloadedOperator(); - ExprResult Op = S.CreateOverloadedBinOp( - Loc, BinaryOperator::getOverloadedOpcode(OO), Fns, - Obj.first.get(), Obj.second.get(), /*PerformADL=*/true, - /*AllowRewrittenCandidates=*/true, FD); + BinaryOperatorKind Opc = BinaryOperator::getOverloadedOpcode(OO); + ExprResult Op; + if (Type->isOverloadableType()) + Op = S.CreateOverloadedBinOp(Loc, Opc, Fns, Obj.first.get(), + Obj.second.get(), /*PerformADL=*/true, + /*AllowRewrittenCandidates=*/true, FD); + else + Op = S.CreateBuiltinBinOp(Loc, Opc, Obj.first.get(), Obj.second.get()); if (Op.isInvalid()) return StmtError(); @@ -7869,8 +8155,12 @@ private: llvm::APInt ZeroVal(S.Context.getIntWidth(S.Context.IntTy), 0); Expr *Zero = IntegerLiteral::Create(S.Context, ZeroVal, S.Context.IntTy, Loc); - ExprResult Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), - Zero, true, true, FD); + ExprResult Comp; + if (VDRef.get()->getType()->isOverloadableType()) + Comp = S.CreateOverloadedBinOp(Loc, BO_NE, Fns, VDRef.get(), Zero, true, + true, FD); + else + Comp = S.CreateBuiltinBinOp(Loc, BO_NE, VDRef.get(), Zero); if (Comp.isInvalid()) return StmtError(); Sema::ConditionResult Cond = S.ActOnCondition( @@ -9423,27 +9713,57 @@ void Sema::DiagnoseHiddenVirtualMethods(CXXMethodDecl *MD) { } void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { - auto PrintDiagAndRemoveAttr = [&]() { + auto PrintDiagAndRemoveAttr = [&](unsigned N) { // No diagnostics if this is a template instantiation. - if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) + if (!isTemplateInstantiation(RD.getTemplateSpecializationKind())) { Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), diag::ext_cannot_use_trivial_abi) << &RD; + Diag(RD.getAttr<TrivialABIAttr>()->getLocation(), + diag::note_cannot_use_trivial_abi_reason) << &RD << N; + } RD.dropAttr<TrivialABIAttr>(); }; + // Ill-formed if the copy and move constructors are deleted. + auto HasNonDeletedCopyOrMoveConstructor = [&]() { + // If the type is dependent, then assume it might have + // implicit copy or move ctor because we won't know yet at this point. + if (RD.isDependentType()) + return true; + if (RD.needsImplicitCopyConstructor() && + !RD.defaultedCopyConstructorIsDeleted()) + return true; + if (RD.needsImplicitMoveConstructor() && + !RD.defaultedMoveConstructorIsDeleted()) + return true; + for (const CXXConstructorDecl *CD : RD.ctors()) + if (CD->isCopyOrMoveConstructor() && !CD->isDeleted()) + return true; + return false; + }; + + if (!HasNonDeletedCopyOrMoveConstructor()) { + PrintDiagAndRemoveAttr(0); + return; + } + // Ill-formed if the struct has virtual functions. if (RD.isPolymorphic()) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(1); return; } for (const auto &B : RD.bases()) { // Ill-formed if the base class is non-trivial for the purpose of calls or a // virtual base. - if ((!B.getType()->isDependentType() && - !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) || - B.isVirtual()) { - PrintDiagAndRemoveAttr(); + if (!B.getType()->isDependentType() && + !B.getType()->getAsCXXRecordDecl()->canPassInRegisters()) { + PrintDiagAndRemoveAttr(2); + return; + } + + if (B.isVirtual()) { + PrintDiagAndRemoveAttr(3); return; } } @@ -9453,14 +9773,14 @@ void Sema::checkIllFormedTrivialABIStruct(CXXRecordDecl &RD) { // non-trivial for the purpose of calls. QualType FT = FD->getType(); if (FT.getObjCLifetime() == Qualifiers::OCL_Weak) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(4); return; } if (const auto *RT = FT->getBaseElementTypeUnsafe()->getAs<RecordType>()) if (!RT->isDependentType() && !cast<CXXRecordDecl>(RT->getDecl())->canPassInRegisters()) { - PrintDiagAndRemoveAttr(); + PrintDiagAndRemoveAttr(5); return; } } @@ -9533,86 +9853,95 @@ static void findImplicitlyDeclaredEqualityComparisons( /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { - if (ClassDecl->needsImplicitDefaultConstructor()) { - ++getASTContext().NumImplicitDefaultConstructors; + // Don't add implicit special members to templated classes. + // FIXME: This means unqualified lookups for 'operator=' within a class + // template don't work properly. + if (!ClassDecl->isDependentType()) { + if (ClassDecl->needsImplicitDefaultConstructor()) { + ++getASTContext().NumImplicitDefaultConstructors; - if (ClassDecl->hasInheritedConstructor()) - DeclareImplicitDefaultConstructor(ClassDecl); - } + if (ClassDecl->hasInheritedConstructor()) + DeclareImplicitDefaultConstructor(ClassDecl); + } - if (ClassDecl->needsImplicitCopyConstructor()) { - ++getASTContext().NumImplicitCopyConstructors; + if (ClassDecl->needsImplicitCopyConstructor()) { + ++getASTContext().NumImplicitCopyConstructors; - // If the properties or semantics of the copy constructor couldn't be - // determined while the class was being declared, force a declaration - // of it now. - if (ClassDecl->needsOverloadResolutionForCopyConstructor() || - ClassDecl->hasInheritedConstructor()) - DeclareImplicitCopyConstructor(ClassDecl); - // For the MS ABI we need to know whether the copy ctor is deleted. A - // prerequisite for deleting the implicit copy ctor is that the class has a - // move ctor or move assignment that is either user-declared or whose - // semantics are inherited from a subobject. FIXME: We should provide a more - // direct way for CodeGen to ask whether the constructor was deleted. - else if (Context.getTargetInfo().getCXXABI().isMicrosoft() && - (ClassDecl->hasUserDeclaredMoveConstructor() || - ClassDecl->needsOverloadResolutionForMoveConstructor() || - ClassDecl->hasUserDeclaredMoveAssignment() || - ClassDecl->needsOverloadResolutionForMoveAssignment())) - DeclareImplicitCopyConstructor(ClassDecl); - } + // If the properties or semantics of the copy constructor couldn't be + // determined while the class was being declared, force a declaration + // of it now. + if (ClassDecl->needsOverloadResolutionForCopyConstructor() || + ClassDecl->hasInheritedConstructor()) + DeclareImplicitCopyConstructor(ClassDecl); + // For the MS ABI we need to know whether the copy ctor is deleted. A + // prerequisite for deleting the implicit copy ctor is that the class has + // a move ctor or move assignment that is either user-declared or whose + // semantics are inherited from a subobject. FIXME: We should provide a + // more direct way for CodeGen to ask whether the constructor was deleted. + else if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + (ClassDecl->hasUserDeclaredMoveConstructor() || + ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasUserDeclaredMoveAssignment() || + ClassDecl->needsOverloadResolutionForMoveAssignment())) + DeclareImplicitCopyConstructor(ClassDecl); + } - if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) { - ++getASTContext().NumImplicitMoveConstructors; + if (getLangOpts().CPlusPlus11 && + ClassDecl->needsImplicitMoveConstructor()) { + ++getASTContext().NumImplicitMoveConstructors; - if (ClassDecl->needsOverloadResolutionForMoveConstructor() || - ClassDecl->hasInheritedConstructor()) - DeclareImplicitMoveConstructor(ClassDecl); - } + if (ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasInheritedConstructor()) + DeclareImplicitMoveConstructor(ClassDecl); + } - if (ClassDecl->needsImplicitCopyAssignment()) { - ++getASTContext().NumImplicitCopyAssignmentOperators; + if (ClassDecl->needsImplicitCopyAssignment()) { + ++getASTContext().NumImplicitCopyAssignmentOperators; - // If we have a dynamic class, then the copy assignment operator may be - // virtual, so we have to declare it immediately. This ensures that, e.g., - // it shows up in the right place in the vtable and that we diagnose - // problems with the implicit exception specification. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForCopyAssignment() || - ClassDecl->hasInheritedAssignment()) - DeclareImplicitCopyAssignment(ClassDecl); - } + // If we have a dynamic class, then the copy assignment operator may be + // virtual, so we have to declare it immediately. This ensures that, e.g., + // it shows up in the right place in the vtable and that we diagnose + // problems with the implicit exception specification. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForCopyAssignment() || + ClassDecl->hasInheritedAssignment()) + DeclareImplicitCopyAssignment(ClassDecl); + } - if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) { - ++getASTContext().NumImplicitMoveAssignmentOperators; + if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveAssignment()) { + ++getASTContext().NumImplicitMoveAssignmentOperators; - // Likewise for the move assignment operator. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForMoveAssignment() || - ClassDecl->hasInheritedAssignment()) - DeclareImplicitMoveAssignment(ClassDecl); - } + // Likewise for the move assignment operator. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForMoveAssignment() || + ClassDecl->hasInheritedAssignment()) + DeclareImplicitMoveAssignment(ClassDecl); + } - if (ClassDecl->needsImplicitDestructor()) { - ++getASTContext().NumImplicitDestructors; + if (ClassDecl->needsImplicitDestructor()) { + ++getASTContext().NumImplicitDestructors; - // If we have a dynamic class, then the destructor may be virtual, so we - // have to declare the destructor immediately. This ensures that, e.g., it - // shows up in the right place in the vtable and that we diagnose problems - // with the implicit exception specification. - if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForDestructor()) - DeclareImplicitDestructor(ClassDecl); + // If we have a dynamic class, then the destructor may be virtual, so we + // have to declare the destructor immediately. This ensures that, e.g., it + // shows up in the right place in the vtable and that we diagnose problems + // with the implicit exception specification. + if (ClassDecl->isDynamicClass() || + ClassDecl->needsOverloadResolutionForDestructor()) + DeclareImplicitDestructor(ClassDecl); + } } // C++2a [class.compare.default]p3: // If the member-specification does not explicitly declare any member or // friend named operator==, an == operator function is declared implicitly - // for each defaulted three-way comparison operator function defined in the - // member-specification + // for each defaulted three-way comparison operator function defined in + // the member-specification // FIXME: Consider doing this lazily. - if (getLangOpts().CPlusPlus2a) { - llvm::SmallVector<FunctionDecl*, 4> DefaultedSpaceships; + // We do this during the initial parse for a class template, not during + // instantiation, so that we can handle unqualified lookups for 'operator==' + // when parsing the template. + if (getLangOpts().CPlusPlus20 && !inTemplateInstantiation()) { + llvm::SmallVector<FunctionDecl *, 4> DefaultedSpaceships; findImplicitlyDeclaredEqualityComparisons(Context, ClassDecl, DefaultedSpaceships); for (auto *FD : DefaultedSpaceships) @@ -9620,19 +9949,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { } } -unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { +unsigned +Sema::ActOnReenterTemplateScope(Decl *D, + llvm::function_ref<Scope *()> EnterScope) { if (!D) return 0; + AdjustDeclIfTemplate(D); - // The order of template parameters is not important here. All names - // get added to the same scope. + // In order to get name lookup right, reenter template scopes in order from + // outermost to innermost. SmallVector<TemplateParameterList *, 4> ParameterLists; - - if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) - D = TD->getTemplatedDecl(); - - if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) - ParameterLists.push_back(PSD->getTemplateParameters()); + DeclContext *LookupDC = dyn_cast<DeclContext>(D); if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) { for (unsigned i = 0; i < DD->getNumTemplateParameterLists(); ++i) @@ -9641,31 +9968,49 @@ unsigned Sema::ActOnReenterTemplateScope(Scope *S, Decl *D) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FunctionTemplateDecl *FTD = FD->getDescribedFunctionTemplate()) ParameterLists.push_back(FTD->getTemplateParameters()); - } - } + } else if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + LookupDC = VD->getDeclContext(); - if (TagDecl *TD = dyn_cast<TagDecl>(D)) { + if (VarTemplateDecl *VTD = VD->getDescribedVarTemplate()) + ParameterLists.push_back(VTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast<VarTemplatePartialSpecializationDecl>(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); + } + } else if (TagDecl *TD = dyn_cast<TagDecl>(D)) { for (unsigned i = 0; i < TD->getNumTemplateParameterLists(); ++i) ParameterLists.push_back(TD->getTemplateParameterList(i)); if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(TD)) { if (ClassTemplateDecl *CTD = RD->getDescribedClassTemplate()) ParameterLists.push_back(CTD->getTemplateParameters()); + else if (auto *PSD = dyn_cast<ClassTemplatePartialSpecializationDecl>(D)) + ParameterLists.push_back(PSD->getTemplateParameters()); } } + // FIXME: Alias declarations and concepts. unsigned Count = 0; + Scope *InnermostTemplateScope = nullptr; for (TemplateParameterList *Params : ParameterLists) { - if (Params->size() > 0) - // Ignore explicit specializations; they don't contribute to the template - // depth. - ++Count; + // Ignore explicit specializations; they don't contribute to the template + // depth. + if (Params->size() == 0) + continue; + + InnermostTemplateScope = EnterScope(); for (NamedDecl *Param : *Params) { if (Param->getDeclName()) { - S->AddDecl(Param); + InnermostTemplateScope->AddDecl(Param); IdResolver.AddDecl(Param); } } + ++Count; + } + + // Associate the new template scopes with the corresponding entities. + if (InnermostTemplateScope) { + assert(LookupDC && "no enclosing DeclContext for template lookup"); + EnterTemplatedContext(InnermostTemplateScope, LookupDC); } return Count; @@ -9717,11 +10062,6 @@ void Sema::ActOnDelayedCXXMethodParameter(Scope *S, Decl *ParamD) { ParmVarDecl *Param = cast<ParmVarDecl>(ParamD); - // If this parameter has an unparsed default argument, clear it out - // to make way for the parsed default argument. - if (Param->hasUnparsedDefaultArg()) - Param->setDefaultArg(nullptr); - S->AddDecl(Param); if (Param->getDeclName()) IdResolver.AddDecl(Param); @@ -9855,11 +10195,9 @@ void Sema::CheckConstructor(CXXConstructorDecl *Constructor) { // either there are no other parameters or else all other // parameters have default arguments. if (!Constructor->isInvalidDecl() && - ((Constructor->getNumParams() == 1) || - (Constructor->getNumParams() > 1 && - Constructor->getParamDecl(1)->hasDefaultArg())) && - Constructor->getTemplateSpecializationKind() - != TSK_ImplicitInstantiation) { + Constructor->hasOneParamOrDefaultArgs() && + Constructor->getTemplateSpecializationKind() != + TSK_ImplicitInstantiation) { QualType ParamType = Constructor->getParamDecl(0)->getType(); QualType ClassTy = Context.getTagDeclType(ClassDecl); if (Context.getCanonicalType(ParamType).getUnqualifiedType() == ClassTy) { @@ -9944,12 +10282,12 @@ QualType Sema::CheckDestructorDeclarator(Declarator &D, QualType R, // declaration. QualType DeclaratorType = GetTypeFromParser(D.getName().DestructorName); if (const TypedefType *TT = DeclaratorType->getAs<TypedefType>()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << isa<TypeAliasDecl>(TT->getDecl()); else if (const TemplateSpecializationType *TST = DeclaratorType->getAs<TemplateSpecializationType>()) if (TST->isTypeAlias()) - Diag(D.getIdentifierLoc(), diag::err_destructor_typedef_name) + Diag(D.getIdentifierLoc(), diag::ext_destructor_typedef_name) << DeclaratorType << 1; // C++ [class.dtor]p2: @@ -10211,7 +10549,7 @@ void Sema::CheckConversionDeclarator(Declarator &D, QualType &R, R = Context.getFunctionType(ConvType, None, Proto->getExtProtoInfo()); // C++0x explicit conversion operators. - if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus2a) + if (DS.hasExplicitSpecifier() && !getLangOpts().CPlusPlus20) Diag(DS.getExplicitSpecLoc(), getLangOpts().CPlusPlus11 ? diag::warn_cxx98_compat_explicit_conversion_functions @@ -10230,15 +10568,12 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { // Make sure we aren't redeclaring the conversion function. QualType ConvType = Context.getCanonicalType(Conversion->getConversionType()); - // C++ [class.conv.fct]p1: // [...] A conversion function is never used to convert a // (possibly cv-qualified) object to the (possibly cv-qualified) // same object type (or a reference to it), to a (possibly // cv-qualified) base class of that type (or a reference to it), // or to (possibly cv-qualified) void. - // FIXME: Suppress this warning if the conversion function ends up being a - // virtual function that overrides a virtual function in a base class. QualType ClassType = Context.getCanonicalType(Context.getTypeDeclType(ClassDecl)); if (const ReferenceType *ConvTypeRef = ConvType->getAs<ReferenceType>()) @@ -10246,6 +10581,8 @@ Decl *Sema::ActOnConversionDeclarator(CXXConversionDecl *Conversion) { if (Conversion->getTemplateSpecializationKind() != TSK_Undeclared && Conversion->getTemplateSpecializationKind() != TSK_ExplicitSpecialization) /* Suppress diagnostics for instantiations. */; + else if (Conversion->size_overridden_methods() != 0) + /* Suppress diagnostics for overriding virtual function in a base class. */; else if (ConvType->isRecordType()) { ConvType = Context.getCanonicalType(ConvType).getUnqualifiedType(); if (ConvType == ClassType) @@ -10920,8 +11257,7 @@ bool Sema::isInitListConstructor(const FunctionDecl *Ctor) { // is of type std::initializer_list<E> or reference to possibly cv-qualified // std::initializer_list<E> for some type E, and either there are no other // parameters or else all other parameters have default arguments. - if (Ctor->getNumParams() < 1 || - (Ctor->getNumParams() > 1 && !Ctor->getParamDecl(1)->hasDefaultArg())) + if (!Ctor->hasOneParamOrDefaultArgs()) return false; QualType ArgType = Ctor->getParamDecl(0)->getType(); @@ -12960,6 +13296,25 @@ void Sema::DefineImplicitDestructor(SourceLocation CurrentLocation, } } +void Sema::CheckCompleteDestructorVariant(SourceLocation CurrentLocation, + CXXDestructorDecl *Destructor) { + if (Destructor->isInvalidDecl()) + return; + + CXXRecordDecl *ClassDecl = Destructor->getParent(); + assert(Context.getTargetInfo().getCXXABI().isMicrosoft() && + "implicit complete dtors unneeded outside MS ABI"); + assert(ClassDecl->getNumVBases() > 0 && + "complete dtor only exists for classes with vbases"); + + SynthesizedFunctionScope Scope(*this, Destructor); + + // Add a context note for diagnostics produced after this point. + Scope.addContextNote(CurrentLocation); + + MarkVirtualBaseDestructorsReferenced(Destructor->getLocation(), ClassDecl); +} + /// Perform any semantic analysis which needs to be delayed until all /// pending class member declarations have been parsed. void Sema::ActOnFinishCXXMemberDecls() { @@ -12981,7 +13336,7 @@ void Sema::ActOnFinishCXXNonNestedClass() { SmallVector<CXXMethodDecl*, 4> WorkList; std::swap(DelayedDllExportMemberFunctions, WorkList); for (CXXMethodDecl *M : WorkList) { - DefineImplicitSpecialMember(*this, M, M->getLocation()); + DefineDefaultedFunction(*this, M, M->getLocation()); // Pass the method to the consumer to get emitted. This is not necessary // for explicit instantiation definitions, as they will get emitted @@ -13180,13 +13535,13 @@ buildMemcpyForAssignmentOp(Sema &S, SourceLocation Loc, QualType T, // directly construct UnaryOperators here because semantic analysis // does not permit us to take the address of an xvalue. Expr *From = FromB.build(S, Loc); - From = new (S.Context) UnaryOperator(From, UO_AddrOf, - S.Context.getPointerType(From->getType()), - VK_RValue, OK_Ordinary, Loc, false); + From = UnaryOperator::Create( + S.Context, From, UO_AddrOf, S.Context.getPointerType(From->getType()), + VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); Expr *To = ToB.build(S, Loc); - To = new (S.Context) UnaryOperator(To, UO_AddrOf, - S.Context.getPointerType(To->getType()), - VK_RValue, OK_Ordinary, Loc, false); + To = UnaryOperator::Create( + S.Context, To, UO_AddrOf, S.Context.getPointerType(To->getType()), + VK_RValue, OK_Ordinary, Loc, false, S.CurFPFeatureOverrides()); const Type *E = T->getBaseElementTypeUnsafe(); bool NeedsCollectableMemCpy = @@ -13420,18 +13775,17 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, // Create the comparison against the array bound. llvm::APInt Upper = ArrayTy->getSize().zextOrTrunc(S.Context.getTypeSize(SizeType)); - Expr *Comparison - = new (S.Context) BinaryOperator(IterationVarRefRVal.build(S, Loc), - IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), - BO_NE, S.Context.BoolTy, - VK_RValue, OK_Ordinary, Loc, FPOptions()); + Expr *Comparison = BinaryOperator::Create( + S.Context, IterationVarRefRVal.build(S, Loc), + IntegerLiteral::Create(S.Context, Upper, SizeType, Loc), BO_NE, + S.Context.BoolTy, VK_RValue, OK_Ordinary, Loc, S.CurFPFeatureOverrides()); // Create the pre-increment of the iteration variable. We can determine // whether the increment will overflow based on the value of the array // bound. - Expr *Increment = new (S.Context) - UnaryOperator(IterationVarRef.build(S, Loc), UO_PreInc, SizeType, - VK_LValue, OK_Ordinary, Loc, Upper.isMaxValue()); + Expr *Increment = UnaryOperator::Create( + S.Context, IterationVarRef.build(S, Loc), UO_PreInc, SizeType, VK_LValue, + OK_Ordinary, Loc, Upper.isMaxValue(), S.CurFPFeatureOverrides()); // Construct the loop that copies all elements of this array. return S.ActOnForStmt( @@ -13529,8 +13883,10 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); - if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) + if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) { + ClassDecl->setImplicitCopyAssignmentIsDeleted(); SetDeclDeleted(CopyAssignment, ClassLoc); + } if (S) PushOnScopeChains(CopyAssignment, S, false); @@ -14642,13 +14998,18 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, MarkFunctionReferenced(ConstructLoc, Constructor); if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) return ExprError(); + if (getLangOpts().SYCLIsDevice && + !checkSYCLDeviceFunction(ConstructLoc, Constructor)) + return ExprError(); - return CXXConstructExpr::Create( - Context, DeclInitType, ConstructLoc, Constructor, Elidable, - ExprArgs, HadMultipleCandidates, IsListInitialization, - IsStdInitListInitialization, RequiresZeroInit, - static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), - ParenRange); + return CheckForImmediateInvocation( + CXXConstructExpr::Create( + Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs, + HadMultipleCandidates, IsListInitialization, + IsStdInitListInitialization, RequiresZeroInit, + static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), + ParenRange), + Constructor); } ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { @@ -14726,6 +15087,10 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { if (VD->isInvalidDecl()) return; + // If initializing the variable failed, don't also diagnose problems with + // the desctructor, they're likely related. + if (VD->getInit() && VD->getInit()->containsErrors()) + return; CXXRecordDecl *ClassDecl = cast<CXXRecordDecl>(Record->getDecl()); if (ClassDecl->isInvalidDecl()) return; @@ -14752,10 +15117,13 @@ void Sema::FinalizeVarWithDestructor(VarDecl *VD, const RecordType *Record) { // If the destructor is constexpr, check whether the variable has constant // destruction now. - if (Destructor->isConstexpr() && VD->getInit() && - !VD->getInit()->isValueDependent() && VD->evaluateValue()) { + if (Destructor->isConstexpr()) { + bool HasConstantInit = false; + if (VD->getInit() && !VD->getInit()->isValueDependent()) + HasConstantInit = VD->evaluateValue(); SmallVector<PartialDiagnosticAt, 8> Notes; - if (!VD->evaluateDestruction(Notes) && VD->isConstexpr()) { + if (!VD->evaluateDestruction(Notes) && VD->isConstexpr() && + HasConstantInit) { Diag(VD->getLocation(), diag::err_constexpr_var_requires_const_destruction) << VD; for (unsigned I = 0, N = Notes.size(); I != N; ++I) @@ -14855,12 +15223,6 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, QualType ResultType = FnDecl->getType()->castAs<FunctionType>()->getReturnType(); - // Check that the result type is not dependent. - if (ResultType->isDependentType()) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_new_delete_dependent_result_type) - << FnDecl->getDeclName() << ExpectedResultType; - // The operator is valid on any address space for OpenCL. if (SemaRef.getLangOpts().OpenCLCPlusPlus) { if (auto *PtrTy = ResultType->getAs<PointerType>()) { @@ -14869,10 +15231,16 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, } // Check that the result type is what we expect. - if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) - return SemaRef.Diag(FnDecl->getLocation(), - diag::err_operator_new_delete_invalid_result_type) - << FnDecl->getDeclName() << ExpectedResultType; + if (SemaRef.Context.getCanonicalType(ResultType) != ExpectedResultType) { + // Reject even if the type is dependent; an operator delete function is + // required to have a non-dependent result type. + return SemaRef.Diag( + FnDecl->getLocation(), + ResultType->isDependentType() + ? diag::err_operator_new_delete_dependent_result_type + : diag::err_operator_new_delete_invalid_result_type) + << FnDecl->getDeclName() << ExpectedResultType; + } // A function template must have at least 2 parameters. if (FnDecl->getDescribedFunctionTemplate() && FnDecl->getNumParams() < 2) @@ -14886,13 +15254,7 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, diag::err_operator_new_delete_too_few_parameters) << FnDecl->getDeclName(); - // Check the first parameter type is not dependent. QualType FirstParamType = FnDecl->getParamDecl(0)->getType(); - if (FirstParamType->isDependentType()) - return SemaRef.Diag(FnDecl->getLocation(), DependentParamTypeDiag) - << FnDecl->getDeclName() << ExpectedFirstParamType; - - // Check that the first parameter type is what we expect. if (SemaRef.getLangOpts().OpenCLCPlusPlus) { // The operator is valid on any address space for OpenCL. if (auto *PtrTy = @@ -14900,10 +15262,18 @@ CheckOperatorNewDeleteTypes(Sema &SemaRef, const FunctionDecl *FnDecl, FirstParamType = RemoveAddressSpaceFromPtr(SemaRef, PtrTy); } } + + // Check that the first parameter type is what we expect. if (SemaRef.Context.getCanonicalType(FirstParamType).getUnqualifiedType() != - ExpectedFirstParamType) - return SemaRef.Diag(FnDecl->getLocation(), InvalidParamTypeDiag) - << FnDecl->getDeclName() << ExpectedFirstParamType; + ExpectedFirstParamType) { + // The first parameter type is not allowed to be dependent. As a tentative + // DR resolution, we allow a dependent parameter type if it is the right + // type anyway, to allow destroying operator delete in class templates. + return SemaRef.Diag(FnDecl->getLocation(), FirstParamType->isDependentType() + ? DependentParamTypeDiag + : InvalidParamTypeDiag) + << FnDecl->getDeclName() << ExpectedFirstParamType; + } return false; } @@ -15442,6 +15812,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, !BaseType->isDependentType() && RequireCompleteType(Loc, BaseType, DK)) Invalid = true; + if (!Invalid && Mode != 1 && BaseType->isSizelessType()) { + Diag(Loc, diag::err_catch_sizeless) << (Mode == 2 ? 1 : 0) << BaseType; + Invalid = true; + } + if (!Invalid && !ExDeclType->isDependentType() && RequireNonAbstractType(Loc, ExDeclType, diag::err_abstract_type_in_decl, @@ -16304,9 +16679,16 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Diag(Prev->getLocation().isInvalid() ? DelLoc : Prev->getLocation(), Prev->isImplicit() ? diag::note_previous_implicit_declaration : diag::note_previous_declaration); + // We can't recover from this; the declaration might have already + // been used. + Fn->setInvalidDecl(); + return; } - // If the declaration wasn't the first, we delete the function anyway for - // recovery. + + // To maintain the invariant that functions are only deleted on their first + // declaration, mark the implicitly-instantiated declaration of the + // explicitly-specialized function as deleted instead of marking the + // instantiated redeclaration. Fn = Fn->getCanonicalDecl(); } @@ -16316,9 +16698,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Fn->setInvalidDecl(); } - if (Fn->isDeleted()) - return; - // C++11 [basic.start.main]p3: // A program that defines main as deleted [...] is ill-formed. if (Fn->isMain()) @@ -16328,25 +16707,6 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // A deleted function is implicitly inline. Fn->setImplicitlyInline(); Fn->setDeletedAsWritten(); - - // See if we're deleting a function which is already known to override a - // non-deleted virtual function. - if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { - bool IssuedDiagnostic = false; - for (const CXXMethodDecl *O : MD->overridden_methods()) { - if (!(*MD->begin_overridden_methods())->isDeleted()) { - if (!IssuedDiagnostic) { - Diag(DelLoc, diag::err_deleted_override) << MD->getDeclName(); - IssuedDiagnostic = true; - } - Diag(O->getLocation(), diag::note_overridden_virtual_function); - } - } - // If this function was implicitly deleted because it was defaulted, - // explain why it was deleted. - if (IssuedDiagnostic && MD->isDefaulted()) - DiagnoseDeletedDefaultedFunction(MD); - } } void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { @@ -16363,7 +16723,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { } Diag(DefaultLoc, diag::err_default_special_members) - << getLangOpts().CPlusPlus2a; + << getLangOpts().CPlusPlus20; return; } @@ -16377,7 +16737,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { (!isa<CXXConstructorDecl>(FD) && FD->getDeclName().getCXXOverloadedOperator() != OO_Equal))) { Diag(DefaultLoc, diag::err_default_special_members) - << getLangOpts().CPlusPlus2a; + << getLangOpts().CPlusPlus20; return; } @@ -16392,7 +16752,7 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // 'operator<=>' when parsing the '<=>' token. if (DefKind.isComparison() && DefKind.asComparison() != DefaultedComparisonKind::ThreeWay) { - Diag(DefaultLoc, getLangOpts().CPlusPlus2a + Diag(DefaultLoc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_defaulted_comparison : diag::ext_defaulted_comparison); } @@ -16428,10 +16788,12 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { if (Primary->getCanonicalDecl()->isDefaulted()) return; + // FIXME: Once we support defining comparisons out of class, check for a + // defaulted comparison here. if (CheckExplicitlyDefaultedSpecialMember(MD, DefKind.asSpecialMember())) MD->setInvalidDecl(); else - DefineImplicitSpecialMember(*this, MD, DefaultLoc); + DefineDefaultedFunction(*this, MD, DefaultLoc); } static void SearchForReturnInStmt(Sema &Self, Stmt *S) { @@ -16743,7 +17105,7 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, return; // Do not mark as used if compiling for the device outside of the target // region. - if (LangOpts.OpenMP && LangOpts.OpenMPIsDevice && + if (TUKind != TU_Prefix && LangOpts.OpenMP && LangOpts.OpenMPIsDevice && !isInOpenMPDeclareTargetContext() && !isInOpenMPTargetExecutionDirective()) { if (!DefinitionRequired) @@ -17386,3 +17748,50 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, return NewPD; } + +void Sema::ActOnStartFunctionDeclarationDeclarator( + Declarator &Declarator, unsigned TemplateParameterDepth) { + auto &Info = InventedParameterInfos.emplace_back(); + TemplateParameterList *ExplicitParams = nullptr; + ArrayRef<TemplateParameterList *> ExplicitLists = + Declarator.getTemplateParameterLists(); + if (!ExplicitLists.empty()) { + bool IsMemberSpecialization, IsInvalid; + ExplicitParams = MatchTemplateParametersToScopeSpecifier( + Declarator.getBeginLoc(), Declarator.getIdentifierLoc(), + Declarator.getCXXScopeSpec(), /*TemplateId=*/nullptr, + ExplicitLists, /*IsFriend=*/false, IsMemberSpecialization, IsInvalid, + /*SuppressDiagnostic=*/true); + } + if (ExplicitParams) { + Info.AutoTemplateParameterDepth = ExplicitParams->getDepth(); + for (NamedDecl *Param : *ExplicitParams) + Info.TemplateParams.push_back(Param); + Info.NumExplicitTemplateParams = ExplicitParams->size(); + } else { + Info.AutoTemplateParameterDepth = TemplateParameterDepth; + Info.NumExplicitTemplateParams = 0; + } +} + +void Sema::ActOnFinishFunctionDeclarationDeclarator(Declarator &Declarator) { + auto &FSI = InventedParameterInfos.back(); + if (FSI.TemplateParams.size() > FSI.NumExplicitTemplateParams) { + if (FSI.NumExplicitTemplateParams != 0) { + TemplateParameterList *ExplicitParams = + Declarator.getTemplateParameterLists().back(); + Declarator.setInventedTemplateParameterList( + TemplateParameterList::Create( + Context, ExplicitParams->getTemplateLoc(), + ExplicitParams->getLAngleLoc(), FSI.TemplateParams, + ExplicitParams->getRAngleLoc(), + ExplicitParams->getRequiresClause())); + } else { + Declarator.setInventedTemplateParameterList( + TemplateParameterList::Create( + Context, SourceLocation(), SourceLocation(), FSI.TemplateParams, + SourceLocation(), /*RequiresClause=*/nullptr)); + } + } + InventedParameterInfos.pop_back(); +} diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp index 5fdf6aeed5b4..d376880a40e8 100644 --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -19,6 +19,7 @@ #include "clang/AST/ExprObjC.h" #include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -937,8 +938,7 @@ static bool checkTypeParamListConsistency(Sema &S, // Override the new type parameter's bound type with the previous type, // so that it's consistent. - newTypeParam->setTypeSourceInfo( - S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + S.Context.adjustObjCTypeParamBoundType(prevTypeParam, newTypeParam); continue; } @@ -965,8 +965,7 @@ static bool checkTypeParamListConsistency(Sema &S, } // Update the new type parameter's bound to match the previous one. - newTypeParam->setTypeSourceInfo( - S.Context.getTrivialTypeSourceInfo(prevTypeParam->getUnderlyingType())); + S.Context.adjustObjCTypeParamBoundType(prevTypeParam, newTypeParam); } return false; @@ -1273,7 +1272,8 @@ Decl *Sema::ActOnStartProtocolInterface( static bool NestedProtocolHasNoDefinition(ObjCProtocolDecl *PDecl, ObjCProtocolDecl *&UndefinedProtocol) { - if (!PDecl->hasDefinition() || PDecl->getDefinition()->isHidden()) { + if (!PDecl->hasDefinition() || + !PDecl->getDefinition()->isUnconditionallyVisible()) { UndefinedProtocol = PDecl; return true; } @@ -2360,7 +2360,7 @@ static bool CheckMethodOverrideReturn(Sema &S, : diag::warn_conflicting_ret_types; // Mismatches between ObjC pointers go into a different warning - // category, and sometimes they're even completely whitelisted. + // category, and sometimes they're even completely explicitly allowed. if (const ObjCObjectPointerType *ImplPtrTy = MethodImpl->getReturnType()->getAs<ObjCObjectPointerType>()) { if (const ObjCObjectPointerType *IfacePtrTy = @@ -2444,7 +2444,7 @@ static bool CheckMethodOverrideParam(Sema &S, : diag::warn_conflicting_param_types; // Mismatches between ObjC pointers go into a different warning - // category, and sometimes they're even completely whitelisted. + // category, and sometimes they're even completely explicitly allowed.. if (const ObjCObjectPointerType *ImplPtrTy = ImplTy->getAs<ObjCObjectPointerType>()) { if (const ObjCObjectPointerType *IfacePtrTy = @@ -3236,7 +3236,7 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, return false; // If either is hidden, it is not considered to match. - if (left->isHidden() || right->isHidden()) + if (!left->isUnconditionallyVisible() || !right->isUnconditionallyVisible()) return false; if (left->isDirectMethod() != right->isDirectMethod()) @@ -3495,7 +3495,7 @@ bool Sema::CollectMultipleMethodsInGlobalPool( ObjCMethodList &MethList = InstanceFirst ? Pos->second.first : Pos->second.second; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) - if (M->getMethod() && !M->getMethod()->isHidden()) { + if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) { if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) Methods.push_back(M->getMethod()); } @@ -3511,7 +3511,7 @@ bool Sema::CollectMultipleMethodsInGlobalPool( ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second : Pos->second.first; for (ObjCMethodList *M = &MethList2; M; M = M->getNext()) - if (M->getMethod() && !M->getMethod()->isHidden()) { + if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) { if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) Methods.push_back(M->getMethod()); } @@ -3558,7 +3558,7 @@ ObjCMethodDecl *Sema::LookupMethodInGlobalPool(Selector Sel, SourceRange R, ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; SmallVector<ObjCMethodDecl *, 4> Methods; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) { - if (M->getMethod() && !M->getMethod()->isHidden()) + if (M->getMethod() && M->getMethod()->isUnconditionallyVisible()) return M->getMethod(); } return nullptr; @@ -4580,6 +4580,62 @@ static void checkObjCMethodX86VectorTypes(Sema &SemaRef, << (Triple.isMacOSX() ? "macOS 10.11" : "iOS 9"); } +static void mergeObjCDirectMembers(Sema &S, Decl *CD, ObjCMethodDecl *Method) { + if (!Method->isDirectMethod() && !Method->hasAttr<UnavailableAttr>() && + CD->hasAttr<ObjCDirectMembersAttr>()) { + Method->addAttr( + ObjCDirectAttr::CreateImplicit(S.Context, Method->getLocation())); + } +} + +static void checkObjCDirectMethodClashes(Sema &S, ObjCInterfaceDecl *IDecl, + ObjCMethodDecl *Method, + ObjCImplDecl *ImpDecl = nullptr) { + auto Sel = Method->getSelector(); + bool isInstance = Method->isInstanceMethod(); + bool diagnosed = false; + + auto diagClash = [&](const ObjCMethodDecl *IMD) { + if (diagnosed || IMD->isImplicit()) + return; + if (Method->isDirectMethod() || IMD->isDirectMethod()) { + S.Diag(Method->getLocation(), diag::err_objc_direct_duplicate_decl) + << Method->isDirectMethod() << /* method */ 0 << IMD->isDirectMethod() + << Method->getDeclName(); + S.Diag(IMD->getLocation(), diag::note_previous_declaration); + diagnosed = true; + } + }; + + // Look for any other declaration of this method anywhere we can see in this + // compilation unit. + // + // We do not use IDecl->lookupMethod() because we have specific needs: + // + // - we absolutely do not need to walk protocols, because + // diag::err_objc_direct_on_protocol has already been emitted + // during parsing if there's a conflict, + // + // - when we do not find a match in a given @interface container, + // we need to attempt looking it up in the @implementation block if the + // translation unit sees it to find more clashes. + + if (auto *IMD = IDecl->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto *Impl = IDecl->getImplementation()) + if (Impl != ImpDecl) + if (auto *IMD = IDecl->getImplementation()->getMethod(Sel, isInstance)) + diagClash(IMD); + + for (const auto *Cat : IDecl->visible_categories()) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); + else if (auto CatImpl = Cat->getImplementation()) + if (CatImpl != ImpDecl) + if (auto *IMD = Cat->getMethod(Sel, isInstance)) + diagClash(IMD); +} + Decl *Sema::ActOnMethodDeclaration( Scope *S, SourceLocation MethodLoc, SourceLocation EndLoc, tok::TokenKind MethodType, ObjCDeclSpec &ReturnQT, ParsedType ReturnType, @@ -4808,9 +4864,9 @@ Decl *Sema::ActOnMethodDeclaration( Diag(ObjCMethod->getLocation(), diag::warn_dealloc_in_category) << ObjCMethod->getDeclName(); } - } else if (ImpDecl->hasAttr<ObjCDirectMembersAttr>()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); + } else { + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod, ImpDecl); } // Warn if a method declared in a protocol to which a category or @@ -4831,39 +4887,16 @@ Decl *Sema::ActOnMethodDeclaration( } } else { if (!isa<ObjCProtocolDecl>(ClassDecl)) { - if (!ObjCMethod->isDirectMethod() && - ClassDecl->hasAttr<ObjCDirectMembersAttr>()) { - ObjCMethod->addAttr( - ObjCDirectAttr::CreateImplicit(Context, ObjCMethod->getLocation())); - } + mergeObjCDirectMembers(*this, ClassDecl, ObjCMethod); - // There can be a single declaration in any @interface container - // for a given direct method, look for clashes as we add them. - // - // For valid code, we should always know the primary interface - // declaration by now, however for invalid code we'll keep parsing - // but we won't find the primary interface and IDecl will be nil. ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl); if (!IDecl) IDecl = cast<ObjCCategoryDecl>(ClassDecl)->getClassInterface(); - + // For valid code, we should always know the primary interface + // declaration by now, however for invalid code we'll keep parsing + // but we won't find the primary interface and IDecl will be nil. if (IDecl) - if (auto *IMD = IDecl->lookupMethod(ObjCMethod->getSelector(), - ObjCMethod->isInstanceMethod(), - /*shallowCategoryLookup=*/false, - /*followSuper=*/false)) { - if (isa<ObjCProtocolDecl>(IMD->getDeclContext())) { - // Do not emit a diagnostic for the Protocol case: - // diag::err_objc_direct_on_protocol has already been emitted - // during parsing for these with a nicer diagnostic. - } else if (ObjCMethod->isDirectMethod() || IMD->isDirectMethod()) { - Diag(ObjCMethod->getLocation(), - diag::err_objc_direct_duplicate_decl) - << ObjCMethod->isDirectMethod() << IMD->isDirectMethod() - << ObjCMethod->getDeclName(); - Diag(IMD->getLocation(), diag::note_previous_declaration); - } - } + checkObjCDirectMethodClashes(*this, IDecl, ObjCMethod); } cast<DeclContext>(ClassDecl)->addDecl(ObjCMethod); diff --git a/clang/lib/Sema/SemaExceptionSpec.cpp b/clang/lib/Sema/SemaExceptionSpec.cpp index 5aedbe7644e4..d7695f9d7d7a 100644 --- a/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/clang/lib/Sema/SemaExceptionSpec.cpp @@ -167,6 +167,14 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) return ReturnValueOnError; + // The MSVC compatibility mode doesn't extend to sizeless types, + // so diagnose them separately. + if (PointeeT->isSizelessType() && Kind != 1) { + Diag(Range.getBegin(), diag::err_sizeless_in_exception_spec) + << (Kind == 2 ? 1 : 0) << PointeeT << Range; + return true; + } + return false; } @@ -991,10 +999,8 @@ static CanThrowResult canSubStmtsThrow(Sema &Self, const Stmt *S) { return R; } -/// Determine whether the callee of a particular function call can throw. -/// E and D are both optional, but at least one of E and Loc must be specified. -static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, - SourceLocation Loc = SourceLocation()) { +CanThrowResult Sema::canCalleeThrow(Sema &S, const Expr *E, const Decl *D, + SourceLocation Loc) { // As an extension, we assume that __attribute__((nothrow)) functions don't // throw. if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) @@ -1040,7 +1046,8 @@ static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D, if (!FT) return CT_Can; - FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); + if (Loc.isValid() || (Loc.isInvalid() && E)) + FT = S.ResolveExceptionSpec(Loc.isInvalid() ? E->getBeginLoc() : Loc, FT); if (!FT) return CT_Can; @@ -1061,7 +1068,7 @@ static CanThrowResult canVarDeclThrow(Sema &Self, const VarDecl *VD) { VD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) { if (auto *Dtor = RD->getDestructor()) { CT = mergeCanThrow( - CT, canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); + CT, Sema::canCalleeThrow(Self, nullptr, Dtor, VD->getLocation())); } } } @@ -1281,6 +1288,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::CompoundLiteralExprClass: case Expr::CXXConstCastExprClass: + case Expr::CXXAddrspaceCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::BuiltinBitCastExprClass: // FIXME: Properly determine whether a variably-modified type can throw. @@ -1290,7 +1298,10 @@ CanThrowResult Sema::canThrow(const Stmt *S) { // Some might be dependent for other reasons. case Expr::ArraySubscriptExprClass: + case Expr::MatrixSubscriptExprClass: case Expr::OMPArraySectionExprClass: + case Expr::OMPArrayShapingExprClass: + case Expr::OMPIteratorExprClass: case Expr::BinaryOperatorClass: case Expr::DependentCoawaitExprClass: case Expr::CompoundAssignOperatorClass: @@ -1332,6 +1343,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::CXXUnresolvedConstructExprClass: case Expr::DependentScopeDeclRefExprClass: case Expr::CXXFoldExprClass: + case Expr::RecoveryExprClass: return CT_Dependent; case Expr::AsTypeExprClass: @@ -1386,6 +1398,7 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Expr::StringLiteralClass: case Expr::SourceLocExprClass: case Expr::ConceptSpecializationExprClass: + case Expr::RequiresExprClass: // These expressions can never throw. return CT_Cannot; @@ -1429,6 +1442,8 @@ CanThrowResult Sema::canThrow(const Stmt *S) { case Stmt::OMPDistributeParallelForSimdDirectiveClass: case Stmt::OMPDistributeSimdDirectiveClass: case Stmt::OMPFlushDirectiveClass: + case Stmt::OMPDepobjDirectiveClass: + case Stmt::OMPScanDirectiveClass: case Stmt::OMPForDirectiveClass: case Stmt::OMPForSimdDirectiveClass: case Stmt::OMPMasterDirectiveClass: diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 5f4071924d3f..ccae79636f32 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -11,6 +11,7 @@ //===----------------------------------------------------------------------===// #include "TreeTransform.h" +#include "UsedDeclVisitor.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" @@ -46,8 +47,10 @@ #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/Support/ConvertUTF.h" +#include "llvm/Support/SaveAndRestore.h" using namespace clang; using namespace sema; +using llvm::RoundingMode; /// Determine whether the use of this declaration is valid, without /// emitting diagnostics. @@ -245,8 +248,8 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, return true; } - // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { + // See if this is a deleted function. if (FD->isDeleted()) { auto *Ctor = dyn_cast<CXXConstructorDecl>(FD); if (Ctor && Ctor->isInheritingConstructor()) @@ -259,6 +262,29 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, return true; } + // [expr.prim.id]p4 + // A program that refers explicitly or implicitly to a function with a + // trailing requires-clause whose constraint-expression is not satisfied, + // other than to declare it, is ill-formed. [...] + // + // See if this is a function with constraints that need to be satisfied. + // Check this before deducing the return type, as it might instantiate the + // definition. + if (FD->getTrailingRequiresClause()) { + ConstraintSatisfaction Satisfaction; + if (CheckFunctionConstraints(FD, Satisfaction, Loc)) + // A diagnostic will have already been generated (non-constant + // constraint expression, for example) + return true; + if (!Satisfaction.IsSatisfied) { + Diag(Loc, + diag::err_reference_to_function_with_unsatisfied_constraints) + << D; + DiagnoseUnsatisfiedConstraint(Satisfaction); + return true; + } + } + // If the function has a deduced return type, and we can't deduce it, // then we can't use it either. if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && @@ -267,6 +293,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) return true; + + if (getLangOpts().SYCLIsDevice && !checkSYCLDeviceFunction(Loc, FD)) + return true; } if (auto *MD = dyn_cast<CXXMethodDecl>(D)) { @@ -326,28 +355,25 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, ArrayRef<SourceLocation> Locs, diagnoseUseOfInternalDeclInInlineFunction(*this, D, Loc); - // [expr.prim.id]p4 - // A program that refers explicitly or implicitly to a function with a - // trailing requires-clause whose constraint-expression is not satisfied, - // other than to declare it, is ill-formed. [...] - // - // See if this is a function with constraints that need to be satisfied. - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - if (Expr *RC = FD->getTrailingRequiresClause()) { - ConstraintSatisfaction Satisfaction; - bool Failed = CheckConstraintSatisfaction(RC, Satisfaction); - if (Failed) - // A diagnostic will have already been generated (non-constant - // constraint expression, for example) - return true; - if (!Satisfaction.IsSatisfied) { - Diag(Loc, - diag::err_reference_to_function_with_unsatisfied_constraints) - << D; - DiagnoseUnsatisfiedConstraint(Satisfaction); - return true; - } - } + if (LangOpts.SYCLIsDevice || (LangOpts.OpenMP && LangOpts.OpenMPIsDevice)) { + if (const auto *VD = dyn_cast<ValueDecl>(D)) + checkDeviceDecl(VD, Loc); + + if (!Context.getTargetInfo().isTLSSupported()) + if (const auto *VD = dyn_cast<VarDecl>(D)) + if (VD->getTLSKind() != VarDecl::TLS_None) + targetDiag(*Locs.begin(), diag::err_thread_unsupported); + } + + if (isa<ParmVarDecl>(D) && isa<RequiresExprBodyDecl>(D->getDeclContext()) && + !isUnevaluatedContext()) { + // C++ [expr.prim.req.nested] p3 + // A local parameter shall only appear as an unevaluated operand + // (Clause 8) within the constraint-expression. + Diag(Loc, diag::err_requires_expr_parameter_referenced_in_evaluated_context) + << D; + Diag(D->getLocation(), diag::note_entity_declared_at) << D; + return true; } return false; @@ -593,6 +619,10 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { QualType T = E->getType(); assert(!T.isNull() && "r-value conversion on typeless expression?"); + // lvalue-to-rvalue conversion cannot be applied to function or array types. + if (T->isFunctionType() || T->isArrayType()) + return E; + // We don't want to throw lvalue-to-rvalue casts on top of // expressions of certain types in C++. if (getLangOpts().CPlusPlus && @@ -661,6 +691,9 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { if (E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) Cleanup.setExprNeedsCleanups(true); + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + // C++ [conv.lval]p3: // If T is cv std::nullptr_t, the result is a null pointer constant. CastKind CK = T->isNullPtrType() ? CK_NullToPointer : CK_LValueToRValue; @@ -697,7 +730,7 @@ ExprResult Sema::CallExprUnaryConversions(Expr *E) { // to function type. if (Ty->isFunctionType()) { Res = ImpCastExprToType(E, Context.getPointerType(Ty), - CK_FunctionToPointerDecay).get(); + CK_FunctionToPointerDecay); if (Res.isInvalid()) return ExprError(); } @@ -931,6 +964,11 @@ ExprResult Sema::DefaultVariadicArgumentPromotion(Expr *E, VariadicCallType CT, ExprResult ExprRes = DefaultArgumentPromotion(E); if (ExprRes.isInvalid()) return ExprError(); + + // Copy blocks to the heap. + if (ExprRes.get()->getType()->isBlockPointerType()) + maybeExtendBlockObject(ExprRes); + E = ExprRes.get(); // Diagnostics regarding non-POD argument types are @@ -1375,8 +1413,8 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, bool IsCompAssign = ACK == Sema::ACK_CompAssign; if ((!IsCompAssign && LEnum && R->isFloatingType()) || (REnum && L->isFloatingType())) { - S.Diag(Loc, S.getLangOpts().CPlusPlus2a - ? diag::warn_arith_conv_enum_float_cxx2a + S.Diag(Loc, S.getLangOpts().CPlusPlus20 + ? diag::warn_arith_conv_enum_float_cxx20 : diag::warn_arith_conv_enum_float) << LHS->getSourceRange() << RHS->getSourceRange() << (int)ACK << LEnum << L << R; @@ -1388,24 +1426,24 @@ static void checkEnumArithmeticConversions(Sema &S, Expr *LHS, Expr *RHS, // If either enumeration type is unnamed, it's less likely that the // user cares about this, but this situation is still deprecated in // C++2a. Use a different warning group. - DiagID = S.getLangOpts().CPlusPlus2a - ? diag::warn_arith_conv_mixed_anon_enum_types_cxx2a + DiagID = S.getLangOpts().CPlusPlus20 + ? diag::warn_arith_conv_mixed_anon_enum_types_cxx20 : diag::warn_arith_conv_mixed_anon_enum_types; } else if (ACK == Sema::ACK_Conditional) { // Conditional expressions are separated out because they have // historically had a different warning flag. - DiagID = S.getLangOpts().CPlusPlus2a - ? diag::warn_conditional_mixed_enum_types_cxx2a + DiagID = S.getLangOpts().CPlusPlus20 + ? diag::warn_conditional_mixed_enum_types_cxx20 : diag::warn_conditional_mixed_enum_types; } else if (ACK == Sema::ACK_Comparison) { // Comparison expressions are separated out because they have // historically had a different warning flag. - DiagID = S.getLangOpts().CPlusPlus2a - ? diag::warn_comparison_mixed_enum_types_cxx2a + DiagID = S.getLangOpts().CPlusPlus20 + ? diag::warn_comparison_mixed_enum_types_cxx20 : diag::warn_comparison_mixed_enum_types; } else { - DiagID = S.getLangOpts().CPlusPlus2a - ? diag::warn_arith_conv_mixed_enum_types_cxx2a + DiagID = S.getLangOpts().CPlusPlus20 + ? diag::warn_arith_conv_mixed_enum_types_cxx20 : diag::warn_arith_conv_mixed_enum_types; } S.Diag(Loc, DiagID) << LHS->getSourceRange() << RHS->getSourceRange() @@ -1466,6 +1504,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, if (LHSType == RHSType) return LHSType; + // ExtInt types aren't subject to conversions between them or normal integers, + // so this fails. + if(LHSType->isExtIntType() || RHSType->isExtIntType()) + return QualType(); + // At this point, we have two different arithmetic types. // Diagnose attempts to convert between __float128 and long double where @@ -1750,15 +1793,15 @@ Sema::ActOnStringLiteral(ArrayRef<Token> StringToks, Scope *UDLScope) { // Warn on initializing an array of char from a u8 string literal; this // becomes ill-formed in C++2a. - if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus2a && + if (getLangOpts().CPlusPlus && !getLangOpts().CPlusPlus20 && !getLangOpts().Char8 && Kind == StringLiteral::UTF8) { - Diag(StringTokLocs.front(), diag::warn_cxx2a_compat_utf8_string); + Diag(StringTokLocs.front(), diag::warn_cxx20_compat_utf8_string); // Create removals for all 'u8' prefixes in the string literal(s). This // ensures C++2a compatibility (but may change the program behavior when // built by non-Clang compilers for which the execution character set is // not always UTF-8). - auto RemovalDiag = PDiag(diag::note_cxx2a_compat_utf8_string_remove_u8); + auto RemovalDiag = PDiag(diag::note_cxx20_compat_utf8_string_remove_u8); SourceLocation RemovalDiagLoc; for (const Token &Tok : StringToks) { if (Tok.getKind() == tok::utf8_string_literal) { @@ -3113,6 +3156,11 @@ ExprResult Sema::BuildDeclarationNameExpr( return ExprError(); ExprValueKind valueKind = VK_RValue; + // In 'T ...V;', the type of the declaration 'V' is 'T...', but the type of + // a reference to 'V' is simply (unexpanded) 'T'. The type, like the value, + // is expanded by some outer '...' in the context of the use. + type = type.getNonPackExpansionType(); + switch (D->getKind()) { // Ignore all the non-ValueDecl kinds. #define ABSTRACT_DECL(kind) @@ -3258,6 +3306,9 @@ ExprResult Sema::BuildDeclarationNameExpr( llvm_unreachable("building reference to deduction guide"); case Decl::MSProperty: + case Decl::MSGuid: + // FIXME: Should MSGuidDecl be subject to capture in OpenMP, + // or duplicated between host and device? valueKind = VK_LValue; break; @@ -3358,6 +3409,70 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc, return PredefinedExpr::Create(Context, Loc, ResTy, IK, SL); } +static std::pair<QualType, StringLiteral *> +GetUniqueStableNameInfo(ASTContext &Context, QualType OpType, + SourceLocation OpLoc, PredefinedExpr::IdentKind K) { + std::pair<QualType, StringLiteral*> Result{{}, nullptr}; + + if (OpType->isDependentType()) { + Result.first = Context.DependentTy; + return Result; + } + + std::string Str = PredefinedExpr::ComputeName(Context, K, OpType); + llvm::APInt Length(32, Str.length() + 1); + Result.first = + Context.adjustStringLiteralBaseType(Context.CharTy.withConst()); + Result.first = Context.getConstantArrayType( + Result.first, Length, nullptr, ArrayType::Normal, /*IndexTypeQuals*/ 0); + Result.second = StringLiteral::Create(Context, Str, StringLiteral::Ascii, + /*Pascal*/ false, Result.first, OpLoc); + return Result; +} + +ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, + TypeSourceInfo *Operand) { + QualType ResultTy; + StringLiteral *SL; + std::tie(ResultTy, SL) = GetUniqueStableNameInfo( + Context, Operand->getType(), OpLoc, PredefinedExpr::UniqueStableNameType); + + return PredefinedExpr::Create(Context, OpLoc, ResultTy, + PredefinedExpr::UniqueStableNameType, SL, + Operand); +} + +ExprResult Sema::BuildUniqueStableName(SourceLocation OpLoc, + Expr *E) { + QualType ResultTy; + StringLiteral *SL; + std::tie(ResultTy, SL) = GetUniqueStableNameInfo( + Context, E->getType(), OpLoc, PredefinedExpr::UniqueStableNameExpr); + + return PredefinedExpr::Create(Context, OpLoc, ResultTy, + PredefinedExpr::UniqueStableNameExpr, SL, E); +} + +ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation L, SourceLocation R, + ParsedType Ty) { + TypeSourceInfo *TInfo = nullptr; + QualType T = GetTypeFromParser(Ty, &TInfo); + + if (T.isNull()) + return ExprError(); + if (!TInfo) + TInfo = Context.getTrivialTypeSourceInfo(T, OpLoc); + + return BuildUniqueStableName(OpLoc, TInfo); +} + +ExprResult Sema::ActOnUniqueStableNameExpr(SourceLocation OpLoc, + SourceLocation L, SourceLocation R, + Expr *E) { + return BuildUniqueStableName(OpLoc, E); +} + ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) { PredefinedExpr::IdentKind IK; @@ -3519,7 +3634,9 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Invalid) return ExprError(); - NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), PP); + NumericLiteralParser Literal(TokSpelling, Tok.getLocation(), + PP.getSourceManager(), PP.getLangOpts(), + PP.getTargetInfo(), PP.getDiagnostics()); if (Literal.hadError) return ExprError(); @@ -3872,7 +3989,7 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T, TraitKind == UETT_PreferredAlignOf)) { // sizeof(function)/alignof(function) is allowed as an extension. S.Diag(Loc, diag::ext_sizeof_alignof_function_type) - << TraitKind << ArgRange; + << getTraitSpelling(TraitKind) << ArgRange; return false; } @@ -3881,7 +3998,7 @@ static bool CheckExtensionTraitOperandType(Sema &S, QualType T, if (T->isVoidType()) { unsigned DiagID = S.LangOpts.OpenCL ? diag::err_opencl_sizeof_alignof_type : diag::ext_sizeof_alignof_void_type; - S.Diag(Loc, DiagID) << TraitKind << ArgRange; + S.Diag(Loc, DiagID) << getTraitSpelling(TraitKind) << ArgRange; return false; } @@ -3948,7 +4065,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, return CheckVecStepTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange()); - // Whitelist some types as extensions + // Explicitly list some types as extensions. if (!CheckExtensionTraitOperandType(*this, ExprTy, E->getExprLoc(), E->getSourceRange(), ExprKind)) return false; @@ -3958,14 +4075,15 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, // be complete (and will attempt to complete it if it's an array of unknown // bound). if (ExprKind == UETT_AlignOf || ExprKind == UETT_PreferredAlignOf) { - if (RequireCompleteType(E->getExprLoc(), - Context.getBaseElementType(E->getType()), - diag::err_sizeof_alignof_incomplete_type, ExprKind, - E->getSourceRange())) + if (RequireCompleteSizedType( + E->getExprLoc(), Context.getBaseElementType(E->getType()), + diag::err_sizeof_alignof_incomplete_or_sizeless_type, + getTraitSpelling(ExprKind), E->getSourceRange())) return true; } else { - if (RequireCompleteExprType(E, diag::err_sizeof_alignof_incomplete_type, - ExprKind, E->getSourceRange())) + if (RequireCompleteSizedExprType( + E, diag::err_sizeof_alignof_incomplete_or_sizeless_type, + getTraitSpelling(ExprKind), E->getSourceRange())) return true; } @@ -3975,7 +4093,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(Expr *E, if (ExprTy->isFunctionType()) { Diag(E->getExprLoc(), diag::err_sizeof_alignof_function_type) - << ExprKind << E->getSourceRange(); + << getTraitSpelling(ExprKind) << E->getSourceRange(); return true; } @@ -4057,19 +4175,19 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType, if (ExprKind == UETT_VecStep) return CheckVecStepTraitOperandType(*this, ExprType, OpLoc, ExprRange); - // Whitelist some types as extensions + // Explicitly list some types as extensions. if (!CheckExtensionTraitOperandType(*this, ExprType, OpLoc, ExprRange, ExprKind)) return false; - if (RequireCompleteType(OpLoc, ExprType, - diag::err_sizeof_alignof_incomplete_type, - ExprKind, ExprRange)) + if (RequireCompleteSizedType( + OpLoc, ExprType, diag::err_sizeof_alignof_incomplete_or_sizeless_type, + getTraitSpelling(ExprKind), ExprRange)) return true; if (ExprType->isFunctionType()) { Diag(OpLoc, diag::err_sizeof_alignof_function_type) - << ExprKind << ExprRange; + << getTraitSpelling(ExprKind) << ExprRange; return true; } @@ -4168,6 +4286,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::Complex: case Type::Vector: case Type::ExtVector: + case Type::ConstantMatrix: case Type::Record: case Type::Enum: case Type::Elaborated: @@ -4177,6 +4296,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::ObjCObjectPointer: case Type::ObjCTypeParam: case Type::Pipe: + case Type::ExtInt: llvm_unreachable("type class is never variably-modified!"); case Type::Adjusted: T = cast<AdjustedType>(Ty)->getOriginalType(); @@ -4442,7 +4562,8 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, if (base && !base->getType().isNull() && base->getType()->isSpecificPlaceholderType(BuiltinType::OMPArraySection)) return ActOnOMPArraySectionExpr(base, lbLoc, idx, SourceLocation(), - /*Length=*/nullptr, rbLoc); + SourceLocation(), /*Length*/ nullptr, + /*Stride=*/nullptr, rbLoc); // Since this might be a postfix expression, get rid of ParenListExprs. if (isa<ParenListExpr>(base)) { @@ -4451,8 +4572,55 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, base = result.get(); } + // Check if base and idx form a MatrixSubscriptExpr. + // + // Helper to check for comma expressions, which are not allowed as indices for + // matrix subscript expressions. + auto CheckAndReportCommaError = [this, base, rbLoc](Expr *E) { + if (isa<BinaryOperator>(E) && cast<BinaryOperator>(E)->isCommaOp()) { + Diag(E->getExprLoc(), diag::err_matrix_subscript_comma) + << SourceRange(base->getBeginLoc(), rbLoc); + return true; + } + return false; + }; + // The matrix subscript operator ([][])is considered a single operator. + // Separating the index expressions by parenthesis is not allowed. + if (base->getType()->isSpecificPlaceholderType( + BuiltinType::IncompleteMatrixIdx) && + !isa<MatrixSubscriptExpr>(base)) { + Diag(base->getExprLoc(), diag::err_matrix_separate_incomplete_index) + << SourceRange(base->getBeginLoc(), rbLoc); + return ExprError(); + } + // If the base is either a MatrixSubscriptExpr or a matrix type, try to create + // a new MatrixSubscriptExpr. + auto *matSubscriptE = dyn_cast<MatrixSubscriptExpr>(base); + if (matSubscriptE) { + if (CheckAndReportCommaError(idx)) + return ExprError(); + + assert(matSubscriptE->isIncomplete() && + "base has to be an incomplete matrix subscript"); + return CreateBuiltinMatrixSubscriptExpr( + matSubscriptE->getBase(), matSubscriptE->getRowIdx(), idx, rbLoc); + } + Expr *matrixBase = base; + bool IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); + if (!IsMSPropertySubscript) { + ExprResult result = CheckPlaceholderExpr(base); + if (!result.isInvalid()) + matrixBase = result.get(); + } + if (matrixBase->getType()->isMatrixType()) { + if (CheckAndReportCommaError(idx)) + return ExprError(); + + return CreateBuiltinMatrixSubscriptExpr(matrixBase, idx, nullptr, rbLoc); + } + // A comma-expression as the index is deprecated in C++2a onwards. - if (getLangOpts().CPlusPlus2a && + if (getLangOpts().CPlusPlus20 && ((isa<BinaryOperator>(idx) && cast<BinaryOperator>(idx)->isCommaOp()) || (isa<CXXOperatorCallExpr>(idx) && cast<CXXOperatorCallExpr>(idx)->getOperator() == OO_Comma))) { @@ -4465,7 +4633,6 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, // operand might be an overloadable type, in which case the overload // resolution for the operator overload should get the first crack // at the overload. - bool IsMSPropertySubscript = false; if (base->getType()->isNonOverloadPlaceholderType()) { IsMSPropertySubscript = isMSPropertySubscriptExpr(*this, base); if (!IsMSPropertySubscript) { @@ -4526,6 +4693,79 @@ Sema::ActOnArraySubscriptExpr(Scope *S, Expr *base, SourceLocation lbLoc, return Res; } +ExprResult Sema::tryConvertExprToType(Expr *E, QualType Ty) { + InitializedEntity Entity = InitializedEntity::InitializeTemporary(Ty); + InitializationKind Kind = + InitializationKind::CreateCopy(E->getBeginLoc(), SourceLocation()); + InitializationSequence InitSeq(*this, Entity, Kind, E); + return InitSeq.Perform(*this, Entity, Kind, E); +} + +ExprResult Sema::CreateBuiltinMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBLoc) { + ExprResult BaseR = CheckPlaceholderExpr(Base); + if (BaseR.isInvalid()) + return BaseR; + Base = BaseR.get(); + + ExprResult RowR = CheckPlaceholderExpr(RowIdx); + if (RowR.isInvalid()) + return RowR; + RowIdx = RowR.get(); + + if (!ColumnIdx) + return new (Context) MatrixSubscriptExpr( + Base, RowIdx, ColumnIdx, Context.IncompleteMatrixIdxTy, RBLoc); + + // Build an unanalyzed expression if any of the operands is type-dependent. + if (Base->isTypeDependent() || RowIdx->isTypeDependent() || + ColumnIdx->isTypeDependent()) + return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + Context.DependentTy, RBLoc); + + ExprResult ColumnR = CheckPlaceholderExpr(ColumnIdx); + if (ColumnR.isInvalid()) + return ColumnR; + ColumnIdx = ColumnR.get(); + + // Check that IndexExpr is an integer expression. If it is a constant + // expression, check that it is less than Dim (= the number of elements in the + // corresponding dimension). + auto IsIndexValid = [&](Expr *IndexExpr, unsigned Dim, + bool IsColumnIdx) -> Expr * { + if (!IndexExpr->getType()->isIntegerType() && + !IndexExpr->isTypeDependent()) { + Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_not_integer) + << IsColumnIdx; + return nullptr; + } + + llvm::APSInt Idx; + if (IndexExpr->isIntegerConstantExpr(Idx, Context) && + (Idx < 0 || Idx >= Dim)) { + Diag(IndexExpr->getBeginLoc(), diag::err_matrix_index_outside_range) + << IsColumnIdx << Dim; + return nullptr; + } + + ExprResult ConvExpr = + tryConvertExprToType(IndexExpr, Context.getSizeType()); + assert(!ConvExpr.isInvalid() && + "should be able to convert any integer type to size type"); + return ConvExpr.get(); + }; + + auto *MTy = Base->getType()->getAs<ConstantMatrixType>(); + RowIdx = IsIndexValid(RowIdx, MTy->getNumRows(), false); + ColumnIdx = IsIndexValid(ColumnIdx, MTy->getNumColumns(), true); + if (!RowIdx || !ColumnIdx) + return ExprError(); + + return new (Context) MatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + MTy->getElementType(), RBLoc); +} + void Sema::CheckAddressOfNoDeref(const Expr *E) { ExpressionEvaluationContextRecord &LastRecord = ExprEvalContexts.back(); const Expr *StrippedExpr = E->IgnoreParenImpCasts(); @@ -4573,7 +4813,9 @@ void Sema::CheckSubscriptAccessOfNoDeref(const ArraySubscriptExpr *E) { ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Expr *LowerBound, - SourceLocation ColonLoc, Expr *Length, + SourceLocation ColonLocFirst, + SourceLocation ColonLocSecond, + Expr *Length, Expr *Stride, SourceLocation RBLoc) { if (Base->getType()->isPlaceholderType() && !Base->getType()->isSpecificPlaceholderType( @@ -4601,15 +4843,25 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, return ExprError(); Length = Result.get(); } + if (Stride && Stride->getType()->isNonOverloadPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Stride); + if (Result.isInvalid()) + return ExprError(); + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) + return ExprError(); + Stride = Result.get(); + } // Build an unanalyzed expression if either operand is type-dependent. if (Base->isTypeDependent() || (LowerBound && (LowerBound->isTypeDependent() || LowerBound->isValueDependent())) || - (Length && (Length->isTypeDependent() || Length->isValueDependent()))) { - return new (Context) - OMPArraySectionExpr(Base, LowerBound, Length, Context.DependentTy, - VK_LValue, OK_Ordinary, ColonLoc, RBLoc); + (Length && (Length->isTypeDependent() || Length->isValueDependent())) || + (Stride && (Stride->isTypeDependent() || Stride->isValueDependent()))) { + return new (Context) OMPArraySectionExpr( + Base, LowerBound, Length, Stride, Context.DependentTy, VK_LValue, + OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc); } // Perform default conversions. @@ -4653,6 +4905,20 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, Diag(Length->getExprLoc(), diag::warn_omp_section_is_char) << 1 << Length->getSourceRange(); } + if (Stride) { + ExprResult Res = + PerformOpenMPImplicitIntegerConversion(Stride->getExprLoc(), Stride); + if (Res.isInvalid()) + return ExprError(Diag(Stride->getExprLoc(), + diag::err_omp_typecheck_section_not_integer) + << 1 << Stride->getSourceRange()); + Stride = Res.get(); + + if (Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_S) || + Stride->getType()->isSpecificBuiltinType(BuiltinType::Char_U)) + Diag(Stride->getExprLoc(), diag::warn_omp_section_is_char) + << 1 << Stride->getSourceRange(); + } // C99 6.5.2.1p1: "shall have type "pointer to *object* type". Similarly, // C++ [expr.sub]p1: The type "T" shall be a completely-defined object @@ -4671,7 +4937,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, if (LowerBound && !OriginalTy->isAnyPointerType()) { Expr::EvalResult Result; if (LowerBound->EvaluateAsInt(Result, Context)) { - // OpenMP 4.5, [2.4 Array Sections] + // OpenMP 5.0, [2.1.5 Array Sections] // The array section must be a subset of the original array. llvm::APSInt LowerBoundValue = Result.Val.getInt(); if (LowerBoundValue.isNegative()) { @@ -4685,7 +4951,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, if (Length) { Expr::EvalResult Result; if (Length->EvaluateAsInt(Result, Context)) { - // OpenMP 4.5, [2.4 Array Sections] + // OpenMP 5.0, [2.1.5 Array Sections] // The length must evaluate to non-negative integers. llvm::APSInt LengthValue = Result.Val.getInt(); if (LengthValue.isNegative()) { @@ -4695,17 +4961,32 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, return ExprError(); } } - } else if (ColonLoc.isValid() && + } else if (ColonLocFirst.isValid() && (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && !OriginalTy->isVariableArrayType()))) { - // OpenMP 4.5, [2.4 Array Sections] + // OpenMP 5.0, [2.1.5 Array Sections] // When the size of the array dimension is not known, the length must be // specified explicitly. - Diag(ColonLoc, diag::err_omp_section_length_undefined) + Diag(ColonLocFirst, diag::err_omp_section_length_undefined) << (!OriginalTy.isNull() && OriginalTy->isArrayType()); return ExprError(); } + if (Stride) { + Expr::EvalResult Result; + if (Stride->EvaluateAsInt(Result, Context)) { + // OpenMP 5.0, [2.1.5 Array Sections] + // The stride must evaluate to a positive integer. + llvm::APSInt StrideValue = Result.Val.getInt(); + if (!StrideValue.isStrictlyPositive()) { + Diag(Stride->getExprLoc(), diag::err_omp_section_stride_non_positive) + << StrideValue.toString(/*Radix=*/10, /*Signed=*/true) + << Stride->getSourceRange(); + return ExprError(); + } + } + } + if (!Base->getType()->isSpecificPlaceholderType( BuiltinType::OMPArraySection)) { ExprResult Result = DefaultFunctionArrayLvalueConversion(Base); @@ -4713,9 +4994,371 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, return ExprError(); Base = Result.get(); } - return new (Context) - OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy, - VK_LValue, OK_Ordinary, ColonLoc, RBLoc); + return new (Context) OMPArraySectionExpr( + Base, LowerBound, Length, Stride, Context.OMPArraySectionTy, VK_LValue, + OK_Ordinary, ColonLocFirst, ColonLocSecond, RBLoc); +} + +ExprResult Sema::ActOnOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef<Expr *> Dims, + ArrayRef<SourceRange> Brackets) { + if (Base->getType()->isPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Base); + if (Result.isInvalid()) + return ExprError(); + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + } + QualType BaseTy = Base->getType(); + // Delay analysis of the types/expressions if instantiation/specialization is + // required. + if (!BaseTy->isPointerType() && Base->isTypeDependent()) + return OMPArrayShapingExpr::Create(Context, Context.DependentTy, Base, + LParenLoc, RParenLoc, Dims, Brackets); + if (!BaseTy->isPointerType() || + (!Base->isTypeDependent() && + BaseTy->getPointeeType()->isIncompleteType())) + return ExprError(Diag(Base->getExprLoc(), + diag::err_omp_non_pointer_type_array_shaping_base) + << Base->getSourceRange()); + + SmallVector<Expr *, 4> NewDims; + bool ErrorFound = false; + for (Expr *Dim : Dims) { + if (Dim->getType()->isPlaceholderType()) { + ExprResult Result = CheckPlaceholderExpr(Dim); + if (Result.isInvalid()) { + ErrorFound = true; + continue; + } + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) { + ErrorFound = true; + continue; + } + Dim = Result.get(); + } + if (!Dim->isTypeDependent()) { + ExprResult Result = + PerformOpenMPImplicitIntegerConversion(Dim->getExprLoc(), Dim); + if (Result.isInvalid()) { + ErrorFound = true; + Diag(Dim->getExprLoc(), diag::err_omp_typecheck_shaping_not_integer) + << Dim->getSourceRange(); + continue; + } + Dim = Result.get(); + Expr::EvalResult EvResult; + if (!Dim->isValueDependent() && Dim->EvaluateAsInt(EvResult, Context)) { + // OpenMP 5.0, [2.1.4 Array Shaping] + // Each si is an integral type expression that must evaluate to a + // positive integer. + llvm::APSInt Value = EvResult.Val.getInt(); + if (!Value.isStrictlyPositive()) { + Diag(Dim->getExprLoc(), diag::err_omp_shaping_dimension_not_positive) + << Value.toString(/*Radix=*/10, /*Signed=*/true) + << Dim->getSourceRange(); + ErrorFound = true; + continue; + } + } + } + NewDims.push_back(Dim); + } + if (ErrorFound) + return ExprError(); + return OMPArrayShapingExpr::Create(Context, Context.OMPArrayShapingTy, Base, + LParenLoc, RParenLoc, NewDims, Brackets); +} + +ExprResult Sema::ActOnOMPIteratorExpr(Scope *S, SourceLocation IteratorKwLoc, + SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<OMPIteratorData> Data) { + SmallVector<OMPIteratorExpr::IteratorDefinition, 4> ID; + bool IsCorrect = true; + for (const OMPIteratorData &D : Data) { + TypeSourceInfo *TInfo = nullptr; + SourceLocation StartLoc; + QualType DeclTy; + if (!D.Type.getAsOpaquePtr()) { + // OpenMP 5.0, 2.1.6 Iterators + // In an iterator-specifier, if the iterator-type is not specified then + // the type of that iterator is of int type. + DeclTy = Context.IntTy; + StartLoc = D.DeclIdentLoc; + } else { + DeclTy = GetTypeFromParser(D.Type, &TInfo); + StartLoc = TInfo->getTypeLoc().getBeginLoc(); + } + + bool IsDeclTyDependent = DeclTy->isDependentType() || + DeclTy->containsUnexpandedParameterPack() || + DeclTy->isInstantiationDependentType(); + if (!IsDeclTyDependent) { + if (!DeclTy->isIntegralType(Context) && !DeclTy->isAnyPointerType()) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must be an integral or pointer type. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + if (DeclTy.isConstant(Context)) { + // OpenMP 5.0, 2.1.6 Iterators, Restrictions, C/C++ + // The iterator-type must not be const qualified. + Diag(StartLoc, diag::err_omp_iterator_not_integral_or_pointer) + << DeclTy; + IsCorrect = false; + continue; + } + } + + // Iterator declaration. + assert(D.DeclIdent && "Identifier expected."); + // Always try to create iterator declarator to avoid extra error messages + // about unknown declarations use. + auto *VD = VarDecl::Create(Context, CurContext, StartLoc, D.DeclIdentLoc, + D.DeclIdent, DeclTy, TInfo, SC_None); + VD->setImplicit(); + if (S) { + // Check for conflicting previous declaration. + DeclarationNameInfo NameInfo(VD->getDeclName(), D.DeclIdentLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForVisibleRedeclaration); + Previous.suppressDiagnostics(); + LookupName(Previous, S); + + FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + if (!Previous.empty()) { + NamedDecl *Old = Previous.getRepresentativeDecl(); + Diag(D.DeclIdentLoc, diag::err_redefinition) << VD->getDeclName(); + Diag(Old->getLocation(), diag::note_previous_definition); + } else { + PushOnScopeChains(VD, S); + } + } else { + CurContext->addDecl(VD); + } + Expr *Begin = D.Range.Begin; + if (!IsDeclTyDependent && Begin && !Begin->isTypeDependent()) { + ExprResult BeginRes = + PerformImplicitConversion(Begin, DeclTy, AA_Converting); + Begin = BeginRes.get(); + } + Expr *End = D.Range.End; + if (!IsDeclTyDependent && End && !End->isTypeDependent()) { + ExprResult EndRes = PerformImplicitConversion(End, DeclTy, AA_Converting); + End = EndRes.get(); + } + Expr *Step = D.Range.Step; + if (!IsDeclTyDependent && Step && !Step->isTypeDependent()) { + if (!Step->getType()->isIntegralType(Context)) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_not_integral) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + llvm::APSInt Result; + bool IsConstant = Step->isIntegerConstantExpr(Result, Context); + // OpenMP 5.0, 2.1.6 Iterators, Restrictions + // If the step expression of a range-specification equals zero, the + // behavior is unspecified. + if (IsConstant && Result.isNullValue()) { + Diag(Step->getExprLoc(), diag::err_omp_iterator_step_constant_zero) + << Step << Step->getSourceRange(); + IsCorrect = false; + continue; + } + } + if (!Begin || !End || !IsCorrect) { + IsCorrect = false; + continue; + } + OMPIteratorExpr::IteratorDefinition &IDElem = ID.emplace_back(); + IDElem.IteratorDecl = VD; + IDElem.AssignmentLoc = D.AssignLoc; + IDElem.Range.Begin = Begin; + IDElem.Range.End = End; + IDElem.Range.Step = Step; + IDElem.ColonLoc = D.ColonLoc; + IDElem.SecondColonLoc = D.SecColonLoc; + } + if (!IsCorrect) { + // Invalidate all created iterator declarations if error is found. + for (const OMPIteratorExpr::IteratorDefinition &D : ID) { + if (Decl *ID = D.IteratorDecl) + ID->setInvalidDecl(); + } + return ExprError(); + } + SmallVector<OMPIteratorHelperData, 4> Helpers; + if (!CurContext->isDependentContext()) { + // Build number of ityeration for each iteration range. + // Ni = ((Stepi > 0) ? ((Endi + Stepi -1 - Begini)/Stepi) : + // ((Begini-Stepi-1-Endi) / -Stepi); + for (OMPIteratorExpr::IteratorDefinition &D : ID) { + // (Endi - Begini) + ExprResult Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, D.Range.End, + D.Range.Begin); + if(!Res.isUsable()) { + IsCorrect = false; + continue; + } + ExprResult St, St1; + if (D.Range.Step) { + St = D.Range.Step; + // (Endi - Begini) + Stepi + Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, Res.get(), St.get()); + if (!Res.isUsable()) { + IsCorrect = false; + continue; + } + // (Endi - Begini) + Stepi - 1 + Res = + CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, Res.get(), + ActOnIntegerConstant(D.AssignmentLoc, 1).get()); + if (!Res.isUsable()) { + IsCorrect = false; + continue; + } + // ((Endi - Begini) + Stepi - 1) / Stepi + Res = CreateBuiltinBinOp(D.AssignmentLoc, BO_Div, Res.get(), St.get()); + if (!Res.isUsable()) { + IsCorrect = false; + continue; + } + St1 = CreateBuiltinUnaryOp(D.AssignmentLoc, UO_Minus, D.Range.Step); + // (Begini - Endi) + ExprResult Res1 = CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, + D.Range.Begin, D.Range.End); + if (!Res1.isUsable()) { + IsCorrect = false; + continue; + } + // (Begini - Endi) - Stepi + Res1 = + CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, Res1.get(), St1.get()); + if (!Res1.isUsable()) { + IsCorrect = false; + continue; + } + // (Begini - Endi) - Stepi - 1 + Res1 = + CreateBuiltinBinOp(D.AssignmentLoc, BO_Sub, Res1.get(), + ActOnIntegerConstant(D.AssignmentLoc, 1).get()); + if (!Res1.isUsable()) { + IsCorrect = false; + continue; + } + // ((Begini - Endi) - Stepi - 1) / (-Stepi) + Res1 = + CreateBuiltinBinOp(D.AssignmentLoc, BO_Div, Res1.get(), St1.get()); + if (!Res1.isUsable()) { + IsCorrect = false; + continue; + } + // Stepi > 0. + ExprResult CmpRes = + CreateBuiltinBinOp(D.AssignmentLoc, BO_GT, D.Range.Step, + ActOnIntegerConstant(D.AssignmentLoc, 0).get()); + if (!CmpRes.isUsable()) { + IsCorrect = false; + continue; + } + Res = ActOnConditionalOp(D.AssignmentLoc, D.AssignmentLoc, CmpRes.get(), + Res.get(), Res1.get()); + if (!Res.isUsable()) { + IsCorrect = false; + continue; + } + } + Res = ActOnFinishFullExpr(Res.get(), /*DiscardedValue=*/false); + if (!Res.isUsable()) { + IsCorrect = false; + continue; + } + + // Build counter update. + // Build counter. + auto *CounterVD = + VarDecl::Create(Context, CurContext, D.IteratorDecl->getBeginLoc(), + D.IteratorDecl->getBeginLoc(), nullptr, + Res.get()->getType(), nullptr, SC_None); + CounterVD->setImplicit(); + ExprResult RefRes = + BuildDeclRefExpr(CounterVD, CounterVD->getType(), VK_LValue, + D.IteratorDecl->getBeginLoc()); + // Build counter update. + // I = Begini + counter * Stepi; + ExprResult UpdateRes; + if (D.Range.Step) { + UpdateRes = CreateBuiltinBinOp( + D.AssignmentLoc, BO_Mul, + DefaultLvalueConversion(RefRes.get()).get(), St.get()); + } else { + UpdateRes = DefaultLvalueConversion(RefRes.get()); + } + if (!UpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + UpdateRes = CreateBuiltinBinOp(D.AssignmentLoc, BO_Add, D.Range.Begin, + UpdateRes.get()); + if (!UpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + ExprResult VDRes = + BuildDeclRefExpr(cast<VarDecl>(D.IteratorDecl), + cast<VarDecl>(D.IteratorDecl)->getType(), VK_LValue, + D.IteratorDecl->getBeginLoc()); + UpdateRes = CreateBuiltinBinOp(D.AssignmentLoc, BO_Assign, VDRes.get(), + UpdateRes.get()); + if (!UpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + UpdateRes = + ActOnFinishFullExpr(UpdateRes.get(), /*DiscardedValue=*/true); + if (!UpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + ExprResult CounterUpdateRes = + CreateBuiltinUnaryOp(D.AssignmentLoc, UO_PreInc, RefRes.get()); + if (!CounterUpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + CounterUpdateRes = + ActOnFinishFullExpr(CounterUpdateRes.get(), /*DiscardedValue=*/true); + if (!CounterUpdateRes.isUsable()) { + IsCorrect = false; + continue; + } + OMPIteratorHelperData &HD = Helpers.emplace_back(); + HD.CounterVD = CounterVD; + HD.Upper = Res.get(); + HD.Update = UpdateRes.get(); + HD.CounterUpdate = CounterUpdateRes.get(); + } + } else { + Helpers.assign(ID.size(), {}); + } + if (!IsCorrect) { + // Invalidate all created iterator declarations if error is found. + for (const OMPIteratorExpr::IteratorDefinition &D : ID) { + if (Decl *ID = D.IteratorDecl) + ID->setInvalidDecl(); + } + return ExprError(); + } + return OMPIteratorExpr::Create(Context, Context.OMPIteratorTy, IteratorKwLoc, + LLoc, RLoc, ID, Helpers); } ExprResult @@ -4873,8 +5516,9 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, // See IsCForbiddenLValueType. if (!ResultType.hasQualifiers()) VK = VK_RValue; } else if (!ResultType->isDependentType() && - RequireCompleteType(LLoc, ResultType, - diag::err_subscript_incomplete_type, BaseExpr)) + RequireCompleteSizedType( + LLoc, ResultType, + diag::err_subscript_incomplete_or_sizeless_type, BaseExpr)) return ExprError(); assert(VK == VK_RValue || LangOpts.CPlusPlus || @@ -4914,6 +5558,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { + // If we've already cleared out the location for the default argument, + // that means we're parsing it right now. + if (!UnparsedDefaultArgLocs.count(Param)) { + Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; + Diag(CallLoc, diag::note_recursive_default_argument_used_here); + Param->setInvalidDecl(); + return true; + } + Diag(CallLoc, diag::err_use_of_default_argument_to_function_declared_later) << FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName(); @@ -4922,90 +5575,11 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, return true; } - if (Param->hasUninstantiatedDefaultArg()) { - Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); - - EnterExpressionEvaluationContext EvalContext( - *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); - - // Instantiate the expression. - // - // FIXME: Pass in a correct Pattern argument, otherwise - // getTemplateInstantiationArgs uses the lexical context of FD, e.g. - // - // template<typename T> - // struct A { - // static int FooImpl(); - // - // template<typename Tp> - // // bug: default argument A<T>::FooImpl() is evaluated with 2-level - // // template argument list [[T], [Tp]], should be [[Tp]]. - // friend A<Tp> Foo(int a); - // }; - // - // template<typename T> - // A<T> Foo(int a = A<T>::FooImpl()); - MultiLevelTemplateArgumentList MutiLevelArgList - = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); - - InstantiatingTemplate Inst(*this, CallLoc, Param, - MutiLevelArgList.getInnermost()); - if (Inst.isInvalid()) - return true; - if (Inst.isAlreadyInstantiating()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); - return true; - } - - ExprResult Result; - { - // C++ [dcl.fct.default]p5: - // The names in the [default argument] expression are bound, and - // the semantic constraints are checked, at the point where the - // default argument expression appears. - ContextRAII SavedContext(*this, FD); - LocalInstantiationScope Local(*this); - runWithSufficientStackSpace(CallLoc, [&] { - Result = SubstInitializer(UninstExpr, MutiLevelArgList, - /*DirectInit*/false); - }); - } - if (Result.isInvalid()) - return true; - - // Check the expression as an initializer for the parameter. - InitializedEntity Entity - = InitializedEntity::InitializeParameter(Context, Param); - InitializationKind Kind = InitializationKind::CreateCopy( - Param->getLocation(), - /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc()); - Expr *ResultE = Result.getAs<Expr>(); - - InitializationSequence InitSeq(*this, Entity, Kind, ResultE); - Result = InitSeq.Perform(*this, Entity, Kind, ResultE); - if (Result.isInvalid()) - return true; - - Result = - ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(), - /*DiscardedValue*/ false); - if (Result.isInvalid()) - return true; - - // Remember the instantiated default argument. - Param->setDefaultArg(Result.getAs<Expr>()); - if (ASTMutationListener *L = getASTMutationListener()) { - L->DefaultArgumentInstantiated(Param); - } - } - - // If the default argument expression is not set yet, we are building it now. - if (!Param->hasInit()) { - Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; - Param->setInvalidDecl(); + if (Param->hasUninstantiatedDefaultArg() && + InstantiateDefaultArgument(CallLoc, FD, Param)) return true; - } + + assert(Param->hasInit() && "default argument but no initializer?"); // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll @@ -5038,6 +5612,7 @@ bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, ParmVarDecl *Param) { + assert(Param->hasDefaultArg() && "can't build nonexistent default arg"); if (CheckCXXDefaultArgExpr(CallLoc, FD, Param)) return ExprError(); return CXXDefaultArgExpr::Create(Context, CallLoc, Param, CurContext); @@ -5183,7 +5758,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; return true; } @@ -5228,7 +5803,7 @@ Sema::ConvertArgumentsForCall(CallExpr *Call, Expr *Fn, // Emit the location of the prototype. if (!TC && FDecl && !FDecl->getBuiltinID() && !IsExecConfig) - Diag(FDecl->getBeginLoc(), diag::note_callee_decl) << FDecl; + Diag(FDecl->getLocation(), diag::note_callee_decl) << FDecl; // This deletes the extra arguments. Call->shrinkNumArgs(NumParams); @@ -5341,9 +5916,6 @@ bool Sema::GatherArgumentsForCall(SourceLocation CallLoc, FunctionDecl *FDecl, for (Expr *A : Args.slice(ArgIx)) { ExprResult Arg = DefaultVariadicArgumentPromotion(A, CallType, FDecl); Invalid |= Arg.isInvalid(); - // Copy blocks to the heap. - if (A->getType()->isBlockPointerType()) - maybeExtendBlockObject(Arg); AllArgs.push_back(Arg.get()); } } @@ -5476,7 +6048,10 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { // These are always invalid as call arguments and should be reported. case BuiltinType::BoundMember: case BuiltinType::BuiltinFn: + case BuiltinType::IncompleteMatrixIdx: case BuiltinType::OMPArraySection: + case BuiltinType::OMPArrayShaping: + case BuiltinType::OMPIterator: return true; } @@ -5599,7 +6174,8 @@ static void checkDirectCallValidity(Sema &S, const Expr *Fn, if (Callee->getMinRequiredArguments() > ArgExprs.size()) return; - if (const EnableIfAttr *Attr = S.CheckEnableIf(Callee, ArgExprs, true)) { + if (const EnableIfAttr *Attr = + S.CheckEnableIf(Callee, Fn->getBeginLoc(), ArgExprs, true)) { S.Diag(Fn->getBeginLoc(), isa<CXXMethodDecl>(Callee) ? diag::err_ovl_no_viable_member_function_in_call @@ -5706,13 +6282,17 @@ ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, if (auto *ULE = dyn_cast<UnresolvedLookupExpr>(Fn)) { if (ULE->hasExplicitTemplateArgs() && ULE->decls_begin() == ULE->decls_end()) { - Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus2a + Diag(Fn->getExprLoc(), getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_adl_only_template_id : diag::ext_adl_only_template_id) << ULE->getName(); } } + if (LangOpts.OpenMP) + Call = ActOnOpenMPCall(Call, Scope, LParenLoc, ArgExprs, RParenLoc, + ExecConfig); + return Call; } @@ -6123,6 +6703,18 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, if (NDecl) DiagnoseSentinelCalls(NDecl, LParenLoc, Args); + // Warn for unions passing across security boundary (CMSE). + if (FuncT != nullptr && FuncT->getCmseNSCallAttr()) { + for (unsigned i = 0, e = Args.size(); i != e; i++) { + if (const auto *RT = + dyn_cast<RecordType>(Args[i]->getType().getCanonicalType())) { + if (RT->getDecl()->isOrContainsUnion()) + Diag(Args[i]->getBeginLoc(), diag::warn_cmse_nonsecure_union) + << 0 << i; + } + } + } + // Do special checking on direct calls to functions. if (FDecl) { if (CheckFunctionCall(FDecl, TheCall, Proto)) @@ -6140,7 +6732,7 @@ ExprResult Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, return ExprError(); } - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FDecl); } ExprResult @@ -6163,10 +6755,10 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, QualType literalType = TInfo->getType(); if (literalType->isArrayType()) { - if (RequireCompleteType(LParenLoc, Context.getBaseElementType(literalType), - diag::err_illegal_decl_array_incomplete_type, - SourceRange(LParenLoc, - LiteralExpr->getSourceRange().getEnd()))) + if (RequireCompleteSizedType( + LParenLoc, Context.getBaseElementType(literalType), + diag::err_array_incomplete_or_sizeless_type, + SourceRange(LParenLoc, LiteralExpr->getSourceRange().getEnd()))) return ExprError(); if (literalType->isVariableArrayType()) return ExprError(Diag(LParenLoc, diag::err_variable_object_no_init) @@ -6240,14 +6832,24 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); } - // Compound literals that have automatic storage duration are destroyed at - // the end of the scope. Emit diagnostics if it is or contains a C union type - // that is non-trivial to destruct. - if (!isFileScope) + if (!isFileScope && !getLangOpts().CPlusPlus) { + // Compound literals that have automatic storage duration are destroyed at + // the end of the scope in C; in C++, they're just temporaries. + + // Emit diagnostics if it is or contains a C union type that is non-trivial + // to destruct. if (E->getType().hasNonTrivialToPrimitiveDestructCUnion()) checkNonTrivialCUnion(E->getType(), E->getExprLoc(), NTCUC_CompoundLiteral, NTCUK_Destruct); + // Diagnose jumps that enter or exit the lifetime of the compound literal. + if (literalType.isDestructedType()) { + Cleanup.setExprNeedsCleanups(true); + ExprCleanupObjects.push_back(E); + getCurFunction()->setHasBranchProtectedScope(); + } + } + if (E->getType().hasNonTrivialToPrimitiveDefaultInitializeCUnion() || E->getType().hasNonTrivialToPrimitiveCopyCUnion()) checkNonTrivialCUnionInInitializer(E->getInitializer(), @@ -6313,7 +6915,7 @@ Sema::ActOnInitList(SourceLocation LBraceLoc, MultiExprArg InitArgList, // already diagnose use of (non-C++20) C99 designator syntax. if (getLangOpts().CPlusPlus && !DiagnosedArrayDesignator && !DiagnosedNestedDesignator && !DiagnosedMixedDesignator) { - Diag(FirstDesignator, getLangOpts().CPlusPlus2a + Diag(FirstDesignator, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_designated_init : diag::ext_cxx_designated_init); } else if (!getLangOpts().CPlusPlus && !getLangOpts().C99) { @@ -7459,7 +8061,8 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // The OpenCL operator with a vector condition is sufficiently // different to merit its own checker. - if (getLangOpts().OpenCL && Cond.get()->getType()->isVectorType()) + if ((getLangOpts().OpenCL && Cond.get()->getType()->isVectorType()) || + Cond.get()->getType()->isExtVectorType()) return OpenCLCheckVectorConditional(*this, Cond, LHS, RHS, QuestionLoc); // First, check the condition. @@ -7509,6 +8112,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return ResTy; } + // And if they're both bfloat (which isn't arithmetic), that's fine too. + if (LHSTy->isBFloat16Type() && RHSTy->isBFloat16Type()) { + return LHSTy; + } + // If both operands are the same structure or union type, the result is that // type. if (const RecordType *LHSRT = LHSTy->getAs<RecordType>()) { // C99 6.5.15p3 @@ -7559,6 +8167,11 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, /*IsIntFirstExpr=*/false)) return LHSTy; + // Allow ?: operations in which both operands have the same + // built-in sizeless type. + if (LHSTy->isSizelessBuiltinType() && LHSTy == RHSTy) + return LHSTy; + // Emit a better diagnostic if one of the expressions is a null pointer // constant and the other is not a pointer type. In this case, the user most // likely forgot to take the address of the other expression. @@ -8002,6 +8615,24 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, ColonLoc, result, VK, OK); } +// Check if we have a conversion between incompatible cmse function pointer +// types, that is, a conversion between a function pointer with the +// cmse_nonsecure_call attribute and one without. +static bool IsInvalidCmseNSCallConversion(Sema &S, QualType FromType, + QualType ToType) { + if (const auto *ToFn = + dyn_cast<FunctionType>(S.Context.getCanonicalType(ToType))) { + if (const auto *FromFn = + dyn_cast<FunctionType>(S.Context.getCanonicalType(FromType))) { + FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo(); + FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo(); + + return ToEInfo.getCmseNSCall() != FromEInfo.getCmseNSCall(); + } + } + return false; +} + // checkPointerTypesForAssignment - This is a very tricky routine (despite // being closely modeled after the C99 spec:-). The odd characteristic of this // routine is it effectively iqnores the qualifiers on the top level pointee. @@ -8133,11 +8764,15 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { } // General pointer incompatibility takes priority over qualifiers. + if (RHSType->isFunctionPointerType() && LHSType->isFunctionPointerType()) + return Sema::IncompatibleFunctionPointer; return Sema::IncompatiblePointer; } if (!S.getLangOpts().CPlusPlus && S.IsFunctionConversion(ltrans, rtrans, ltrans)) - return Sema::IncompatiblePointer; + return Sema::IncompatibleFunctionPointer; + if (IsInvalidCmseNSCallConversion(S, ltrans, rtrans)) + return Sema::IncompatibleFunctionPointer; return ConvTy; } @@ -8248,7 +8883,7 @@ Sema::CheckAssignmentConstraints(SourceLocation Loc, /// type ElementType. static bool isVector(QualType QT, QualType ElementType) { if (const VectorType *VT = QT->getAs<VectorType>()) - return VT->getElementType() == ElementType; + return VT->getElementType().getCanonicalType() == ElementType; return false; } @@ -8691,7 +9326,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, ImplicitConversionSequence ICS = TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, + AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false); @@ -8786,7 +9421,7 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, if (getLangOpts().ObjC && (CheckObjCBridgeRelatedConversions(E->getBeginLoc(), LHSType, E->getType(), E, Diagnose) || - ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) { + CheckConversionToObjCLiteral(LHSType, E, Diagnose))) { if (!Diagnose) return Incompatible; // Replace the expression with a corrected version and continue so we @@ -9083,7 +9718,13 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, // Reject cases where the scalar type is not a constant and has a higher // Order than the vector element type. llvm::APFloat Result(0.0); - bool CstScalar = Scalar->get()->EvaluateAsFloat(Result, S.Context); + + // Determine whether this is a constant scalar. In the event that the + // value is dependent (and thus cannot be evaluated by the constant + // evaluator), skip the evaluation. This will then diagnose once the + // expression is instantiated. + bool CstScalar = Scalar->get()->isValueDependent() || + Scalar->get()->EvaluateAsFloat(Result, S.Context); int Order = S.Context.getFloatingTypeOrder(VectorEltTy, ScalarTy); if (!CstScalar && Order < 0) return true; @@ -9106,7 +9747,8 @@ static bool tryGCCVectorConvertAndSplat(Sema &S, ExprResult *Scalar, ScalarCast = CK_IntegralToFloating; } else return true; - } + } else if (ScalarTy->isEnumeralType()) + return true; // Adjust scalar if desired. if (Scalar) { @@ -9395,6 +10037,9 @@ QualType Sema::CheckMultiplyDivideOperands(ExprResult &LHS, ExprResult &RHS, return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, /*AllowBothBool*/getLangOpts().AltiVec, /*AllowBoolConversions*/false); + if (!IsDiv && (LHS.get()->getType()->isConstantMatrixType() || + RHS.get()->getType()->isConstantMatrixType())) + return CheckMatrixMultiplyOperands(LHS, RHS, Loc, IsCompAssign); QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, IsCompAssign ? ACK_CompAssign : ACK_Arithmetic); @@ -9509,9 +10154,10 @@ static bool checkArithmeticIncompletePointerType(Sema &S, SourceLocation Loc, assert(ResType->isAnyPointerType() && !ResType->isDependentType()); QualType PointeeTy = ResType->getPointeeType(); - return S.RequireCompleteType(Loc, PointeeTy, - diag::err_typecheck_arithmetic_incomplete_type, - PointeeTy, Operand->getSourceRange()); + return S.RequireCompleteSizedType( + Loc, PointeeTy, + diag::err_typecheck_arithmetic_incomplete_or_sizeless_type, + Operand->getSourceRange()); } /// Check the validity of an arithmetic pointer operand. @@ -9565,10 +10211,8 @@ static bool checkArithmeticBinOpPointerOperands(Sema &S, SourceLocation Loc, if (isRHSPointer) RHSPointeeTy = RHSExpr->getType()->getPointeeType(); // if both are pointers check if operation is valid wrt address spaces - if (S.getLangOpts().OpenCL && isLHSPointer && isRHSPointer) { - const PointerType *lhsPtr = LHSExpr->getType()->castAs<PointerType>(); - const PointerType *rhsPtr = RHSExpr->getType()->castAs<PointerType>(); - if (!lhsPtr->isAddressSpaceOverlapping(*rhsPtr)) { + if (isLHSPointer && isRHSPointer) { + if (!LHSPointeeTy.isAddressSpaceOverlapping(RHSPointeeTy)) { S.Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSExpr->getType() << RHSExpr->getType() << 1 /*arithmetic op*/ @@ -9715,6 +10359,11 @@ QualType Sema::CheckAdditionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } + if (LHS.get()->getType()->isConstantMatrixType() || + RHS.get()->getType()->isConstantMatrixType()) { + return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy); + } + QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) @@ -9810,6 +10459,11 @@ QualType Sema::CheckSubtractionOperands(ExprResult &LHS, ExprResult &RHS, return compType; } + if (LHS.get()->getType()->isConstantMatrixType() || + RHS.get()->getType()->isConstantMatrixType()) { + return CheckMatrixElementwiseOperands(LHS, RHS, Loc, CompLHSTy); + } + QualType compType = UsualArithmeticConversions( LHS, RHS, Loc, CompLHSTy ? ACK_CompAssign : ACK_Arithmetic); if (LHS.isInvalid() || RHS.isInvalid()) @@ -9933,14 +10587,19 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange()); return; } - llvm::APInt LeftBits(Right.getBitWidth(), - S.Context.getTypeSize(LHS.get()->getType())); + + QualType LHSExprType = LHS.get()->getType(); + uint64_t LeftSize = LHSExprType->isExtIntType() + ? S.Context.getIntWidth(LHSExprType) + : S.Context.getTypeSize(LHSExprType); + llvm::APInt LeftBits(Right.getBitWidth(), LeftSize); if (Right.uge(LeftBits)) { S.DiagRuntimeBehavior(Loc, RHS.get(), S.PDiag(diag::warn_shift_gt_typewidth) << RHS.get()->getSourceRange()); return; } + if (Opc != BO_Shl) return; @@ -9960,7 +10619,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // If LHS does not have a signed type and non-negative value // then, the behavior is undefined before C++2a. Warn about it. if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined() && - !S.getLangOpts().CPlusPlus2a) { + !S.getLangOpts().CPlusPlus20) { S.DiagRuntimeBehavior(Loc, LHS.get(), S.PDiag(diag::warn_shift_lhs_negative) << LHS.get()->getSourceRange()); @@ -10440,7 +11099,7 @@ static void diagnoseTautologicalComparison(Sema &S, SourceLocation Loc, // C++2a [depr.array.comp]: // Equality and relational comparisons ([expr.eq], [expr.rel]) between two // operands of array type are deprecated. - if (S.getLangOpts().CPlusPlus2a && LHSStripped->getType()->isArrayType() && + if (S.getLangOpts().CPlusPlus20 && LHSStripped->getType()->isArrayType() && RHSStripped->getType()->isArrayType()) { S.Diag(Loc, diag::warn_depr_array_comparison) << LHS->getSourceRange() << RHS->getSourceRange() @@ -10897,11 +11556,22 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // C99 6.5.9p2 and C99 6.5.8p2 if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), RCanPointeeTy.getUnqualifiedType())) { - // Valid unless a relational comparison of function pointers - if (IsRelational && LCanPointeeTy->isFunctionType()) { - Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) - << LHSType << RHSType << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); + if (IsRelational) { + // Pointers both need to point to complete or incomplete types + if ((LCanPointeeTy->isIncompleteType() != + RCanPointeeTy->isIncompleteType()) && + !getLangOpts().C11) { + Diag(Loc, diag::ext_typecheck_compare_complete_incomplete_pointers) + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange() + << LHSType << RHSType << LCanPointeeTy->isIncompleteType() + << RCanPointeeTy->isIncompleteType(); + } + if (LCanPointeeTy->isFunctionType()) { + // Valid unless a relational comparison of function pointers + Diag(Loc, diag::ext_typecheck_ordered_comparison_of_function_pointers) + << LHSType << RHSType << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + } } } else if (!IsRelational && (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { @@ -10917,8 +11587,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, if (LCanPointeeTy != RCanPointeeTy) { // Treat NULL constant as a special case in OpenCL. if (getLangOpts().OpenCL && !LHSIsNull && !RHSIsNull) { - const PointerType *LHSPtr = LHSType->castAs<PointerType>(); - if (!LHSPtr->isAddressSpaceOverlapping(*RHSType->castAs<PointerType>())) { + if (!LCanPointeeTy.isAddressSpaceOverlapping(RCanPointeeTy)) { Diag(Loc, diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) << LHSType << RHSType << 0 /* comparison */ @@ -11316,12 +11985,12 @@ static void diagnoseXorMisusedAsPow(Sema &S, const ExprResult &XorLHS, if (XorStr == "xor") return; - std::string LHSStr = Lexer::getSourceText( + std::string LHSStr = std::string(Lexer::getSourceText( CharSourceRange::getTokenRange(LHSInt->getSourceRange()), - S.getSourceManager(), S.getLangOpts()); - std::string RHSStr = Lexer::getSourceText( + S.getSourceManager(), S.getLangOpts())); + std::string RHSStr = std::string(Lexer::getSourceText( CharSourceRange::getTokenRange(RHSInt->getSourceRange()), - S.getSourceManager(), S.getLangOpts()); + S.getSourceManager(), S.getLangOpts())); if (Negative) { RightSideValue = -RightSideValue; @@ -11401,6 +12070,83 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, return GetSignedVectorType(LHS.get()->getType()); } +QualType Sema::CheckMatrixElementwiseOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign) { + if (!IsCompAssign) { + LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + } + RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + + // For conversion purposes, we ignore any qualifiers. + // For example, "const float" and "float" are equivalent. + QualType LHSType = LHS.get()->getType().getUnqualifiedType(); + QualType RHSType = RHS.get()->getType().getUnqualifiedType(); + + const MatrixType *LHSMatType = LHSType->getAs<MatrixType>(); + const MatrixType *RHSMatType = RHSType->getAs<MatrixType>(); + assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix"); + + if (Context.hasSameType(LHSType, RHSType)) + return LHSType; + + // Type conversion may change LHS/RHS. Keep copies to the original results, in + // case we have to return InvalidOperands. + ExprResult OriginalLHS = LHS; + ExprResult OriginalRHS = RHS; + if (LHSMatType && !RHSMatType) { + RHS = tryConvertExprToType(RHS.get(), LHSMatType->getElementType()); + if (!RHS.isInvalid()) + return LHSType; + + return InvalidOperands(Loc, OriginalLHS, OriginalRHS); + } + + if (!LHSMatType && RHSMatType) { + LHS = tryConvertExprToType(LHS.get(), RHSMatType->getElementType()); + if (!LHS.isInvalid()) + return RHSType; + return InvalidOperands(Loc, OriginalLHS, OriginalRHS); + } + + return InvalidOperands(Loc, LHS, RHS); +} + +QualType Sema::CheckMatrixMultiplyOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + bool IsCompAssign) { + if (!IsCompAssign) { + LHS = DefaultFunctionArrayLvalueConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); + } + RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); + if (RHS.isInvalid()) + return QualType(); + + auto *LHSMatType = LHS.get()->getType()->getAs<ConstantMatrixType>(); + auto *RHSMatType = RHS.get()->getType()->getAs<ConstantMatrixType>(); + assert((LHSMatType || RHSMatType) && "At least one operand must be a matrix"); + + if (LHSMatType && RHSMatType) { + if (LHSMatType->getNumColumns() != RHSMatType->getNumRows()) + return InvalidOperands(Loc, LHS, RHS); + + if (!Context.hasSameType(LHSMatType->getElementType(), + RHSMatType->getElementType())) + return InvalidOperands(Loc, LHS, RHS); + + return Context.getConstantMatrixType(LHSMatType->getElementType(), + LHSMatType->getNumRows(), + RHSMatType->getNumColumns()); + } + return CheckMatrixElementwiseOperands(LHS, RHS, Loc, IsCompAssign); +} + inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, BinaryOperatorKind Opc) { @@ -12086,7 +12832,7 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, CheckForNullPointerDereference(*this, LHSExpr); - if (getLangOpts().CPlusPlus2a && LHSType.isVolatileQualified()) { + if (getLangOpts().CPlusPlus20 && LHSType.isVolatileQualified()) { if (CompoundType.isNull()) { // C++2a [expr.ass]p5: // A simple-assignment whose left operand is of a volatile-qualified @@ -12132,8 +12878,8 @@ static bool IgnoreCommaOperand(const Expr *E) { } // Look for instances where it is likely the comma operator is confused with -// another operator. There is a whitelist of acceptable expressions for the -// left hand side of the comma operator, otherwise emit a warning. +// another operator. There is an explicit list of acceptable expressions for +// the left hand side of the comma operator, otherwise emit a warning. void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { // No warnings in macros if (Loc.isMacroID()) @@ -12143,10 +12889,10 @@ void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { if (inTemplateInstantiation()) return; - // Scope isn't fine-grained enough to whitelist the specific cases, so + // Scope isn't fine-grained enough to explicitly list the specific cases, so // instead, skip more than needed, then call back into here with the // CommaVisitor in SemaStmt.cpp. - // The whitelisted locations are the initialization and increment portions + // The listed locations are the initialization and increment portions // of a for loop. The additional checks are on the condition of // if statements, do/while loops, and for loops. // Differences in scope flags for C89 mode requires the extra logic. @@ -12289,7 +13035,7 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, // Now make sure the operand is a modifiable lvalue. if (CheckForModifiableLvalue(Op, OpLoc, S)) return QualType(); - if (S.getLangOpts().CPlusPlus2a && ResType.isVolatileQualified()) { + if (S.getLangOpts().CPlusPlus20 && ResType.isVolatileQualified()) { // C++2a [expr.pre.inc]p1, [expr.post.inc]p1: // An operand with volatile-qualified type is deprecated S.Diag(OpLoc, diag::warn_deprecated_increment_decrement_volatile) @@ -12321,6 +13067,9 @@ static QualType CheckIncrementDecrementOperand(Sema &S, Expr *Op, /// - *(x + 1) -> x, if x is an array /// - &"123"[2] -> 0 /// - & __real__ x -> x +/// +/// FIXME: We don't recurse to the RHS of a comma, nor handle pointers to +/// members. static ValueDecl *getPrimaryDecl(Expr *E) { switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: @@ -12361,19 +13110,22 @@ static ValueDecl *getPrimaryDecl(Expr *E) { // If the result of an implicit cast is an l-value, we care about // the sub-expression; otherwise, the result here doesn't matter. return getPrimaryDecl(cast<ImplicitCastExpr>(E)->getSubExpr()); + case Stmt::CXXUuidofExprClass: + return cast<CXXUuidofExpr>(E)->getGuidDecl(); default: return nullptr; } } namespace { - enum { - AO_Bit_Field = 0, - AO_Vector_Element = 1, - AO_Property_Expansion = 2, - AO_Register_Variable = 3, - AO_No_Error = 4 - }; +enum { + AO_Bit_Field = 0, + AO_Vector_Element = 1, + AO_Property_Expansion = 2, + AO_Register_Variable = 3, + AO_Matrix_Element = 4, + AO_No_Error = 5 +}; } /// Diagnose invalid operand for address of operations. /// @@ -12540,6 +13292,9 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } else if (op->getObjectKind() == OK_VectorComponent) { // The operand cannot be an element of a vector AddressOfError = AO_Vector_Element; + } else if (op->getObjectKind() == OK_MatrixComponent) { + // The operand cannot be an element of a matrix. + AddressOfError = AO_Matrix_Element; } else if (dcl) { // C99 6.5.3.2p1 // We have an lvalue with a decl. Make sure the decl is not declared // with the register storage-class specifier. @@ -12581,7 +13336,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { } } } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) && - !isa<BindingDecl>(dcl)) + !isa<BindingDecl>(dcl) && !isa<MSGuidDecl>(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } @@ -12845,7 +13600,7 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, BinaryOperatorKind Opc, QualType ResultTy, ExprValueKind VK, ExprObjectKind OK, bool IsCompAssign, SourceLocation OpLoc, - FPOptions FPFeatures) { + FPOptionsOverride FPFeatures) { auto &Context = S.getASTContext(); assert((isVector(ResultTy, Context.HalfTy) || isVector(ResultTy, Context.ShortTy)) && @@ -12863,13 +13618,13 @@ static ExprResult convertHalfVecBinOp(Sema &S, ExprResult LHS, ExprResult RHS, BinOpResTy = S.GetSignedVectorType(BinOpResTy); if (IsCompAssign) - return new (Context) CompoundAssignOperator( - LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, BinOpResTy, BinOpResTy, - OpLoc, FPFeatures); + return CompoundAssignOperator::Create(Context, LHS.get(), RHS.get(), Opc, + ResultTy, VK, OK, OpLoc, FPFeatures, + BinOpResTy, BinOpResTy); LHS = convertVector(LHS.get(), Context.FloatTy, S); - auto *BO = new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, BinOpResTy, - VK, OK, OpLoc, FPFeatures); + auto *BO = BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, + BinOpResTy, VK, OK, OpLoc, FPFeatures); return convertVector(BO, ResultTy->castAs<VectorType>()->getElementType(), S); } @@ -12882,13 +13637,15 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. LHS = S.CorrectDelayedTyposInExpr(LHS); - RHS = S.CorrectDelayedTyposInExpr(RHS, [Opc, LHS](Expr *E) { - if (Opc != BO_Assign) - return ExprResult(E); - // Avoid correcting the RHS to the same Expr as the LHS. - Decl *D = getDeclFromExpr(E); - return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; - }); + RHS = S.CorrectDelayedTyposInExpr( + RHS, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, + [Opc, LHS](Expr *E) { + if (Opc != BO_Assign) + return ExprResult(E); + // Avoid correcting the RHS to the same Expr as the LHS. + Decl *D = getDeclFromExpr(E); + return (D && D == getDeclFromExpr(LHS.get())) ? ExprError() : E; + }); } return std::make_pair(LHS, RHS); } @@ -12896,10 +13653,27 @@ CorrectDelayedTyposInBinOp(Sema &S, BinaryOperatorKind Opc, Expr *LHSExpr, /// Returns true if conversion between vectors of halfs and vectors of floats /// is needed. static bool needsConversionOfHalfVec(bool OpRequiresConversion, ASTContext &Ctx, - QualType SrcType) { - return OpRequiresConversion && !Ctx.getLangOpts().NativeHalfType && - !Ctx.getTargetInfo().useFP16ConversionIntrinsics() && - isVector(SrcType, Ctx.HalfTy); + Expr *E0, Expr *E1 = nullptr) { + if (!OpRequiresConversion || Ctx.getLangOpts().NativeHalfType || + Ctx.getTargetInfo().useFP16ConversionIntrinsics()) + return false; + + auto HasVectorOfHalfType = [&Ctx](Expr *E) { + QualType Ty = E->IgnoreImplicit()->getType(); + + // Don't promote half precision neon vectors like float16x4_t in arm_neon.h + // to vectors of floats. Although the element type of the vectors is __fp16, + // the vectors shouldn't be treated as storage-only types. See the + // discussion here: https://reviews.llvm.org/rG825235c140e7 + if (const VectorType *VT = Ty->getAs<VectorType>()) { + if (VT->getVectorKind() == VectorType::NeonVector) + return false; + return VT->getElementType().getCanonicalType() == Ctx.HalfTy; + } + return false; + }; + + return HasVectorOfHalfType(E0) && (!E1 || HasVectorOfHalfType(E1)); } /// CreateBuiltinBinOp - Creates a new built-in binary operation with @@ -12964,14 +13738,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } } - // Diagnose operations on the unsupported types for OpenMP device compilation. - if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { - if (Opc != BO_Assign && Opc != BO_Comma) { - checkOpenMPDeviceExpr(LHSExpr); - checkOpenMPDeviceExpr(RHSExpr); - } - } - switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); @@ -13119,14 +13885,6 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (ResultTy.isNull() || LHS.isInvalid() || RHS.isInvalid()) return ExprError(); - if (ResultTy->isRealFloatingType() && - (getLangOpts().getFPRoundingMode() != LangOptions::FPR_ToNearest || - getLangOpts().getFPExceptionMode() != LangOptions::FPE_Ignore)) - // Mark the current function as usng floating point constrained intrinsics - if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) { - F->setUsesFPIntrin(true); - } - // Some of the binary operations require promoting operands of half vector to // float vectors and truncating the result back to half vector. For now, we do // this only when HalfArgsAndReturn is set (that is, when the target is arm or @@ -13134,8 +13892,8 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, assert(isVector(RHS.get()->getType(), Context.HalfTy) == isVector(LHS.get()->getType(), Context.HalfTy) && "both sides are half vectors or neither sides are"); - ConvertHalfVec = needsConversionOfHalfVec(ConvertHalfVec, Context, - LHS.get()->getType()); + ConvertHalfVec = + needsConversionOfHalfVec(ConvertHalfVec, Context, LHS.get(), RHS.get()); // Check for array bounds violations for both sides of the BinaryOperator CheckArrayAccess(LHS.get()); @@ -13165,9 +13923,9 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, if (CompResultTy.isNull()) { if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, false, - OpLoc, FPFeatures); - return new (Context) BinaryOperator(LHS.get(), RHS.get(), Opc, ResultTy, VK, - OK, OpLoc, FPFeatures); + OpLoc, CurFPFeatureOverrides()); + return BinaryOperator::Create(Context, LHS.get(), RHS.get(), Opc, ResultTy, + VK, OK, OpLoc, CurFPFeatureOverrides()); } // Handle compound assignments. @@ -13177,13 +13935,19 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, OK = LHS.get()->getObjectKind(); } + // The LHS is not converted to the result type for fixed-point compound + // assignment as the common type is computed on demand. Reset the CompLHSTy + // to the LHS type we would have gotten after unary conversions. + if (CompResultTy->isFixedPointType()) + CompLHSTy = UsualUnaryConversions(LHS.get()).get()->getType(); + if (ConvertHalfVec) return convertHalfVecBinOp(*this, LHS, RHS, Opc, ResultTy, VK, OK, true, - OpLoc, FPFeatures); + OpLoc, CurFPFeatureOverrides()); - return new (Context) CompoundAssignOperator( - LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, CompLHSTy, CompResultTy, - OpLoc, FPFeatures); + return CompoundAssignOperator::Create( + Context, LHS.get(), RHS.get(), Opc, ResultTy, VK, OK, OpLoc, + CurFPFeatureOverrides(), CompLHSTy, CompResultTy); } /// DiagnoseBitwisePrecedence - Emit a warning when bitwise and comparison @@ -13436,7 +14200,7 @@ static ExprResult BuildOverloadedBinOp(Sema &S, Scope *Sc, SourceLocation OpLoc, RHS->getType(), Functions); // In C++20 onwards, we may have a second operator to look up. - if (S.getLangOpts().CPlusPlus2a) { + if (S.getLangOpts().CPlusPlus20) { if (OverloadedOperatorKind ExtraOp = getRewrittenOverloadedOperator(OverOp)) S.LookupOverloadedOperatorName(ExtraOp, Sc, LHS->getType(), RHS->getType(), Functions); @@ -13586,12 +14350,6 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, << Input.get()->getSourceRange()); } } - // Diagnose operations on the unsupported types for OpenMP device compilation. - if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { - if (UnaryOperator::isIncrementDecrementOp(Opc) || - UnaryOperator::isArithmeticOp(Opc)) - checkOpenMPDeviceExpr(InputExpr); - } switch (Opc) { case UO_PreInc: @@ -13627,8 +14385,7 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // float vector and truncating the result back to a half vector. For now, we // do this only when HalfArgsAndReturns is set (that is, when the target is // arm or arm64). - ConvertHalfVec = - needsConversionOfHalfVec(true, Context, Input.get()->getType()); + ConvertHalfVec = needsConversionOfHalfVec(true, Context, Input.get()); // If the operand is a half vector, promote it to a float vector. if (ConvertHalfVec) @@ -13722,9 +14479,16 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, // Vector logical not returns the signed variant of the operand type. resultType = GetSignedVectorType(resultType); break; + } else if (Context.getLangOpts().CPlusPlus && resultType->isVectorType()) { + const VectorType *VTy = resultType->castAs<VectorType>(); + if (VTy->getVectorKind() != VectorType::GenericVector) + return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) + << resultType << Input.get()->getSourceRange()); + + // Vector logical not returns the signed variant of the operand type. + resultType = GetSignedVectorType(resultType); + break; } else { - // FIXME: GCC's vector extension permits the usage of '!' with a vector - // type in C++. We should allow that here too. return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << resultType << Input.get()->getSourceRange()); } @@ -13771,8 +14535,9 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, if (Opc != UO_AddrOf && Opc != UO_Deref) CheckArrayAccess(Input.get()); - auto *UO = new (Context) - UnaryOperator(Input.get(), Opc, resultType, VK, OK, OpLoc, CanOverflow); + auto *UO = + UnaryOperator::Create(Context, Input.get(), Opc, resultType, VK, OK, + OpLoc, CanOverflow, CurFPFeatureOverrides()); if (Opc == UO_Deref && UO->getType()->hasAttr(attr::NoDeref) && !isa<ArrayType>(UO->getType().getDesugaredType(Context))) @@ -13898,9 +14663,13 @@ void Sema::ActOnStmtExprError() { PopExpressionEvaluationContext(); } -ExprResult -Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, - SourceLocation RPLoc) { // "({..})" +ExprResult Sema::ActOnStmtExpr(Scope *S, SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc) { + return BuildStmtExpr(LPLoc, SubStmt, RPLoc, getTemplateDepth(S)); +} + +ExprResult Sema::BuildStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, + SourceLocation RPLoc, unsigned TemplateDepth) { assert(SubStmt && isa<CompoundStmt>(SubStmt) && "Invalid action invocation!"); CompoundStmt *Compound = cast<CompoundStmt>(SubStmt); @@ -13931,7 +14700,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, // FIXME: Check that expression type is complete/non-abstract; statement // expressions are not lvalues. - Expr *ResStmtExpr = new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc); + Expr *ResStmtExpr = + new (Context) StmtExpr(Compound, Ty, LPLoc, RPLoc, TemplateDepth); if (StmtExprMayBindToTemp) return MaybeBindToTemporary(ResStmtExpr); return ResStmtExpr; @@ -14159,11 +14929,9 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; QualType resType; - bool ValueDependent = false; bool CondIsTrue = false; if (CondExpr->isTypeDependent() || CondExpr->isValueDependent()) { resType = Context.DependentTy; - ValueDependent = true; } else { // The conditional expression is required to be a constant expression. llvm::APSInt condEval(32); @@ -14179,14 +14947,12 @@ ExprResult Sema::ActOnChooseExpr(SourceLocation BuiltinLoc, Expr *ActiveExpr = CondIsTrue ? LHSExpr : RHSExpr; resType = ActiveExpr->getType(); - ValueDependent = ActiveExpr->isValueDependent(); VK = ActiveExpr->getValueKind(); OK = ActiveExpr->getObjectKind(); } - return new (Context) - ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, resType, VK, OK, RPLoc, - CondIsTrue, resType->isDependentType(), ValueDependent); + return new (Context) ChooseExpr(BuiltinLoc, CondExpr, LHSExpr, RHSExpr, + resType, VK, OK, RPLoc, CondIsTrue); } //===----------------------------------------------------------------------===// @@ -14297,11 +15063,12 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, if (ExplicitSignature) { for (unsigned I = 0, E = ExplicitSignature.getNumParams(); I != E; ++I) { ParmVarDecl *Param = ExplicitSignature.getParam(I); - if (Param->getIdentifier() == nullptr && - !Param->isImplicit() && - !Param->isInvalidDecl() && - !getLangOpts().CPlusPlus) - Diag(Param->getLocation(), diag::err_parameter_name_omitted); + if (Param->getIdentifier() == nullptr && !Param->isImplicit() && + !Param->isInvalidDecl() && !getLangOpts().CPlusPlus) { + // Diagnose this as an extension in C17 and earlier. + if (!getLangOpts().C2x) + Diag(Param->getLocation(), diag::ext_parameter_name_omitted_c2x); + } Params.push_back(Param); } @@ -14690,21 +15457,15 @@ ExprResult Sema::BuildSourceLocExpr(SourceLocExpr::IdentKind Kind, SourceLocExpr(Context, Kind, BuiltinLoc, RPLoc, ParentContext); } -bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp, - bool Diagnose) { +bool Sema::CheckConversionToObjCLiteral(QualType DstType, Expr *&Exp, + bool Diagnose) { if (!getLangOpts().ObjC) return false; const ObjCObjectPointerType *PT = DstType->getAs<ObjCObjectPointerType>(); if (!PT) return false; - - if (!PT->isObjCIdType()) { - // Check if the destination is the 'NSString' interface. - const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); - if (!ID || !ID->getIdentifier()->isStr("NSString")) - return false; - } + const ObjCInterfaceDecl *ID = PT->getInterfaceDecl(); // Ignore any parens, implicit casts (should only be // array-to-pointer decays), and not-so-opaque values. The last is @@ -14714,15 +15475,41 @@ bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp, if (OV->getSourceExpr()) SrcExpr = OV->getSourceExpr()->IgnoreParenImpCasts(); - StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr); - if (!SL || !SL->isAscii()) - return false; - if (Diagnose) { - Diag(SL->getBeginLoc(), diag::err_missing_atsign_prefix) - << FixItHint::CreateInsertion(SL->getBeginLoc(), "@"); - Exp = BuildObjCStringLiteral(SL->getBeginLoc(), SL).get(); + if (auto *SL = dyn_cast<StringLiteral>(SrcExpr)) { + if (!PT->isObjCIdType() && + !(ID && ID->getIdentifier()->isStr("NSString"))) + return false; + if (!SL->isAscii()) + return false; + + if (Diagnose) { + Diag(SL->getBeginLoc(), diag::err_missing_atsign_prefix) + << /*string*/0 << FixItHint::CreateInsertion(SL->getBeginLoc(), "@"); + Exp = BuildObjCStringLiteral(SL->getBeginLoc(), SL).get(); + } + return true; } - return true; + + if ((isa<IntegerLiteral>(SrcExpr) || isa<CharacterLiteral>(SrcExpr) || + isa<FloatingLiteral>(SrcExpr) || isa<ObjCBoolLiteralExpr>(SrcExpr) || + isa<CXXBoolLiteralExpr>(SrcExpr)) && + !SrcExpr->isNullPointerConstant( + getASTContext(), Expr::NPC_NeverValueDependent)) { + if (!ID || !ID->getIdentifier()->isStr("NSNumber")) + return false; + if (Diagnose) { + Diag(SrcExpr->getBeginLoc(), diag::err_missing_atsign_prefix) + << /*number*/1 + << FixItHint::CreateInsertion(SrcExpr->getBeginLoc(), "@"); + Expr *NumLit = + BuildObjCNumericLiteral(SrcExpr->getBeginLoc(), SrcExpr).get(); + if (NumLit) + Exp = NumLit; + } + return true; + } + + return false; } static bool maybeDiagnoseAssignmentToFunction(Sema &S, QualType DstType, @@ -14769,24 +15556,44 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, return false; case PointerToInt: - DiagKind = diag::ext_typecheck_convert_pointer_int; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_pointer_int; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_pointer_int; + } ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; case IntToPointer: - DiagKind = diag::ext_typecheck_convert_int_pointer; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_int_pointer; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_int_pointer; + } + ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); + MayHaveConvFixit = true; + break; + case IncompatibleFunctionPointer: + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_incompatible_function_pointer; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer; + } ConvHints.tryToFixConversion(SrcExpr, SrcType, DstType, *this); MayHaveConvFixit = true; break; case IncompatiblePointer: - if (Action == AA_Passing_CFAudited) + if (Action == AA_Passing_CFAudited) { DiagKind = diag::err_arc_typecheck_convert_incompatible_pointer; - else if (SrcType->isFunctionPointerType() && - DstType->isFunctionPointerType()) - DiagKind = diag::ext_typecheck_convert_incompatible_function_pointer; - else + } else if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_incompatible_pointer; + isInvalid = true; + } else { DiagKind = diag::ext_typecheck_convert_incompatible_pointer; - + } CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); if (Hint.isNull() && !CheckInferredResultType) { @@ -14799,15 +15606,27 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, MayHaveConvFixit = true; break; case IncompatiblePointerSign: - DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_incompatible_pointer_sign; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_incompatible_pointer_sign; + } break; case FunctionVoidPointer: - DiagKind = diag::ext_typecheck_convert_pointer_void_func; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_pointer_void_func; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_pointer_void_func; + } break; case IncompatiblePointerDiscardsQualifiers: { // Perform array-to-pointer decay if necessary. if (SrcType->isArrayType()) SrcType = Context.getArrayDecayedType(SrcType); + isInvalid = true; + Qualifiers lhq = SrcType->getPointeeType().getQualifiers(); Qualifiers rhq = DstType->getPointeeType().getQualifiers(); if (lhq.getAddressSpace() != rhq.getAddressSpace()) { @@ -14835,19 +15654,33 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, if (getLangOpts().CPlusPlus && IsStringLiteralToNonConstPointerConversion(SrcExpr, DstType)) return false; - DiagKind = diag::ext_typecheck_convert_discards_qualifiers; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_typecheck_convert_discards_qualifiers; + isInvalid = true; + } else { + DiagKind = diag::ext_typecheck_convert_discards_qualifiers; + } + break; case IncompatibleNestedPointerQualifiers: - DiagKind = diag::ext_nested_pointer_qualifier_mismatch; + if (getLangOpts().CPlusPlus) { + isInvalid = true; + DiagKind = diag::err_nested_pointer_qualifier_mismatch; + } else { + DiagKind = diag::ext_nested_pointer_qualifier_mismatch; + } break; case IncompatibleNestedPointerAddressSpaceMismatch: DiagKind = diag::err_typecheck_incompatible_nested_address_space; + isInvalid = true; break; case IntToBlockPointer: DiagKind = diag::err_int_to_block_pointer; + isInvalid = true; break; case IncompatibleBlockPointer: DiagKind = diag::err_typecheck_convert_incompatible_block_pointer; + isInvalid = true; break; case IncompatibleObjCQualifiedId: { if (SrcType->isObjCQualifiedIdType()) { @@ -14872,14 +15705,25 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, SrcType->castAs<ObjCObjectPointerType>()->getInterfaceType()) IFace = IFaceT->getDecl(); } - DiagKind = diag::warn_incompatible_qualified_id; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_incompatible_qualified_id; + isInvalid = true; + } else { + DiagKind = diag::warn_incompatible_qualified_id; + } break; } case IncompatibleVectors: - DiagKind = diag::warn_incompatible_vectors; + if (getLangOpts().CPlusPlus) { + DiagKind = diag::err_incompatible_vectors; + isInvalid = true; + } else { + DiagKind = diag::warn_incompatible_vectors; + } break; case IncompatibleObjCWeakRef: DiagKind = diag::err_arc_weak_unavailable_assign; + isInvalid = true; break; case Incompatible: if (maybeDiagnoseAssignmentToFunction(*this, DstType, SrcExpr)) { @@ -14937,9 +15781,10 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, HandleFunctionTypeMismatch(FDiag, SecondType, FirstType); Diag(Loc, FDiag); - if (DiagKind == diag::warn_incompatible_qualified_id && + if ((DiagKind == diag::warn_incompatible_qualified_id || + DiagKind == diag::err_incompatible_qualified_id) && PDecl && IFace && !IFace->hasDefinition()) - Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id) + Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id) << IFace << PDecl; if (SecondType == Context.OverloadTy) @@ -15064,6 +15909,12 @@ Sema::VerifyIntegerConstantExpression(Expr *E, llvm::APSInt *Result, return ExprError(); } + ExprResult RValueExpr = DefaultLvalueConversion(E); + if (RValueExpr.isInvalid()) + return ExprError(); + + E = RValueExpr.get(); + // Circumvent ICE checking in C++11 to avoid evaluating the expression twice // in the non-ICE case. if (!getLangOpts().CPlusPlus11 && E->isIntegerConstantExpr(Context)) { @@ -15251,7 +16102,7 @@ void Sema::WarnOnPendingNoDerefs(ExpressionEvaluationContextRecord &Rec) { /// and if so, remove it from the list of volatile-qualified assignments that /// we are going to warn are deprecated. void Sema::CheckUnusedVolatileAssignment(Expr *E) { - if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus2a) + if (!E->getType().isVolatileQualified() || !getLangOpts().CPlusPlus20) return; // Note: ignoring parens here is not justified by the standard rules, but @@ -15266,6 +16117,186 @@ void Sema::CheckUnusedVolatileAssignment(Expr *E) { } } +ExprResult Sema::CheckForImmediateInvocation(ExprResult E, FunctionDecl *Decl) { + if (!E.isUsable() || !Decl || !Decl->isConsteval() || isConstantEvaluated() || + RebuildingImmediateInvocation) + return E; + + /// Opportunistically remove the callee from ReferencesToConsteval if we can. + /// It's OK if this fails; we'll also remove this in + /// HandleImmediateInvocations, but catching it here allows us to avoid + /// walking the AST looking for it in simple cases. + if (auto *Call = dyn_cast<CallExpr>(E.get()->IgnoreImplicit())) + if (auto *DeclRef = + dyn_cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit())) + ExprEvalContexts.back().ReferenceToConsteval.erase(DeclRef); + + E = MaybeCreateExprWithCleanups(E); + + ConstantExpr *Res = ConstantExpr::Create( + getASTContext(), E.get(), + ConstantExpr::getStorageKind(Decl->getReturnType().getTypePtr(), + getASTContext()), + /*IsImmediateInvocation*/ true); + ExprEvalContexts.back().ImmediateInvocationCandidates.emplace_back(Res, 0); + return Res; +} + +static void EvaluateAndDiagnoseImmediateInvocation( + Sema &SemaRef, Sema::ImmediateInvocationCandidate Candidate) { + llvm::SmallVector<PartialDiagnosticAt, 8> Notes; + Expr::EvalResult Eval; + Eval.Diag = &Notes; + ConstantExpr *CE = Candidate.getPointer(); + bool Result = CE->EvaluateAsConstantExpr(Eval, Expr::EvaluateForCodeGen, + SemaRef.getASTContext(), true); + if (!Result || !Notes.empty()) { + Expr *InnerExpr = CE->getSubExpr()->IgnoreImplicit(); + if (auto *FunctionalCast = dyn_cast<CXXFunctionalCastExpr>(InnerExpr)) + InnerExpr = FunctionalCast->getSubExpr(); + FunctionDecl *FD = nullptr; + if (auto *Call = dyn_cast<CallExpr>(InnerExpr)) + FD = cast<FunctionDecl>(Call->getCalleeDecl()); + else if (auto *Call = dyn_cast<CXXConstructExpr>(InnerExpr)) + FD = Call->getConstructor(); + else + llvm_unreachable("unhandled decl kind"); + assert(FD->isConsteval()); + SemaRef.Diag(CE->getBeginLoc(), diag::err_invalid_consteval_call) << FD; + for (auto &Note : Notes) + SemaRef.Diag(Note.first, Note.second); + return; + } + CE->MoveIntoResult(Eval.Val, SemaRef.getASTContext()); +} + +static void RemoveNestedImmediateInvocation( + Sema &SemaRef, Sema::ExpressionEvaluationContextRecord &Rec, + SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator It) { + struct ComplexRemove : TreeTransform<ComplexRemove> { + using Base = TreeTransform<ComplexRemove>; + llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet; + SmallVector<Sema::ImmediateInvocationCandidate, 4> &IISet; + SmallVector<Sema::ImmediateInvocationCandidate, 4>::reverse_iterator + CurrentII; + ComplexRemove(Sema &SemaRef, llvm::SmallPtrSetImpl<DeclRefExpr *> &DR, + SmallVector<Sema::ImmediateInvocationCandidate, 4> &II, + SmallVector<Sema::ImmediateInvocationCandidate, + 4>::reverse_iterator Current) + : Base(SemaRef), DRSet(DR), IISet(II), CurrentII(Current) {} + void RemoveImmediateInvocation(ConstantExpr* E) { + auto It = std::find_if(CurrentII, IISet.rend(), + [E](Sema::ImmediateInvocationCandidate Elem) { + return Elem.getPointer() == E; + }); + assert(It != IISet.rend() && + "ConstantExpr marked IsImmediateInvocation should " + "be present"); + It->setInt(1); // Mark as deleted + } + ExprResult TransformConstantExpr(ConstantExpr *E) { + if (!E->isImmediateInvocation()) + return Base::TransformConstantExpr(E); + RemoveImmediateInvocation(E); + return Base::TransformExpr(E->getSubExpr()); + } + /// Base::TransfromCXXOperatorCallExpr doesn't traverse the callee so + /// we need to remove its DeclRefExpr from the DRSet. + ExprResult TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { + DRSet.erase(cast<DeclRefExpr>(E->getCallee()->IgnoreImplicit())); + return Base::TransformCXXOperatorCallExpr(E); + } + /// Base::TransformInitializer skip ConstantExpr so we need to visit them + /// here. + ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) { + if (!Init) + return Init; + /// ConstantExpr are the first layer of implicit node to be removed so if + /// Init isn't a ConstantExpr, no ConstantExpr will be skipped. + if (auto *CE = dyn_cast<ConstantExpr>(Init)) + if (CE->isImmediateInvocation()) + RemoveImmediateInvocation(CE); + return Base::TransformInitializer(Init, NotCopyInit); + } + ExprResult TransformDeclRefExpr(DeclRefExpr *E) { + DRSet.erase(E); + return E; + } + bool AlwaysRebuild() { return false; } + bool ReplacingOriginal() { return true; } + bool AllowSkippingCXXConstructExpr() { + bool Res = AllowSkippingFirstCXXConstructExpr; + AllowSkippingFirstCXXConstructExpr = true; + return Res; + } + bool AllowSkippingFirstCXXConstructExpr = true; + } Transformer(SemaRef, Rec.ReferenceToConsteval, + Rec.ImmediateInvocationCandidates, It); + + /// CXXConstructExpr with a single argument are getting skipped by + /// TreeTransform in some situtation because they could be implicit. This + /// can only occur for the top-level CXXConstructExpr because it is used + /// nowhere in the expression being transformed therefore will not be rebuilt. + /// Setting AllowSkippingFirstCXXConstructExpr to false will prevent from + /// skipping the first CXXConstructExpr. + if (isa<CXXConstructExpr>(It->getPointer()->IgnoreImplicit())) + Transformer.AllowSkippingFirstCXXConstructExpr = false; + + ExprResult Res = Transformer.TransformExpr(It->getPointer()->getSubExpr()); + assert(Res.isUsable()); + Res = SemaRef.MaybeCreateExprWithCleanups(Res); + It->getPointer()->setSubExpr(Res.get()); +} + +static void +HandleImmediateInvocations(Sema &SemaRef, + Sema::ExpressionEvaluationContextRecord &Rec) { + if ((Rec.ImmediateInvocationCandidates.size() == 0 && + Rec.ReferenceToConsteval.size() == 0) || + SemaRef.RebuildingImmediateInvocation) + return; + + /// When we have more then 1 ImmediateInvocationCandidates we need to check + /// for nested ImmediateInvocationCandidates. when we have only 1 we only + /// need to remove ReferenceToConsteval in the immediate invocation. + if (Rec.ImmediateInvocationCandidates.size() > 1) { + + /// Prevent sema calls during the tree transform from adding pointers that + /// are already in the sets. + llvm::SaveAndRestore<bool> DisableIITracking( + SemaRef.RebuildingImmediateInvocation, true); + + /// Prevent diagnostic during tree transfrom as they are duplicates + Sema::TentativeAnalysisScope DisableDiag(SemaRef); + + for (auto It = Rec.ImmediateInvocationCandidates.rbegin(); + It != Rec.ImmediateInvocationCandidates.rend(); It++) + if (!It->getInt()) + RemoveNestedImmediateInvocation(SemaRef, Rec, It); + } else if (Rec.ImmediateInvocationCandidates.size() == 1 && + Rec.ReferenceToConsteval.size()) { + struct SimpleRemove : RecursiveASTVisitor<SimpleRemove> { + llvm::SmallPtrSetImpl<DeclRefExpr *> &DRSet; + SimpleRemove(llvm::SmallPtrSetImpl<DeclRefExpr *> &S) : DRSet(S) {} + bool VisitDeclRefExpr(DeclRefExpr *E) { + DRSet.erase(E); + return DRSet.size(); + } + } Visitor(Rec.ReferenceToConsteval); + Visitor.TraverseStmt( + Rec.ImmediateInvocationCandidates.front().getPointer()->getSubExpr()); + } + for (auto CE : Rec.ImmediateInvocationCandidates) + if (!CE.getInt()) + EvaluateAndDiagnoseImmediateInvocation(SemaRef, CE); + for (auto DR : Rec.ReferenceToConsteval) { + auto *FD = cast<FunctionDecl>(DR->getDecl()); + SemaRef.Diag(DR->getBeginLoc(), diag::err_invalid_consteval_take_address) + << FD; + SemaRef.Diag(FD->getLocation(), diag::note_declared_at); + } +} + void Sema::PopExpressionEvaluationContext() { ExpressionEvaluationContextRecord& Rec = ExprEvalContexts.back(); unsigned NumTypos = Rec.NumTypos; @@ -15299,6 +16330,7 @@ void Sema::PopExpressionEvaluationContext() { } WarnOnPendingNoDerefs(Rec); + HandleImmediateInvocations(*this, Rec); // Warn on any volatile-qualified simple-assignments that are not discarded- // value expressions nor unevaluated operands (those cases get removed from @@ -15584,6 +16616,9 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (getLangOpts().CUDA) CheckCUDACall(Loc, Func); + if (getLangOpts().SYCLIsDevice) + checkSYCLDeviceFunction(Loc, Func); + // If we need a definition, try to create one. if (NeedDefinition && !Func->getBody()) { runWithSufficientStackSpace(Loc, [&] { @@ -15722,15 +16757,21 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (funcHasParameterSizeMangling(*this, Func)) CheckCompleteParameterTypesForMangler(*this, Func, Loc); - Func->markUsed(Context); - } + // In the MS C++ ABI, the compiler emits destructor variants where they are + // used. If the destructor is used here but defined elsewhere, mark the + // virtual base destructors referenced. If those virtual base destructors + // are inline, this will ensure they are defined when emitting the complete + // destructor variant. This checking may be redundant if the destructor is + // provided later in this TU. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (auto *Dtor = dyn_cast<CXXDestructorDecl>(Func)) { + CXXRecordDecl *Parent = Dtor->getParent(); + if (Parent->getNumVBases() > 0 && !Dtor->getBody()) + CheckCompleteDestructorVariant(Loc, Dtor); + } + } - if (LangOpts.OpenMP) { - markOpenMPDeclareVariantFuncsReferenced(Loc, Func, MightBeOdrUse); - if (LangOpts.OpenMPIsDevice) - checkOpenMPDeviceFunction(Loc, Func); - else - checkOpenMPHostFunction(Loc, Func); + Func->markUsed(Context); } } @@ -16022,6 +17063,10 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, if (HasConst) DeclRefType.addConst(); } + // Do not capture firstprivates in tasks. + if (S.isOpenMPPrivateDecl(Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel) != + OMPC_unknown) + return true; ByRef = S.isOpenMPCapturedByRef(Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel); } @@ -16106,9 +17151,10 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // Make sure that by-copy captures are of a complete and non-abstract type. if (!Invalid && BuildAndDiagnose) { if (!CaptureType->isDependentType() && - S.RequireCompleteType(Loc, CaptureType, - diag::err_capture_of_incomplete_type, - Var->getDeclName())) + S.RequireCompleteSizedType( + Loc, CaptureType, + diag::err_capture_of_incomplete_or_sizeless_type, + Var->getDeclName())) Invalid = true; else if (S.RequireNonAbstractType(Loc, CaptureType, diag::err_capture_of_abstract_type)) @@ -16250,12 +17296,14 @@ bool Sema::tryCaptureVariable( // just break here. Similarly, global variables that are captured in a // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { - bool IsOpenMPPrivateDecl = isOpenMPPrivateDecl(Var, RSI->OpenMPLevel); + OpenMPClauseKind IsOpenMPPrivateDecl = isOpenMPPrivateDecl( + Var, RSI->OpenMPLevel, RSI->OpenMPCaptureLevel); // If the variable is private (i.e. not captured) and has variably // modified type, we still need to capture the type for correct // codegen in all regions, associated with the construct. Currently, // it is captured in the innermost captured region only. - if (IsOpenMPPrivateDecl && Var->getType()->isVariablyModifiedType()) { + if (IsOpenMPPrivateDecl != OMPC_unknown && + Var->getType()->isVariablyModifiedType()) { QualType QTy = Var->getType(); if (ParmVarDecl *PVD = dyn_cast_or_null<ParmVarDecl>(Var)) QTy = PVD->getOriginalType(); @@ -16269,15 +17317,23 @@ bool Sema::tryCaptureVariable( captureVariablyModifiedType(Context, QTy, OuterRSI); } } - bool IsTargetCap = !IsOpenMPPrivateDecl && - isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); + bool IsTargetCap = + IsOpenMPPrivateDecl != OMPC_private && + isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel, + RSI->OpenMPCaptureLevel); + // Do not capture global if it is not privatized in outer regions. + bool IsGlobalCap = + IsGlobal && isOpenMPGlobalCapturedDecl(Var, RSI->OpenMPLevel, + RSI->OpenMPCaptureLevel); + // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the // enclosing region. Therefore, the capture is not initially nested. if (IsTargetCap) adjustOpenMPTargetScopeIndex(FunctionScopesIndex, RSI->OpenMPLevel); - if (IsTargetCap || IsOpenMPPrivateDecl) { + if (IsTargetCap || IsOpenMPPrivateDecl == OMPC_private || + (IsGlobal && !IsGlobalCap)) { Nested = !IsTargetCap; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); @@ -16493,7 +17549,7 @@ static ExprResult rebuildPotentialResultsAsNonOdrUsed(Sema &S, Expr *E, // Mark that this expression does not constitute an odr-use. auto MarkNotOdrUsed = [&] { - S.MaybeODRUseExprs.erase(E); + S.MaybeODRUseExprs.remove(E); if (LambdaScopeInfo *LSI = S.getCurLambda()) LSI->markVariableExprAsNonODRUsed(E); }; @@ -17025,6 +18081,11 @@ void Sema::MarkDeclRefReferenced(DeclRefExpr *E, const Expr *Base) { if (Method->isVirtual() && !Method->getDevirtualizedMethod(Base, getLangOpts().AppleKext)) OdrUse = false; + + if (auto *FD = dyn_cast<FunctionDecl>(E->getDecl())) + if (!isConstantEvaluated() && FD->isConsteval() && + !RebuildingImmediateInvocation) + ExprEvalContexts.back().ReferenceToConsteval.insert(E); MarkExprReferenced(*this, E->getLocation(), E->getDecl(), E, OdrUse); } @@ -17116,71 +18177,36 @@ void Sema::MarkDeclarationsReferencedInType(SourceLocation Loc, QualType T) { } namespace { - /// Helper class that marks all of the declarations referenced by - /// potentially-evaluated subexpressions as "referenced". - class EvaluatedExprMarker : public EvaluatedExprVisitor<EvaluatedExprMarker> { - Sema &S; - bool SkipLocalVariables; - - public: - typedef EvaluatedExprVisitor<EvaluatedExprMarker> Inherited; - - EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) - : Inherited(S.Context), S(S), SkipLocalVariables(SkipLocalVariables) { } - - void VisitDeclRefExpr(DeclRefExpr *E) { - // If we were asked not to visit local variables, don't. - if (SkipLocalVariables) { - if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) - if (VD->hasLocalStorage()) - return; - } - - S.MarkDeclRefReferenced(E); - } - - void VisitMemberExpr(MemberExpr *E) { - S.MarkMemberReferenced(E); - Inherited::VisitMemberExpr(E); - } - - void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { - S.MarkFunctionReferenced( - E->getBeginLoc(), - const_cast<CXXDestructorDecl *>(E->getTemporary()->getDestructor())); - Visit(E->getSubExpr()); - } - - void VisitCXXNewExpr(CXXNewExpr *E) { - if (E->getOperatorNew()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorNew()); - if (E->getOperatorDelete()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); - Inherited::VisitCXXNewExpr(E); - } +/// Helper class that marks all of the declarations referenced by +/// potentially-evaluated subexpressions as "referenced". +class EvaluatedExprMarker : public UsedDeclVisitor<EvaluatedExprMarker> { +public: + typedef UsedDeclVisitor<EvaluatedExprMarker> Inherited; + bool SkipLocalVariables; - void VisitCXXDeleteExpr(CXXDeleteExpr *E) { - if (E->getOperatorDelete()) - S.MarkFunctionReferenced(E->getBeginLoc(), E->getOperatorDelete()); - QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); - if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { - CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); - S.MarkFunctionReferenced(E->getBeginLoc(), S.LookupDestructor(Record)); - } + EvaluatedExprMarker(Sema &S, bool SkipLocalVariables) + : Inherited(S), SkipLocalVariables(SkipLocalVariables) {} - Inherited::VisitCXXDeleteExpr(E); - } + void visitUsedDecl(SourceLocation Loc, Decl *D) { + S.MarkFunctionReferenced(Loc, cast<FunctionDecl>(D)); + } - void VisitCXXConstructExpr(CXXConstructExpr *E) { - S.MarkFunctionReferenced(E->getBeginLoc(), E->getConstructor()); - Inherited::VisitCXXConstructExpr(E); + void VisitDeclRefExpr(DeclRefExpr *E) { + // If we were asked not to visit local variables, don't. + if (SkipLocalVariables) { + if (VarDecl *VD = dyn_cast<VarDecl>(E->getDecl())) + if (VD->hasLocalStorage()) + return; } + S.MarkDeclRefReferenced(E); + } - void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { - Visit(E->getExpr()); - } - }; -} + void VisitMemberExpr(MemberExpr *E) { + S.MarkMemberReferenced(E); + Visit(E->getBase()); + } +}; +} // namespace /// Mark any declarations that appear within this expression or any /// potentially-evaluated subexpressions as "referenced". @@ -18060,11 +19086,25 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { return ExprError(); } + case BuiltinType::IncompleteMatrixIdx: + Diag(cast<MatrixSubscriptExpr>(E->IgnoreParens()) + ->getRowIdx() + ->getBeginLoc(), + diag::err_matrix_incomplete_index); + return ExprError(); + // Expressions of unknown type. case BuiltinType::OMPArraySection: Diag(E->getBeginLoc(), diag::err_omp_array_section_use); return ExprError(); + // Expressions of unknown type. + case BuiltinType::OMPArrayShaping: + return ExprError(Diag(E->getBeginLoc(), diag::err_omp_array_shaping_use)); + + case BuiltinType::OMPIterator: + return ExprError(Diag(E->getBeginLoc(), diag::err_omp_iterator_use)); + // Everything else should be impossible. #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: @@ -18138,7 +19178,16 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); } -bool Sema::IsDependentFunctionNameExpr(Expr *E) { - assert(E->isTypeDependent()); - return isa<UnresolvedLookupExpr>(E); +ExprResult Sema::CreateRecoveryExpr(SourceLocation Begin, SourceLocation End, + ArrayRef<Expr *> SubExprs, QualType T) { + if (!Context.getLangOpts().RecoveryAST) + return ExprError(); + + if (isSFINAEContext()) + return ExprError(); + + if (T.isNull() || !Context.getLangOpts().RecoveryASTType) + // We don't know the concrete type, fallback to dependent type. + T = Context.DependentTy; + return RecoveryExpr::Create(Context, T, Begin, End, SubExprs); } diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index a73e6906fceb..d885920b6c14 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -11,6 +11,7 @@ /// //===----------------------------------------------------------------------===// +#include "clang/Sema/Template.h" #include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "TypeLocBuilder.h" @@ -155,196 +156,203 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // } // // See also PR6358 and PR6359. - // For this reason, we're currently only doing the C++03 version of this - // code; the C++0x version has to wait until we get a proper spec. - QualType SearchType; - DeclContext *LookupCtx = nullptr; - bool isDependent = false; - bool LookInScope = false; + // + // For now, we accept all the cases in which the name given could plausibly + // be interpreted as a correct destructor name, issuing off-by-default + // extension diagnostics on the cases that don't strictly conform to the + // C++20 rules. This basically means we always consider looking in the + // nested-name-specifier prefix, the complete nested-name-specifier, and + // the scope, and accept if we find the expected type in any of the three + // places. if (SS.isInvalid()) return nullptr; + // Whether we've failed with a diagnostic already. + bool Failed = false; + + llvm::SmallVector<NamedDecl*, 8> FoundDecls; + llvm::SmallSet<CanonicalDeclPtr<Decl>, 8> FoundDeclSet; + // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and // we know what type we're looking for. - if (ObjectTypePtr) - SearchType = GetTypeFromParser(ObjectTypePtr); + QualType SearchType = + ObjectTypePtr ? GetTypeFromParser(ObjectTypePtr) : QualType(); - if (SS.isSet()) { - NestedNameSpecifier *NNS = SS.getScopeRep(); - - bool AlreadySearched = false; - bool LookAtPrefix = true; - // C++11 [basic.lookup.qual]p6: - // If a pseudo-destructor-name (5.2.4) contains a nested-name-specifier, - // the type-names are looked up as types in the scope designated by the - // nested-name-specifier. Similarly, in a qualified-id of the form: - // - // nested-name-specifier[opt] class-name :: ~ class-name - // - // the second class-name is looked up in the same scope as the first. - // - // Here, we determine whether the code below is permitted to look at the - // prefix of the nested-name-specifier. - DeclContext *DC = computeDeclContext(SS, EnteringContext); - if (DC && DC->isFileContext()) { - AlreadySearched = true; - LookupCtx = DC; - isDependent = false; - } else if (DC && isa<CXXRecordDecl>(DC)) { - LookAtPrefix = false; - LookInScope = true; - } - - // The second case from the C++03 rules quoted further above. - NestedNameSpecifier *Prefix = nullptr; - if (AlreadySearched) { - // Nothing left to do. - } else if (LookAtPrefix && (Prefix = NNS->getPrefix())) { - CXXScopeSpec PrefixSS; - PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); - LookupCtx = computeDeclContext(PrefixSS, EnteringContext); - isDependent = isDependentScopeSpecifier(PrefixSS); - } else if (ObjectTypePtr) { - LookupCtx = computeDeclContext(SearchType); - isDependent = SearchType->isDependentType(); - } else { - LookupCtx = computeDeclContext(SS, EnteringContext); - isDependent = LookupCtx && LookupCtx->isDependentContext(); - } - } else if (ObjectTypePtr) { - // C++ [basic.lookup.classref]p3: - // If the unqualified-id is ~type-name, the type-name is looked up - // in the context of the entire postfix-expression. If the type T - // of the object expression is of a class type C, the type-name is - // also looked up in the scope of class C. At least one of the - // lookups shall find a name that refers to (possibly - // cv-qualified) T. - LookupCtx = computeDeclContext(SearchType); - isDependent = SearchType->isDependentType(); - assert((isDependent || !SearchType->isIncompleteType()) && - "Caller should have completed object type"); - - LookInScope = true; - } else { - // Perform lookup into the current scope (only). - LookInScope = true; - } - - TypeDecl *NonMatchingTypeDecl = nullptr; - LookupResult Found(*this, &II, NameLoc, LookupOrdinaryName); - for (unsigned Step = 0; Step != 2; ++Step) { - // Look for the name first in the computed lookup context (if we - // have one) and, if that fails to find a match, in the scope (if - // we're allowed to look there). - Found.clear(); - if (Step == 0 && LookupCtx) { - if (RequireCompleteDeclContext(SS, LookupCtx)) - return nullptr; - LookupQualifiedName(Found, LookupCtx); - } else if (Step == 1 && LookInScope && S) { - LookupName(Found, S); - } else { - continue; - } + auto CheckLookupResult = [&](LookupResult &Found) -> ParsedType { + auto IsAcceptableResult = [&](NamedDecl *D) -> bool { + auto *Type = dyn_cast<TypeDecl>(D->getUnderlyingDecl()); + if (!Type) + return false; - // FIXME: Should we be suppressing ambiguities here? - if (Found.isAmbiguous()) - return nullptr; + if (SearchType.isNull() || SearchType->isDependentType()) + return true; - if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); - MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); + return Context.hasSameUnqualifiedType(T, SearchType); + }; - if (SearchType.isNull() || SearchType->isDependentType() || - Context.hasSameUnqualifiedType(T, SearchType)) { - // We found our type! + unsigned NumAcceptableResults = 0; + for (NamedDecl *D : Found) { + if (IsAcceptableResult(D)) + ++NumAcceptableResults; + + // Don't list a class twice in the lookup failure diagnostic if it's + // found by both its injected-class-name and by the name in the enclosing + // scope. + if (auto *RD = dyn_cast<CXXRecordDecl>(D)) + if (RD->isInjectedClassName()) + D = cast<NamedDecl>(RD->getParent()); + + if (FoundDeclSet.insert(D).second) + FoundDecls.push_back(D); + } + + // As an extension, attempt to "fix" an ambiguity by erasing all non-type + // results, and all non-matching results if we have a search type. It's not + // clear what the right behavior is if destructor lookup hits an ambiguity, + // but other compilers do generally accept at least some kinds of + // ambiguity. + if (Found.isAmbiguous() && NumAcceptableResults == 1) { + Diag(NameLoc, diag::ext_dtor_name_ambiguous); + LookupResult::Filter F = Found.makeFilter(); + while (F.hasNext()) { + NamedDecl *D = F.next(); + if (auto *TD = dyn_cast<TypeDecl>(D->getUnderlyingDecl())) + Diag(D->getLocation(), diag::note_destructor_type_here) + << Context.getTypeDeclType(TD); + else + Diag(D->getLocation(), diag::note_destructor_nontype_here); + + if (!IsAcceptableResult(D)) + F.erase(); + } + F.done(); + } + + if (Found.isAmbiguous()) + Failed = true; + if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { + if (IsAcceptableResult(Type)) { + QualType T = Context.getTypeDeclType(Type); + MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); return CreateParsedType(T, Context.getTrivialTypeSourceInfo(T, NameLoc)); } + } - if (!SearchType.isNull()) - NonMatchingTypeDecl = Type; - } - - // If the name that we found is a class template name, and it is - // the same name as the template name in the last part of the - // nested-name-specifier (if present) or the object type, then - // this is the destructor for that class. - // FIXME: This is a workaround until we get real drafting for core - // issue 399, for which there isn't even an obvious direction. - if (ClassTemplateDecl *Template = Found.getAsSingle<ClassTemplateDecl>()) { - QualType MemberOfType; - if (SS.isSet()) { - if (DeclContext *Ctx = computeDeclContext(SS, EnteringContext)) { - // Figure out the type of the context, if it has one. - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Ctx)) - MemberOfType = Context.getTypeDeclType(Record); - } - } - if (MemberOfType.isNull()) - MemberOfType = SearchType; + return nullptr; + }; - if (MemberOfType.isNull()) - continue; + bool IsDependent = false; - // We're referring into a class template specialization. If the - // class template we found is the same as the template being - // specialized, we found what we are looking for. - if (const RecordType *Record = MemberOfType->getAs<RecordType>()) { - if (ClassTemplateSpecializationDecl *Spec - = dyn_cast<ClassTemplateSpecializationDecl>(Record->getDecl())) { - if (Spec->getSpecializedTemplate()->getCanonicalDecl() == - Template->getCanonicalDecl()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); - } + auto LookupInObjectType = [&]() -> ParsedType { + if (Failed || SearchType.isNull()) + return nullptr; - continue; - } + IsDependent |= SearchType->isDependentType(); - // We're referring to an unresolved class template - // specialization. Determine whether we class template we found - // is the same as the template being specialized or, if we don't - // know which template is being specialized, that it at least - // has the same name. - if (const TemplateSpecializationType *SpecType - = MemberOfType->getAs<TemplateSpecializationType>()) { - TemplateName SpecName = SpecType->getTemplateName(); - - // The class template we found is the same template being - // specialized. - if (TemplateDecl *SpecTemplate = SpecName.getAsTemplateDecl()) { - if (SpecTemplate->getCanonicalDecl() == Template->getCanonicalDecl()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + DeclContext *LookupCtx = computeDeclContext(SearchType); + if (!LookupCtx) + return nullptr; + LookupQualifiedName(Found, LookupCtx); + return CheckLookupResult(Found); + }; - continue; - } + auto LookupInNestedNameSpec = [&](CXXScopeSpec &LookupSS) -> ParsedType { + if (Failed) + return nullptr; - // The class template we found has the same name as the - // (dependent) template name being specialized. - if (DependentTemplateName *DepTemplate - = SpecName.getAsDependentTemplateName()) { - if (DepTemplate->isIdentifier() && - DepTemplate->getIdentifier() == Template->getIdentifier()) - return CreateParsedType( - MemberOfType, - Context.getTrivialTypeSourceInfo(MemberOfType, NameLoc)); + IsDependent |= isDependentScopeSpecifier(LookupSS); + DeclContext *LookupCtx = computeDeclContext(LookupSS, EnteringContext); + if (!LookupCtx) + return nullptr; - continue; - } - } + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + if (RequireCompleteDeclContext(LookupSS, LookupCtx)) { + Failed = true; + return nullptr; } + LookupQualifiedName(Found, LookupCtx); + return CheckLookupResult(Found); + }; + + auto LookupInScope = [&]() -> ParsedType { + if (Failed || !S) + return nullptr; + + LookupResult Found(*this, &II, NameLoc, LookupDestructorName); + LookupName(Found, S); + return CheckLookupResult(Found); + }; + + // C++2a [basic.lookup.qual]p6: + // In a qualified-id of the form + // + // nested-name-specifier[opt] type-name :: ~ type-name + // + // the second type-name is looked up in the same scope as the first. + // + // We interpret this as meaning that if you do a dual-scope lookup for the + // first name, you also do a dual-scope lookup for the second name, per + // C++ [basic.lookup.classref]p4: + // + // If the id-expression in a class member access is a qualified-id of the + // form + // + // class-name-or-namespace-name :: ... + // + // the class-name-or-namespace-name following the . or -> is first looked + // up in the class of the object expression and the name, if found, is used. + // Otherwise, it is looked up in the context of the entire + // postfix-expression. + // + // This looks in the same scopes as for an unqualified destructor name: + // + // C++ [basic.lookup.classref]p3: + // If the unqualified-id is ~ type-name, the type-name is looked up + // in the context of the entire postfix-expression. If the type T + // of the object expression is of a class type C, the type-name is + // also looked up in the scope of class C. At least one of the + // lookups shall find a name that refers to cv T. + // + // FIXME: The intent is unclear here. Should type-name::~type-name look in + // the scope anyway if it finds a non-matching name declared in the class? + // If both lookups succeed and find a dependent result, which result should + // we retain? (Same question for p->~type-name().) + + if (NestedNameSpecifier *Prefix = + SS.isSet() ? SS.getScopeRep()->getPrefix() : nullptr) { + // This is + // + // nested-name-specifier type-name :: ~ type-name + // + // Look for the second type-name in the nested-name-specifier. + CXXScopeSpec PrefixSS; + PrefixSS.Adopt(NestedNameSpecifierLoc(Prefix, SS.location_data())); + if (ParsedType T = LookupInNestedNameSpec(PrefixSS)) + return T; + } else { + // This is one of + // + // type-name :: ~ type-name + // ~ type-name + // + // Look in the scope and (if any) the object type. + if (ParsedType T = LookupInScope()) + return T; + if (ParsedType T = LookupInObjectType()) + return T; } - if (isDependent) { - // We didn't find our type, but that's okay: it's dependent - // anyway. + if (Failed) + return nullptr; + + if (IsDependent) { + // We didn't find our type, but that's OK: it's dependent anyway. // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), @@ -353,26 +361,98 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, return ParsedType::make(T); } - if (NonMatchingTypeDecl) { - QualType T = Context.getTypeDeclType(NonMatchingTypeDecl); - Diag(NameLoc, diag::err_destructor_expr_type_mismatch) - << T << SearchType; - Diag(NonMatchingTypeDecl->getLocation(), diag::note_destructor_type_here) - << T; - } else if (ObjectTypePtr) - Diag(NameLoc, diag::err_ident_in_dtor_not_a_type) - << &II; - else { - SemaDiagnosticBuilder DtorDiag = Diag(NameLoc, - diag::err_destructor_class_name); - if (S) { - const DeclContext *Ctx = S->getEntity(); - if (const CXXRecordDecl *Class = dyn_cast_or_null<CXXRecordDecl>(Ctx)) - DtorDiag << FixItHint::CreateReplacement(SourceRange(NameLoc), - Class->getNameAsString()); + // The remaining cases are all non-standard extensions imitating the behavior + // of various other compilers. + unsigned NumNonExtensionDecls = FoundDecls.size(); + + if (SS.isSet()) { + // For compatibility with older broken C++ rules and existing code, + // + // nested-name-specifier :: ~ type-name + // + // also looks for type-name within the nested-name-specifier. + if (ParsedType T = LookupInNestedNameSpec(SS)) { + Diag(SS.getEndLoc(), diag::ext_dtor_named_in_wrong_scope) + << SS.getRange() + << FixItHint::CreateInsertion(SS.getEndLoc(), + ("::" + II.getName()).str()); + return T; + } + + // For compatibility with other compilers and older versions of Clang, + // + // nested-name-specifier type-name :: ~ type-name + // + // also looks for type-name in the scope. Unfortunately, we can't + // reasonably apply this fallback for dependent nested-name-specifiers. + if (SS.getScopeRep()->getPrefix()) { + if (ParsedType T = LookupInScope()) { + Diag(SS.getEndLoc(), diag::ext_qualified_dtor_named_in_lexical_scope) + << FixItHint::CreateRemoval(SS.getRange()); + Diag(FoundDecls.back()->getLocation(), diag::note_destructor_type_here) + << GetTypeFromParser(T); + return T; + } } } + // We didn't find anything matching; tell the user what we did find (if + // anything). + + // Don't tell the user about declarations we shouldn't have found. + FoundDecls.resize(NumNonExtensionDecls); + + // List types before non-types. + std::stable_sort(FoundDecls.begin(), FoundDecls.end(), + [](NamedDecl *A, NamedDecl *B) { + return isa<TypeDecl>(A->getUnderlyingDecl()) > + isa<TypeDecl>(B->getUnderlyingDecl()); + }); + + // Suggest a fixit to properly name the destroyed type. + auto MakeFixItHint = [&]{ + const CXXRecordDecl *Destroyed = nullptr; + // FIXME: If we have a scope specifier, suggest its last component? + if (!SearchType.isNull()) + Destroyed = SearchType->getAsCXXRecordDecl(); + else if (S) + Destroyed = dyn_cast_or_null<CXXRecordDecl>(S->getEntity()); + if (Destroyed) + return FixItHint::CreateReplacement(SourceRange(NameLoc), + Destroyed->getNameAsString()); + return FixItHint(); + }; + + if (FoundDecls.empty()) { + // FIXME: Attempt typo-correction? + Diag(NameLoc, diag::err_undeclared_destructor_name) + << &II << MakeFixItHint(); + } else if (!SearchType.isNull() && FoundDecls.size() == 1) { + if (auto *TD = dyn_cast<TypeDecl>(FoundDecls[0]->getUnderlyingDecl())) { + assert(!SearchType.isNull() && + "should only reject a type result if we have a search type"); + QualType T = Context.getTypeDeclType(TD); + Diag(NameLoc, diag::err_destructor_expr_type_mismatch) + << T << SearchType << MakeFixItHint(); + } else { + Diag(NameLoc, diag::err_destructor_expr_nontype) + << &II << MakeFixItHint(); + } + } else { + Diag(NameLoc, SearchType.isNull() ? diag::err_destructor_name_nontype + : diag::err_destructor_expr_mismatch) + << &II << SearchType << MakeFixItHint(); + } + + for (NamedDecl *FoundD : FoundDecls) { + if (auto *TD = dyn_cast<TypeDecl>(FoundD->getUnderlyingDecl())) + Diag(FoundD->getLocation(), diag::note_destructor_type_here) + << Context.getTypeDeclType(TD); + else + Diag(FoundD->getLocation(), diag::note_destructor_nontype_here) + << FoundD; + } + return nullptr; } @@ -624,11 +704,11 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, } /// Build a Microsoft __uuidof expression with a type operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { - StringRef UuidStr; + MSGuidDecl *Guid = nullptr; if (!Operand->getType()->isDependentType()) { llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); @@ -636,22 +716,21 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + Guid = UuidAttrs.back()->getGuidDecl(); } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, Operand, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// Build a Microsoft __uuidof expression with an expression operand. -ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *E, - SourceLocation RParenLoc) { - StringRef UuidStr; +ExprResult Sema::BuildCXXUuidof(QualType Type, SourceLocation TypeidLoc, + Expr *E, SourceLocation RParenLoc) { + MSGuidDecl *Guid = nullptr; if (!E->getType()->isDependentType()) { if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - UuidStr = "00000000-0000-0000-0000-000000000000"; + // A null pointer results in {00000000-0000-0000-0000-000000000000}. + Guid = Context.getMSGuidDecl(MSGuidDecl::Parts{}); } else { llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; getUuidAttrOfType(*this, E->getType(), UuidAttrs); @@ -659,29 +738,20 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); if (UuidAttrs.size() > 1) return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - UuidStr = UuidAttrs.back()->getGuid(); + Guid = UuidAttrs.back()->getGuidDecl(); } } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, - SourceRange(TypeidLoc, RParenLoc)); + return new (Context) + CXXUuidofExpr(Type, E, Guid, SourceRange(TypeidLoc, RParenLoc)); } /// ActOnCXXUuidof - Parse __uuidof( type-id ) or __uuidof (expression); ExprResult Sema::ActOnCXXUuidof(SourceLocation OpLoc, SourceLocation LParenLoc, bool isType, void *TyOrExpr, SourceLocation RParenLoc) { - // If MSVCGuidDecl has not been cached, do the lookup. - if (!MSVCGuidDecl) { - IdentifierInfo *GuidII = &PP.getIdentifierTable().get("_GUID"); - LookupResult R(*this, GuidII, SourceLocation(), LookupTagName); - LookupQualifiedName(R, Context.getTranslationUnitDecl()); - MSVCGuidDecl = R.getAsSingle<RecordDecl>(); - if (!MSVCGuidDecl) - return ExprError(Diag(OpLoc, diag::err_need_header_before_ms_uuidof)); - } - - QualType GuidType = Context.getTypeDeclType(MSVCGuidDecl); + QualType GuidType = Context.getMSGuidType(); + GuidType.addConst(); if (isType) { // The operand is a type; handle it as such. @@ -876,6 +946,11 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, E->getSourceRange())) return true; + if (!isPointer && Ty->isSizelessType()) { + Diag(ThrowLoc, diag::err_throw_sizeless) << Ty << E->getSourceRange(); + return true; + } + if (RequireNonAbstractType(ThrowLoc, ExceptionObjectTy, diag::err_throw_abstract_type, E)) return true; @@ -1742,8 +1817,9 @@ Sema::isUnavailableAlignedAllocationFunction(const FunctionDecl &FD) const { return false; if (FD.isDefined()) return false; - bool IsAligned = false; - if (FD.isReplaceableGlobalAllocationFunction(&IsAligned) && IsAligned) + Optional<unsigned> AlignmentParam; + if (FD.isReplaceableGlobalAllocationFunction(&AlignmentParam) && + AlignmentParam.hasValue()) return true; return false; } @@ -2061,8 +2137,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { - const FunctionProtoType *Proto = - OperatorNew->getType()->getAs<FunctionProtoType>(); + auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>(); VariadicCallType CallType = Proto->isVariadic() ? VariadicFunction : VariadicDoesNotApply; @@ -2070,18 +2145,80 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // arguments. Skip the first parameter because we don't have a corresponding // argument. Skip the second parameter too if we're passing in the // alignment; we've already filled it in. + unsigned NumImplicitArgs = PassAlignment ? 2 : 1; if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, - PassAlignment ? 2 : 1, PlacementArgs, - AllPlaceArgs, CallType)) + NumImplicitArgs, PlacementArgs, AllPlaceArgs, + CallType)) return ExprError(); if (!AllPlaceArgs.empty()) PlacementArgs = AllPlaceArgs; - // FIXME: This is wrong: PlacementArgs misses out the first (size) argument. - DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); - - // FIXME: Missing call to CheckFunctionCall or equivalent + // We would like to perform some checking on the given `operator new` call, + // but the PlacementArgs does not contain the implicit arguments, + // namely allocation size and maybe allocation alignment, + // so we need to conjure them. + + QualType SizeTy = Context.getSizeType(); + unsigned SizeTyWidth = Context.getTypeSize(SizeTy); + + llvm::APInt SingleEltSize( + SizeTyWidth, Context.getTypeSizeInChars(AllocType).getQuantity()); + + // How many bytes do we want to allocate here? + llvm::Optional<llvm::APInt> AllocationSize; + if (!ArraySize.hasValue() && !AllocType->isDependentType()) { + // For non-array operator new, we only want to allocate one element. + AllocationSize = SingleEltSize; + } else if (KnownArraySize.hasValue() && !AllocType->isDependentType()) { + // For array operator new, only deal with static array size case. + bool Overflow; + AllocationSize = llvm::APInt(SizeTyWidth, *KnownArraySize) + .umul_ov(SingleEltSize, Overflow); + (void)Overflow; + assert( + !Overflow && + "Expected that all the overflows would have been handled already."); + } + + IntegerLiteral AllocationSizeLiteral( + Context, + AllocationSize.getValueOr(llvm::APInt::getNullValue(SizeTyWidth)), + SizeTy, SourceLocation()); + // Otherwise, if we failed to constant-fold the allocation size, we'll + // just give up and pass-in something opaque, that isn't a null pointer. + OpaqueValueExpr OpaqueAllocationSize(SourceLocation(), SizeTy, VK_RValue, + OK_Ordinary, /*SourceExpr=*/nullptr); + + // Let's synthesize the alignment argument in case we will need it. + // Since we *really* want to allocate these on stack, this is slightly ugly + // because there might not be a `std::align_val_t` type. + EnumDecl *StdAlignValT = getStdAlignValT(); + QualType AlignValT = + StdAlignValT ? Context.getTypeDeclType(StdAlignValT) : SizeTy; + IntegerLiteral AlignmentLiteral( + Context, + llvm::APInt(Context.getTypeSize(SizeTy), + Alignment / Context.getCharWidth()), + SizeTy, SourceLocation()); + ImplicitCastExpr DesiredAlignment(ImplicitCastExpr::OnStack, AlignValT, + CK_IntegralCast, &AlignmentLiteral, + VK_RValue); + + // Adjust placement args by prepending conjured size and alignment exprs. + llvm::SmallVector<Expr *, 8> CallArgs; + CallArgs.reserve(NumImplicitArgs + PlacementArgs.size()); + CallArgs.emplace_back(AllocationSize.hasValue() + ? static_cast<Expr *>(&AllocationSizeLiteral) + : &OpaqueAllocationSize); + if (PassAlignment) + CallArgs.emplace_back(&DesiredAlignment); + CallArgs.insert(CallArgs.end(), PlacementArgs.begin(), PlacementArgs.end()); + + DiagnoseSentinelCalls(OperatorNew, PlacementLParen, CallArgs); + + checkCall(OperatorNew, Proto, /*ThisArg=*/nullptr, CallArgs, + /*IsMemberFunction=*/false, StartLoc, Range, CallType); // Warn if the type is over-aligned and is being allocated by (unaligned) // global operator new. @@ -2193,7 +2330,8 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, return Diag(Loc, diag::err_bad_new_type) << AllocType << 1 << R; else if (!AllocType->isDependentType() && - RequireCompleteType(Loc, AllocType, diag::err_new_incomplete_type,R)) + RequireCompleteSizedType( + Loc, AllocType, diag::err_new_incomplete_or_sizeless_type, R)) return true; else if (RequireNonAbstractType(Loc, AllocType, diag::err_allocation_of_abstract_type)) @@ -2515,8 +2653,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // for template argument deduction and for comparison purposes. QualType ExpectedFunctionType; { - const FunctionProtoType *Proto - = OperatorNew->getType()->getAs<FunctionProtoType>(); + auto *Proto = OperatorNew->getType()->castAs<FunctionProtoType>(); SmallVector<QualType, 4> ArgTypes; ArgTypes.push_back(Context.VoidPtrTy); @@ -2835,6 +2972,7 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->setParams(ParamDecls); if (ExtraAttr) Alloc->addAttr(ExtraAttr); + AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(Alloc); Context.getTranslationUnitDecl()->addDecl(Alloc); IdResolver.tryAddTopLevelDecl(Alloc, Name); }; @@ -3319,7 +3457,8 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // this, so we treat it as a warning unless we're in a SFINAE context. Diag(StartLoc, diag::ext_delete_void_ptr_operand) << Type << Ex.get()->getSourceRange(); - } else if (Pointee->isFunctionType() || Pointee->isVoidType()) { + } else if (Pointee->isFunctionType() || Pointee->isVoidType() || + Pointee->isSizelessType()) { return ExprError(Diag(StartLoc, diag::err_delete_operand) << Type << Ex.get()->getSourceRange()); } else if (!Pointee->isDependentType()) { @@ -3865,15 +4004,17 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ICS.DiagnoseAmbiguousConversion(*this, From->getExprLoc(), PDiag(diag::err_typecheck_ambiguous_condition) << From->getSourceRange()); - return ExprError(); + return ExprError(); case ImplicitConversionSequence::EllipsisConversion: llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: - bool Diagnosed = - DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, - From->getType(), From, Action); + Sema::AssignConvertType ConvTy = + CheckAssignmentConstraints(From->getExprLoc(), ToType, From->getType()); + bool Diagnosed = DiagnoseAssignmentResult( + ConvTy == Compatible ? Incompatible : ConvTy, From->getExprLoc(), + ToType, From->getType(), From, Action); assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } @@ -4062,8 +4203,8 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, break; case ICK_Compatible_Conversion: - From = ImpCastExprToType(From, ToType, CK_NoOp, - VK_RValue, /*BasePath=*/nullptr, CCK).get(); + From = ImpCastExprToType(From, ToType, CK_NoOp, From->getValueKind(), + /*BasePath=*/nullptr, CCK).get(); break; case ICK_Writeback_Conversion: @@ -4213,9 +4354,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Case 2. _Complex x -> y } else { - const ComplexType *FromComplex = From->getType()->getAs<ComplexType>(); - assert(FromComplex); - + auto *FromComplex = From->getType()->castAs<ComplexType>(); QualType ElType = FromComplex->getElementType(); bool isFloatingComplex = ElType->isRealFloatingType(); @@ -4302,11 +4441,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, break; case ICK_Qualification: { - // The qualification keeps the category of the inner expression, unless the - // target type isn't a reference. - ExprValueKind VK = - ToType->isReferenceType() ? From->getValueKind() : VK_RValue; - + ExprValueKind VK = From->getValueKind(); CastKind CK = CK_NoOp; if (ToType->isReferenceType() && @@ -4348,6 +4483,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, VK_RValue, nullptr, CCK).get(); } + // Materialize a temporary if we're implicitly converting to a reference + // type. This is not required by the C++ rules but is necessary to maintain + // AST invariants. + if (ToType->isReferenceType() && From->isRValue()) { + ExprResult Res = TemporaryMaterializationConversion(From); + if (Res.isInvalid()) + return ExprError(); + From = Res.get(); + } + // If this conversion sequence succeeded and involved implicitly converting a // _Nullable type to a _Nonnull one, complain. if (!isCast(CCK)) @@ -4504,8 +4649,7 @@ static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, CXXMethodDecl *Operator = cast<CXXMethodDecl>(*Op); if((Operator->*IsDesiredOp)()) { FoundOperator = true; - const FunctionProtoType *CPT = - Operator->getType()->getAs<FunctionProtoType>(); + auto *CPT = Operator->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; @@ -4534,7 +4678,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, case UTT_IsArray: return T->isArrayType(); case UTT_IsPointer: - return T->isPointerType(); + return T->isAnyPointerType(); case UTT_IsLvalueReference: return T->isLValueReferenceType(); case UTT_IsRvalueReference: @@ -4754,8 +4898,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, if (C.getLangOpts().AccessControl && Destructor->getAccess() != AS_public) return false; if (UTT == UTT_IsNothrowDestructible) { - const FunctionProtoType *CPT = - Destructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Destructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT || !CPT->isNothrow()) return false; @@ -4843,8 +4986,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; @@ -4882,8 +5024,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; - const FunctionProtoType *CPT - = Constructor->getType()->getAs<FunctionProtoType>(); + auto *CPT = Constructor->getType()->castAs<FunctionProtoType>(); CPT = Self.ResolveExceptionSpec(KeyLoc, CPT); if (!CPT) return false; @@ -4976,20 +5117,19 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (RD && RD->isAbstract()) return false; - SmallVector<OpaqueValueExpr, 2> OpaqueArgExprs; + llvm::BumpPtrAllocator OpaqueExprAllocator; SmallVector<Expr *, 2> ArgExprs; ArgExprs.reserve(Args.size() - 1); for (unsigned I = 1, N = Args.size(); I != N; ++I) { QualType ArgTy = Args[I]->getType(); if (ArgTy->isObjectType() || ArgTy->isFunctionType()) ArgTy = S.Context.getRValueReferenceType(ArgTy); - OpaqueArgExprs.push_back( - OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), - ArgTy.getNonLValueExprType(S.Context), - Expr::getValueKindForType(ArgTy))); + ArgExprs.push_back( + new (OpaqueExprAllocator.Allocate<OpaqueValueExpr>()) + OpaqueValueExpr(Args[I]->getTypeLoc().getBeginLoc(), + ArgTy.getNonLValueExprType(S.Context), + Expr::getValueKindForType(ArgTy))); } - for (Expr &E : OpaqueArgExprs) - ArgExprs.push_back(&E); // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. @@ -5539,7 +5679,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, // C++2a allows functions with ref-qualifier & if their cv-qualifier-seq // is (exactly) 'const'. if (Proto->isConst() && !Proto->isVolatile()) - Diag(Loc, getLangOpts().CPlusPlus2a + Diag(Loc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_pointer_to_const_ref_member_on_rvalue : diag::ext_pointer_to_const_ref_member_on_rvalue); else @@ -5768,7 +5908,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, RHS = DefaultFunctionArrayLvalueConversion(RHS.get()); QualType CondType = Cond.get()->getType(); - const auto *CondVT = CondType->getAs<VectorType>(); + const auto *CondVT = CondType->castAs<VectorType>(); QualType CondElementTy = CondVT->getElementType(); unsigned CondElementCount = CondVT->getNumElements(); QualType LHSType = LHS.get()->getType(); @@ -5824,7 +5964,7 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, return {}; } ResultType = Context.getVectorType( - ResultElementTy, CondType->getAs<VectorType>()->getNumElements(), + ResultElementTy, CondType->castAs<VectorType>()->getNumElements(), VectorType::GenericVector); LHS = ImpCastExprToType(LHS.get(), ResultType, CK_VectorSplat); @@ -5833,9 +5973,9 @@ QualType Sema::CheckGNUVectorConditionalTypes(ExprResult &Cond, ExprResult &LHS, assert(!ResultType.isNull() && ResultType->isVectorType() && "Result should have been a vector type"); - QualType ResultElementTy = ResultType->getAs<VectorType>()->getElementType(); - unsigned ResultElementCount = - ResultType->getAs<VectorType>()->getNumElements(); + auto *ResultVectorTy = ResultType->castAs<VectorType>(); + QualType ResultElementTy = ResultVectorTy->getElementType(); + unsigned ResultElementCount = ResultVectorTy->getNumElements(); if (ResultElementCount != CondElementCount) { Diag(QuestionLoc, diag::err_conditional_vector_size) << CondType @@ -6632,8 +6772,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { else if (const MemberPointerType *MemPtr = T->getAs<MemberPointerType>()) T = MemPtr->getPointeeType(); - const FunctionType *FTy = T->getAs<FunctionType>(); - assert(FTy && "call to value not of function type?"); + auto *FTy = T->castAs<FunctionType>(); ReturnsRetained = FTy->getExtInfo().getProducesResult(); // ActOnStmtExpr arranges things so that StmtExprs of retainable @@ -6697,6 +6836,9 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { VK_RValue); } + if (E->getType().isDestructedType() == QualType::DK_nontrivial_c_struct) + Cleanup.setExprNeedsCleanups(true); + if (!getLangOpts().CPlusPlus) return E; @@ -6799,8 +6941,9 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { // a new AsmStmtWithTemporaries. CompoundStmt *CompStmt = CompoundStmt::Create( Context, SubStmt, SourceLocation(), SourceLocation()); - Expr *E = new (Context) StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), - SourceLocation()); + Expr *E = new (Context) + StmtExpr(CompStmt, Context.VoidTy, SourceLocation(), SourceLocation(), + /*FIXME TemplateDepth=*/0); return MaybeCreateExprWithCleanups(E); } @@ -6843,9 +6986,10 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return ExprError(); if (RHS.get() == BO->getRHS()) return E; - return new (Context) BinaryOperator( - BO->getLHS(), RHS.get(), BO_Comma, BO->getType(), BO->getValueKind(), - BO->getObjectKind(), BO->getOperatorLoc(), BO->getFPFeatures()); + return BinaryOperator::Create(Context, BO->getLHS(), RHS.get(), BO_Comma, + BO->getType(), BO->getValueKind(), + BO->getObjectKind(), BO->getOperatorLoc(), + BO->getFPFeatures(getLangOpts())); } } @@ -7317,7 +7461,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -7370,7 +7514,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), TemplateId->NumArgs); TypeResult T = ActOnTemplateIdType(S, - TemplateId->SS, + SS, TemplateId->TemplateKWLoc, TemplateId->Template, TemplateId->Name, @@ -7447,13 +7591,13 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, // a difference in ARC, but outside of ARC the resulting block literal // follows the normal lifetime rules for block literals instead of being // autoreleased. - DiagnosticErrorTrap Trap(Diags); PushExpressionEvaluationContext( ExpressionEvaluationContext::PotentiallyEvaluated); ExprResult BlockExp = BuildBlockForLambdaConversion( Exp.get()->getExprLoc(), Exp.get()->getExprLoc(), Method, Exp.get()); PopExpressionEvaluationContext(); + // FIXME: This note should be produced by a CodeSynthesisContext. if (BlockExp.isInvalid()) Diag(Exp.get()->getExprLoc(), diag::note_lambda_to_block_conv); return BlockExp; @@ -7512,61 +7656,6 @@ ExprResult Sema::ActOnNoexceptExpr(SourceLocation KeyLoc, SourceLocation, return BuildCXXNoexceptExpr(KeyLoc, Operand, RParen); } -static bool IsSpecialDiscardedValue(Expr *E) { - // In C++11, discarded-value expressions of a certain form are special, - // according to [expr]p10: - // The lvalue-to-rvalue conversion (4.1) is applied only if the - // expression is an lvalue of volatile-qualified type and it has - // one of the following forms: - E = E->IgnoreParens(); - - // - id-expression (5.1.1), - if (isa<DeclRefExpr>(E)) - return true; - - // - subscripting (5.2.1), - if (isa<ArraySubscriptExpr>(E)) - return true; - - // - class member access (5.2.5), - if (isa<MemberExpr>(E)) - return true; - - // - indirection (5.3.1), - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) - if (UO->getOpcode() == UO_Deref) - return true; - - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { - // - pointer-to-member operation (5.5), - if (BO->isPtrMemOp()) - return true; - - // - comma expression (5.18) where the right operand is one of the above. - if (BO->getOpcode() == BO_Comma) - return IsSpecialDiscardedValue(BO->getRHS()); - } - - // - conditional expression (5.16) where both the second and the third - // operands are one of the above, or - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) - return IsSpecialDiscardedValue(CO->getTrueExpr()) && - IsSpecialDiscardedValue(CO->getFalseExpr()); - // The related edge case of "*x ?: *x". - if (BinaryConditionalOperator *BCO = - dyn_cast<BinaryConditionalOperator>(E)) { - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(BCO->getTrueExpr())) - return IsSpecialDiscardedValue(OVE->getSourceExpr()) && - IsSpecialDiscardedValue(BCO->getFalseExpr()); - } - - // Objective-C++ extensions to the rule. - if (isa<PseudoObjectExpr>(E) || isa<ObjCIvarRefExpr>(E)) - return true; - - return false; -} - /// Perform the conversions required for an expression used in a /// context that ignores the result. ExprResult Sema::IgnoredValueConversions(Expr *E) { @@ -7591,23 +7680,20 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { return E; } - if (getLangOpts().CPlusPlus) { + if (getLangOpts().CPlusPlus) { // The C++11 standard defines the notion of a discarded-value expression; // normally, we don't need to do anything to handle it, but if it is a // volatile lvalue with a special form, we perform an lvalue-to-rvalue // conversion. - if (getLangOpts().CPlusPlus11 && E->isGLValue() && - E->getType().isVolatileQualified()) { - if (IsSpecialDiscardedValue(E)) { - ExprResult Res = DefaultLvalueConversion(E); - if (Res.isInvalid()) - return E; - E = Res.get(); - } else { - // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if - // it occurs as a discarded-value expression. - CheckUnusedVolatileAssignment(E); - } + if (getLangOpts().CPlusPlus11 && E->isReadIfDiscardedInCPlusPlus11()) { + ExprResult Res = DefaultLvalueConversion(E); + if (Res.isInvalid()) + return E; + E = Res.get(); + } else { + // Per C++2a [expr.ass]p5, a volatile assignment is not deprecated if + // it occurs as a discarded-value expression. + CheckUnusedVolatileAssignment(E); } // C++1z: @@ -8163,6 +8249,7 @@ public: ExprResult Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, + bool RecoverUncorrectedTypos, llvm::function_ref<ExprResult(Expr *)> Filter) { // If the current evaluation context indicates there are uncorrected typos // and the current expression isn't guaranteed to not have typos, try to @@ -8175,6 +8262,16 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, TyposResolved -= DelayedTypos.size(); if (Result.isInvalid() || Result.get() != E) { ExprEvalContexts.back().NumTypos -= TyposResolved; + if (Result.isInvalid() && RecoverUncorrectedTypos) { + struct TyposReplace : TreeTransform<TyposReplace> { + TyposReplace(Sema &SemaRef) : TreeTransform(SemaRef) {} + ExprResult TransformTypoExpr(clang::TypoExpr *E) { + return this->SemaRef.CreateRecoveryExpr(E->getBeginLoc(), + E->getEndLoc(), {}); + } + } TT(*this); + return TT.TransformExpr(E); + } return Result; } assert(TyposResolved == 0 && "Corrected typo but got same Expr back?"); @@ -8213,7 +8310,8 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, DiagnoseUnusedExprResult(FullExpr.get()); } - FullExpr = CorrectDelayedTyposInExpr(FullExpr.get()); + FullExpr = CorrectDelayedTyposInExpr(FullExpr.get(), /*InitDecl=*/nullptr, + /*RecoverUncorrectedTypos=*/true); if (FullExpr.isInvalid()) return ExprError(); @@ -8331,3 +8429,216 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } + +concepts::Requirement *Sema::ActOnSimpleRequirement(Expr *E) { + return BuildExprRequirement(E, /*IsSimple=*/true, + /*NoexceptLoc=*/SourceLocation(), + /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnTypeRequirement(SourceLocation TypenameKWLoc, CXXScopeSpec &SS, + SourceLocation NameLoc, IdentifierInfo *TypeName, + TemplateIdAnnotation *TemplateId) { + assert(((!TypeName && TemplateId) || (TypeName && !TemplateId)) && + "Exactly one of TypeName and TemplateId must be specified."); + TypeSourceInfo *TSI = nullptr; + if (TypeName) { + QualType T = CheckTypenameType(ETK_Typename, TypenameKWLoc, + SS.getWithLocInContext(Context), *TypeName, + NameLoc, &TSI, /*DeducedTypeContext=*/false); + if (T.isNull()) + return nullptr; + } else { + ASTTemplateArgsPtr ArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + TypeResult T = ActOnTypenameType(CurScope, TypenameKWLoc, SS, + TemplateId->TemplateKWLoc, + TemplateId->Template, TemplateId->Name, + TemplateId->TemplateNameLoc, + TemplateId->LAngleLoc, ArgsPtr, + TemplateId->RAngleLoc); + if (T.isInvalid()) + return nullptr; + if (GetTypeFromParser(T.get(), &TSI).isNull()) + return nullptr; + } + return BuildTypeRequirement(TSI); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement(Expr *E, SourceLocation NoexceptLoc) { + return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, + /*ReturnTypeRequirement=*/{}); +} + +concepts::Requirement * +Sema::ActOnCompoundRequirement( + Expr *E, SourceLocation NoexceptLoc, CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstraint, unsigned Depth) { + // C++2a [expr.prim.req.compound] p1.3.3 + // [..] the expression is deduced against an invented function template + // F [...] F is a void function template with a single type template + // parameter T declared with the constrained-parameter. Form a new + // cv-qualifier-seq cv by taking the union of const and volatile specifiers + // around the constrained-parameter. F has a single parameter whose + // type-specifier is cv T followed by the abstract-declarator. [...] + // + // The cv part is done in the calling function - we get the concept with + // arguments and the abstract declarator with the correct CV qualification and + // have to synthesize T and the single parameter of F. + auto &II = Context.Idents.get("expr-type"); + auto *TParam = TemplateTypeParmDecl::Create(Context, CurContext, + SourceLocation(), + SourceLocation(), Depth, + /*Index=*/0, &II, + /*Typename=*/true, + /*ParameterPack=*/false, + /*HasTypeConstraint=*/true); + + if (ActOnTypeConstraint(SS, TypeConstraint, TParam, + /*EllpsisLoc=*/SourceLocation())) + // Just produce a requirement with no type requirements. + return BuildExprRequirement(E, /*IsSimple=*/false, NoexceptLoc, {}); + + auto *TPL = TemplateParameterList::Create(Context, SourceLocation(), + SourceLocation(), + ArrayRef<NamedDecl *>(TParam), + SourceLocation(), + /*RequiresClause=*/nullptr); + return BuildExprRequirement( + E, /*IsSimple=*/false, NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement(TPL)); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( + Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { + auto Status = concepts::ExprRequirement::SS_Satisfied; + ConceptSpecializationExpr *SubstitutedConstraintExpr = nullptr; + if (E->isInstantiationDependent() || ReturnTypeRequirement.isDependent()) + Status = concepts::ExprRequirement::SS_Dependent; + else if (NoexceptLoc.isValid() && canThrow(E) == CanThrowResult::CT_Can) + Status = concepts::ExprRequirement::SS_NoexceptNotMet; + else if (ReturnTypeRequirement.isSubstitutionFailure()) + Status = concepts::ExprRequirement::SS_TypeRequirementSubstitutionFailure; + else if (ReturnTypeRequirement.isTypeConstraint()) { + // C++2a [expr.prim.req]p1.3.3 + // The immediately-declared constraint ([temp]) of decltype((E)) shall + // be satisfied. + TemplateParameterList *TPL = + ReturnTypeRequirement.getTypeConstraintTemplateParameterList(); + QualType MatchedType = + BuildDecltypeType(E, E->getBeginLoc()).getCanonicalType(); + llvm::SmallVector<TemplateArgument, 1> Args; + Args.push_back(TemplateArgument(MatchedType)); + TemplateArgumentList TAL(TemplateArgumentList::OnStack, Args); + MultiLevelTemplateArgumentList MLTAL(TAL); + for (unsigned I = 0; I < TPL->getDepth(); ++I) + MLTAL.addOuterRetainedLevel(); + Expr *IDC = + cast<TemplateTypeParmDecl>(TPL->getParam(0))->getTypeConstraint() + ->getImmediatelyDeclaredConstraint(); + ExprResult Constraint = SubstExpr(IDC, MLTAL); + assert(!Constraint.isInvalid() && + "Substitution cannot fail as it is simply putting a type template " + "argument into a concept specialization expression's parameter."); + + SubstitutedConstraintExpr = + cast<ConceptSpecializationExpr>(Constraint.get()); + if (!SubstitutedConstraintExpr->isSatisfied()) + Status = concepts::ExprRequirement::SS_ConstraintsNotSatisfied; + } + return new (Context) concepts::ExprRequirement(E, IsSimple, NoexceptLoc, + ReturnTypeRequirement, Status, + SubstitutedConstraintExpr); +} + +concepts::ExprRequirement * +Sema::BuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *ExprSubstitutionDiagnostic, + bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement ReturnTypeRequirement) { + return new (Context) concepts::ExprRequirement(ExprSubstitutionDiagnostic, + IsSimple, NoexceptLoc, + ReturnTypeRequirement); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement(TypeSourceInfo *Type) { + return new (Context) concepts::TypeRequirement(Type); +} + +concepts::TypeRequirement * +Sema::BuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return new (Context) concepts::TypeRequirement(SubstDiag); +} + +concepts::Requirement *Sema::ActOnNestedRequirement(Expr *Constraint) { + return BuildNestedRequirement(Constraint); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement(Expr *Constraint) { + ConstraintSatisfaction Satisfaction; + if (!Constraint->isInstantiationDependent() && + CheckConstraintSatisfaction(nullptr, {Constraint}, /*TemplateArgs=*/{}, + Constraint->getSourceRange(), Satisfaction)) + return nullptr; + return new (Context) concepts::NestedRequirement(Context, Constraint, + Satisfaction); +} + +concepts::NestedRequirement * +Sema::BuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return new (Context) concepts::NestedRequirement(SubstDiag); +} + +RequiresExprBodyDecl * +Sema::ActOnStartRequiresExpr(SourceLocation RequiresKWLoc, + ArrayRef<ParmVarDecl *> LocalParameters, + Scope *BodyScope) { + assert(BodyScope); + + RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create(Context, CurContext, + RequiresKWLoc); + + PushDeclContext(BodyScope, Body); + + for (ParmVarDecl *Param : LocalParameters) { + if (Param->hasDefaultArg()) + // C++2a [expr.prim.req] p4 + // [...] A local parameter of a requires-expression shall not have a + // default argument. [...] + Diag(Param->getDefaultArgRange().getBegin(), + diag::err_requires_expr_local_parameter_default_argument); + // Ignore default argument and move on + + Param->setDeclContext(Body); + // If this has an identifier, add it to the scope stack. + if (Param->getIdentifier()) { + CheckShadow(BodyScope, Param); + PushOnScopeChains(Param, BodyScope); + } + } + return Body; +} + +void Sema::ActOnFinishRequiresExpr() { + assert(CurContext && "DeclContext imbalance!"); + CurContext = CurContext->getLexicalParent(); + assert(CurContext && "Popped translation unit!"); +} + +ExprResult +Sema::ActOnRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation ClosingBraceLoc) { + return RequiresExpr::Create(Context, RequiresKWLoc, Body, LocalParameters, + Requirements, ClosingBraceLoc); +} diff --git a/clang/lib/Sema/SemaExprObjC.cpp b/clang/lib/Sema/SemaExprObjC.cpp index c61b13cf5980..228a1ec3ba1f 100644 --- a/clang/lib/Sema/SemaExprObjC.cpp +++ b/clang/lib/Sema/SemaExprObjC.cpp @@ -894,6 +894,62 @@ ExprResult Sema::BuildObjCArrayLiteral(SourceRange SR, MultiExprArg Elements) { ArrayWithObjectsMethod, SR)); } +/// Check for duplicate keys in an ObjC dictionary literal. For instance: +/// NSDictionary *nd = @{ @"foo" : @"bar", @"foo" : @"baz" }; +static void +CheckObjCDictionaryLiteralDuplicateKeys(Sema &S, + ObjCDictionaryLiteral *Literal) { + if (Literal->isValueDependent() || Literal->isTypeDependent()) + return; + + // NSNumber has quite relaxed equality semantics (for instance, @YES is + // considered equal to @1.0). For now, ignore floating points and just do a + // bit-width and sign agnostic integer compare. + struct APSIntCompare { + bool operator()(const llvm::APSInt &LHS, const llvm::APSInt &RHS) const { + return llvm::APSInt::compareValues(LHS, RHS) < 0; + } + }; + + llvm::DenseMap<StringRef, SourceLocation> StringKeys; + std::map<llvm::APSInt, SourceLocation, APSIntCompare> IntegralKeys; + + auto checkOneKey = [&](auto &Map, const auto &Key, SourceLocation Loc) { + auto Pair = Map.insert({Key, Loc}); + if (!Pair.second) { + S.Diag(Loc, diag::warn_nsdictionary_duplicate_key); + S.Diag(Pair.first->second, diag::note_nsdictionary_duplicate_key_here); + } + }; + + for (unsigned Idx = 0, End = Literal->getNumElements(); Idx != End; ++Idx) { + Expr *Key = Literal->getKeyValueElement(Idx).Key->IgnoreParenImpCasts(); + + if (auto *StrLit = dyn_cast<ObjCStringLiteral>(Key)) { + StringRef Bytes = StrLit->getString()->getBytes(); + SourceLocation Loc = StrLit->getExprLoc(); + checkOneKey(StringKeys, Bytes, Loc); + } + + if (auto *BE = dyn_cast<ObjCBoxedExpr>(Key)) { + Expr *Boxed = BE->getSubExpr(); + SourceLocation Loc = BE->getExprLoc(); + + // Check for @("foo"). + if (auto *Str = dyn_cast<StringLiteral>(Boxed->IgnoreParenImpCasts())) { + checkOneKey(StringKeys, Str->getBytes(), Loc); + continue; + } + + Expr::EvalResult Result; + if (Boxed->EvaluateAsInt(Result, S.getASTContext(), + Expr::SE_AllowSideEffects)) { + checkOneKey(IntegralKeys, Result.Val.getInt(), Loc); + } + } + } +} + ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, MutableArrayRef<ObjCDictionaryElement> Elements) { SourceLocation Loc = SR.getBegin(); @@ -1061,12 +1117,14 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, HasPackExpansions = true; } - QualType Ty - = Context.getObjCObjectPointerType( - Context.getObjCInterfaceType(NSDictionaryDecl)); - return MaybeBindToTemporary(ObjCDictionaryLiteral::Create( - Context, Elements, HasPackExpansions, Ty, - DictionaryWithObjectsMethod, SR)); + QualType Ty = Context.getObjCObjectPointerType( + Context.getObjCInterfaceType(NSDictionaryDecl)); + + auto *Literal = + ObjCDictionaryLiteral::Create(Context, Elements, HasPackExpansions, Ty, + DictionaryWithObjectsMethod, SR); + CheckObjCDictionaryLiteralDuplicateKeys(*this, Literal); + return MaybeBindToTemporary(Literal); } ExprResult Sema::BuildObjCEncodeExpression(SourceLocation AtLoc, @@ -1170,33 +1228,66 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc, } } -static void HelperToDiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, - Selector Sel, - ObjCMethodList &MethList, - bool &onlyDirect) { +static ObjCMethodDecl *LookupDirectMethodInMethodList(Sema &S, Selector Sel, + ObjCMethodList &MethList, + bool &onlyDirect, + bool &anyDirect) { + (void)Sel; ObjCMethodList *M = &MethList; - for (M = M->getNext(); M; M = M->getNext()) { + ObjCMethodDecl *DirectMethod = nullptr; + for (; M; M = M->getNext()) { ObjCMethodDecl *Method = M->getMethod(); - if (Method->getSelector() != Sel) + if (!Method) continue; - if (!Method->isDirectMethod()) + assert(Method->getSelector() == Sel && "Method with wrong selector in method list"); + if (Method->isDirectMethod()) { + anyDirect = true; + DirectMethod = Method; + } else onlyDirect = false; } + + return DirectMethod; } -static void DiagnoseDirectSelectorsExpr(Sema &S, SourceLocation AtLoc, - Selector Sel, bool &onlyDirect) { - for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), - e = S.MethodPool.end(); b != e; b++) { - // first, instance methods - ObjCMethodList &InstMethList = b->second.first; - HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, InstMethList, - onlyDirect); +// Search the global pool for (potentially) direct methods matching the given +// selector. If a non-direct method is found, set \param onlyDirect to false. If +// a direct method is found, set \param anyDirect to true. Returns a direct +// method, if any. +static ObjCMethodDecl *LookupDirectMethodInGlobalPool(Sema &S, Selector Sel, + bool &onlyDirect, + bool &anyDirect) { + auto Iter = S.MethodPool.find(Sel); + if (Iter == S.MethodPool.end()) + return nullptr; - // second, class methods - ObjCMethodList &ClsMethList = b->second.second; - HelperToDiagnoseDirectSelectorsExpr(S, AtLoc, Sel, ClsMethList, onlyDirect); - } + ObjCMethodDecl *DirectInstance = LookupDirectMethodInMethodList( + S, Sel, Iter->second.first, onlyDirect, anyDirect); + ObjCMethodDecl *DirectClass = LookupDirectMethodInMethodList( + S, Sel, Iter->second.second, onlyDirect, anyDirect); + + return DirectInstance ? DirectInstance : DirectClass; +} + +static ObjCMethodDecl *findMethodInCurrentClass(Sema &S, Selector Sel) { + auto *CurMD = S.getCurMethodDecl(); + if (!CurMD) + return nullptr; + ObjCInterfaceDecl *IFace = CurMD->getClassInterface(); + + // The language enforce that only one direct method is present in a given + // class, so we just need to find one method in the current class to know + // whether Sel is potentially direct in this context. + if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/true)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/true)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupMethod(Sel, /*isInstance=*/false)) + return MD; + if (ObjCMethodDecl *MD = IFace->lookupPrivateMethod(Sel, /*isInstance=*/false)) + return MD; + + return nullptr; } ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, @@ -1222,15 +1313,38 @@ ExprResult Sema::ParseObjCSelectorExpression(Selector Sel, } else Diag(SelLoc, diag::warn_undeclared_selector) << Sel; } else { - bool onlyDirect = Method->isDirectMethod(); - DiagnoseDirectSelectorsExpr(*this, AtLoc, Sel, onlyDirect); DiagnoseMismatchedSelectors(*this, AtLoc, Method, LParenLoc, RParenLoc, WarnMultipleSelectors); + + bool onlyDirect = true; + bool anyDirect = false; + ObjCMethodDecl *GlobalDirectMethod = + LookupDirectMethodInGlobalPool(*this, Sel, onlyDirect, anyDirect); + if (onlyDirect) { Diag(AtLoc, diag::err_direct_selector_expression) << Method->getSelector(); Diag(Method->getLocation(), diag::note_direct_method_declared_at) << Method->getDeclName(); + } else if (anyDirect) { + // If we saw any direct methods, see if we see a direct member of the + // current class. If so, the @selector will likely be used to refer to + // this direct method. + ObjCMethodDecl *LikelyTargetMethod = findMethodInCurrentClass(*this, Sel); + if (LikelyTargetMethod && LikelyTargetMethod->isDirectMethod()) { + Diag(AtLoc, diag::warn_potentially_direct_selector_expression) << Sel; + Diag(LikelyTargetMethod->getLocation(), + diag::note_direct_method_declared_at) + << LikelyTargetMethod->getDeclName(); + } else if (!LikelyTargetMethod) { + // Otherwise, emit the "strict" variant of this diagnostic, unless + // LikelyTargetMethod is non-direct. + Diag(AtLoc, diag::warn_strict_potentially_direct_selector_expression) + << Sel; + Diag(GlobalDirectMethod->getLocation(), + diag::note_direct_method_declared_at) + << GlobalDirectMethod->getDeclName(); + } } } @@ -1953,7 +2067,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { // Do not warn if user is using property-dot syntax to make call to // user named setter. - if (!(PDecl->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_setter)) + if (!(PDecl->getPropertyAttributes() & + ObjCPropertyAttribute::kind_setter)) Diag(MemberLoc, diag::warn_property_access_suggest) << MemberName << QualType(OPT, 0) << PDecl->getName() @@ -2570,6 +2685,16 @@ ExprResult Sema::BuildClassMessage(TypeSourceInfo *ReceiverTypeInfo, diag::err_illegal_message_expr_incomplete_type)) return ExprError(); + if (Method && Method->isDirectMethod() && SuperLoc.isValid()) { + Diag(SuperLoc, diag::err_messaging_super_with_direct_method) + << FixItHint::CreateReplacement( + SuperLoc, getLangOpts().ObjCAutoRefCount + ? "self" + : Method->getClassInterface()->getName()); + Diag(Method->getLocation(), diag::note_direct_method_declared_at) + << Method->getDeclName(); + } + // Warn about explicit call of +initialize on its own class. But not on 'super'. if (Method && Method->getMethodFamily() == OMF_initialize) { if (!SuperLoc.isValid()) { @@ -2774,9 +2899,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, ReceiverType->isIntegerType())) { // Implicitly convert integers and pointers to 'id' but emit a warning. // But not in ARC. - Diag(Loc, diag::warn_bad_receiver_type) - << ReceiverType - << Receiver->getSourceRange(); + Diag(Loc, diag::warn_bad_receiver_type) << ReceiverType << RecRange; if (ReceiverType->isPointerType()) { Receiver = ImpCastExprToType(Receiver, Context.getObjCIdType(), CK_CPointerToObjCPointerCast).get(); @@ -2927,11 +3050,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // definition is found in a module that's not visible. const ObjCInterfaceDecl *forwardClass = nullptr; if (RequireCompleteType(Loc, OCIType->getPointeeType(), - getLangOpts().ObjCAutoRefCount - ? diag::err_arc_receiver_forward_instance - : diag::warn_receiver_forward_instance, - Receiver? Receiver->getSourceRange() - : SourceRange(SuperLoc))) { + getLangOpts().ObjCAutoRefCount + ? diag::err_arc_receiver_forward_instance + : diag::warn_receiver_forward_instance, + RecRange)) { if (getLangOpts().ObjCAutoRefCount) return ExprError(); @@ -2993,8 +3115,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, return ExprError(); } else { // Reject other random receiver types (e.g. structs). - Diag(Loc, diag::err_bad_receiver_type) - << ReceiverType << Receiver->getSourceRange(); + Diag(Loc, diag::err_bad_receiver_type) << ReceiverType << RecRange; return ExprError(); } } @@ -3012,15 +3133,35 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, << Method->getDeclName(); } - if (ReceiverType->isObjCClassType() && !isImplicit) { - Diag(Receiver->getExprLoc(), - diag::err_messaging_class_with_direct_method); + // Under ARC, self can't be assigned, and doing a direct call to `self` + // when it's a Class is hence safe. For other cases, we can't trust `self` + // is what we think it is, so we reject it. + if (ReceiverType->isObjCClassType() && !isImplicit && + !(Receiver->isObjCSelfExpr() && getLangOpts().ObjCAutoRefCount)) { + { + DiagnosticBuilder Builder = + Diag(Receiver->getExprLoc(), + diag::err_messaging_class_with_direct_method); + if (Receiver->isObjCSelfExpr()) { + Builder.AddFixItHint(FixItHint::CreateReplacement( + RecRange, Method->getClassInterface()->getName())); + } + } Diag(Method->getLocation(), diag::note_direct_method_declared_at) << Method->getDeclName(); } if (SuperLoc.isValid()) { - Diag(SuperLoc, diag::err_messaging_super_with_direct_method); + { + DiagnosticBuilder Builder = + Diag(SuperLoc, diag::err_messaging_super_with_direct_method); + if (ReceiverType->isObjCClassType()) { + Builder.AddFixItHint(FixItHint::CreateReplacement( + SuperLoc, Method->getClassInterface()->getName())); + } else { + Builder.AddFixItHint(FixItHint::CreateReplacement(SuperLoc, "self")); + } + } Diag(Method->getLocation(), diag::note_direct_method_declared_at) << Method->getDeclName(); } @@ -3232,7 +3373,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!isImplicit && Method) { if (const ObjCPropertyDecl *Prop = Method->findPropertyDecl()) { bool IsWeak = - Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak; + Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak; if (!IsWeak && Sel.isUnarySelector()) IsWeak = ReturnType.getObjCLifetime() & Qualifiers::OCL_Weak; if (IsWeak && !isUnevaluatedContext() && @@ -4337,7 +4478,7 @@ Sema::CheckObjCConversion(SourceRange castRange, QualType castType, // to 'NSString *', instead of falling through to report a "bridge cast" // diagnostic. if (castACTC == ACTC_retainable && exprACTC == ACTC_none && - ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) + CheckConversionToObjCLiteral(castType, castExpr, Diagnose)) return ACR_error; // Do not issue "bridge cast" diagnostic when implicit casting @@ -4400,9 +4541,10 @@ Expr *Sema::stripARCUnbridgedCast(Expr *e) { } else if (UnaryOperator *uo = dyn_cast<UnaryOperator>(e)) { assert(uo->getOpcode() == UO_Extension); Expr *sub = stripARCUnbridgedCast(uo->getSubExpr()); - return new (Context) - UnaryOperator(sub, UO_Extension, sub->getType(), sub->getValueKind(), - sub->getObjectKind(), uo->getOperatorLoc(), false); + return UnaryOperator::Create(Context, sub, UO_Extension, sub->getType(), + sub->getValueKind(), sub->getObjectKind(), + uo->getOperatorLoc(), false, + CurFPFeatureOverrides()); } else if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { assert(!gse->isResultDependent()); diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 785637761e71..eb07de65d266 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -17,6 +17,7 @@ #include "clang/AST/ExprOpenMP.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/CharInfo.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Initialization.h" @@ -1092,7 +1093,7 @@ void InitListChecker::CheckImplicitInitList(const InitializedEntity &Entity, auto *CXXRD = T->getAsCXXRecordDecl(); if (!VerifyOnly && CXXRD && CXXRD->hasUserDeclaredConstructor()) { SemaRef.Diag(StructuredSubobjectInitList->getBeginLoc(), - diag::warn_cxx2a_compat_aggregate_init_with_ctors) + diag::warn_cxx20_compat_aggregate_init_with_ctors) << StructuredSubobjectInitList->getSourceRange() << T; } } @@ -1118,14 +1119,14 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Result: // Extra braces here are suspicious. - DiagID = diag::warn_braces_around_scalar_init; + DiagID = diag::warn_braces_around_init; break; case InitializedEntity::EK_Member: // Warn on aggregate initialization but not on ctor init list or // default member initializer. if (Entity.getParent()) - DiagID = diag::warn_braces_around_scalar_init; + DiagID = diag::warn_braces_around_init; break; case InitializedEntity::EK_Variable: @@ -1156,9 +1157,9 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, if (DiagID) { S.Diag(Braces.getBegin(), DiagID) - << Braces - << FixItHint::CreateRemoval(Braces.getBegin()) - << FixItHint::CreateRemoval(Braces.getEnd()); + << Entity.getType()->isSizelessBuiltinType() << Braces + << FixItHint::CreateRemoval(Braces.getBegin()) + << FixItHint::CreateRemoval(Braces.getEnd()); } } @@ -1202,6 +1203,12 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, : diag::ext_excess_initializers_in_char_array_initializer; SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) << IList->getInit(Index)->getSourceRange(); + } else if (T->isSizelessBuiltinType()) { + unsigned DK = ExtraInitsIsError + ? diag::err_excess_initializers_for_sizeless_type + : diag::ext_excess_initializers_for_sizeless_type; + SemaRef.Diag(IList->getInit(Index)->getBeginLoc(), DK) + << T << IList->getInit(Index)->getSourceRange(); } else { int initKind = T->isArrayType() ? 0 : T->isVectorType() ? 1 : @@ -1235,7 +1242,7 @@ void InitListChecker::CheckExplicitInitList(const InitializedEntity &Entity, if (!HasEquivCtor) { SemaRef.Diag(IList->getBeginLoc(), - diag::warn_cxx2a_compat_aggregate_init_with_ctors) + diag::warn_cxx20_compat_aggregate_init_with_ctors) << IList->getSourceRange() << T; } } @@ -1294,7 +1301,8 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, if (!VerifyOnly) SemaRef.Diag(IList->getBeginLoc(), diag::err_init_objc_class) << DeclType; hadError = true; - } else if (DeclType->isOCLIntelSubgroupAVCType()) { + } else if (DeclType->isOCLIntelSubgroupAVCType() || + DeclType->isSizelessBuiltinType()) { // Checks for scalar type are sufficient for these types too. CheckScalarType(Entity, IList, DeclType, Index, StructuredList, StructuredIndex); @@ -1507,12 +1515,20 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, InitListExpr *StructuredList, unsigned &StructuredIndex) { if (Index >= IList->getNumInits()) { - if (!VerifyOnly) - SemaRef.Diag(IList->getBeginLoc(), - SemaRef.getLangOpts().CPlusPlus11 - ? diag::warn_cxx98_compat_empty_scalar_initializer - : diag::err_empty_scalar_initializer) - << IList->getSourceRange(); + if (!VerifyOnly) { + if (DeclType->isSizelessBuiltinType()) + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_sizeless_initializer + : diag::err_empty_sizeless_initializer) + << DeclType << IList->getSourceRange(); + else + SemaRef.Diag(IList->getBeginLoc(), + SemaRef.getLangOpts().CPlusPlus11 + ? diag::warn_cxx98_compat_empty_scalar_initializer + : diag::err_empty_scalar_initializer) + << IList->getSourceRange(); + } hadError = !SemaRef.getLangOpts().CPlusPlus11; ++Index; ++StructuredIndex; @@ -1524,17 +1540,18 @@ void InitListChecker::CheckScalarType(const InitializedEntity &Entity, // FIXME: This is invalid, and accepting it causes overload resolution // to pick the wrong overload in some corner cases. if (!VerifyOnly) - SemaRef.Diag(SubIList->getBeginLoc(), - diag::ext_many_braces_around_scalar_init) - << SubIList->getSourceRange(); + SemaRef.Diag(SubIList->getBeginLoc(), diag::ext_many_braces_around_init) + << DeclType->isSizelessBuiltinType() << SubIList->getSourceRange(); CheckScalarType(Entity, SubIList, DeclType, Index, StructuredList, StructuredIndex); return; } else if (isa<DesignatedInitExpr>(expr)) { if (!VerifyOnly) - SemaRef.Diag(expr->getBeginLoc(), diag::err_designator_for_scalar_init) - << DeclType << expr->getSourceRange(); + SemaRef.Diag(expr->getBeginLoc(), + diag::err_designator_for_scalar_or_sizeless_init) + << DeclType->isSizelessBuiltinType() << DeclType + << expr->getSourceRange(); hadError = true; ++Index; ++StructuredIndex; @@ -1621,7 +1638,7 @@ void InitListChecker::CheckReferenceType(const InitializedEntity &Entity, expr = Result.getAs<Expr>(); // FIXME: Why are we updating the syntactic init list? - if (!VerifyOnly) + if (!VerifyOnly && expr) IList->setInit(Index, expr); if (hadError) @@ -3477,6 +3494,7 @@ bool InitializationSequence::isAmbiguous() const { case FK_NonConstLValueReferenceBindingToTemporary: case FK_NonConstLValueReferenceBindingToBitfield: case FK_NonConstLValueReferenceBindingToVectorElement: + case FK_NonConstLValueReferenceBindingToMatrixElement: case FK_NonConstLValueReferenceBindingToUnrelated: case FK_RValueReferenceBindingToLValue: case FK_ReferenceAddrspaceMismatchTemporary: @@ -4420,16 +4438,20 @@ static void TryListInitialization(Sema &S, // direct-list-initialization and copy-initialization otherwise. // We can't use InitListChecker for this, because it always performs // copy-initialization. This only matters if we might use an 'explicit' - // conversion operator, so we only need to handle the cases where the source - // is of record type. - if (InitList->getInit(0)->getType()->isRecordType()) { + // conversion operator, or for the special case conversion of nullptr_t to + // bool, so we only need to handle those cases. + // + // FIXME: Why not do this in all cases? + Expr *Init = InitList->getInit(0); + if (Init->getType()->isRecordType() || + (Init->getType()->isNullPtrType() && DestType->isBooleanType())) { InitializationKind SubKind = Kind.getKind() == InitializationKind::IK_DirectList ? InitializationKind::CreateDirect(Kind.getLocation(), InitList->getLBraceLoc(), InitList->getRBraceLoc()) : Kind; - Expr *SubInit[1] = { InitList->getInit(0) }; + Expr *SubInit[1] = { Init }; Sequence.InitializeFrom(S, Entity, SubKind, SubInit, /*TopLevelOfInitList*/true, TreatUnavailableAsInvalid); @@ -4666,10 +4688,14 @@ static void TryReferenceInitialization(Sema &S, /// which a reference can never bind). Attempting to bind a reference to /// such a glvalue will always create a temporary. static bool isNonReferenceableGLValue(Expr *E) { - return E->refersToBitField() || E->refersToVectorElement(); + return E->refersToBitField() || E->refersToVectorElement() || + E->refersToMatrixElement(); } /// Reference initialization without resolving overloaded functions. +/// +/// We also can get here in C if we call a builtin which is declared as +/// a function with a parameter of reference type (such as __builtin_va_end()). static void TryReferenceInitializationCore(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4746,15 +4772,20 @@ static void TryReferenceInitializationCore(Sema &S, // an rvalue. DR1287 removed the "implicitly" here. if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && (isLValueRef || InitCategory.isRValue())) { - ConvOvlResult = TryRefInitWithConversionFunction( - S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef, - /*IsLValueRef*/ isLValueRef, Sequence); - if (ConvOvlResult == OR_Success) - return; - if (ConvOvlResult != OR_No_Viable_Function) - Sequence.SetOverloadFailure( - InitializationSequence::FK_ReferenceInitOverloadFailed, - ConvOvlResult); + if (S.getLangOpts().CPlusPlus) { + // Try conversion functions only for C++. + ConvOvlResult = TryRefInitWithConversionFunction( + S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef, + /*IsLValueRef*/ isLValueRef, Sequence); + if (ConvOvlResult == OR_Success) + return; + if (ConvOvlResult != OR_No_Viable_Function) + Sequence.SetOverloadFailure( + InitializationSequence::FK_ReferenceInitOverloadFailed, + ConvOvlResult); + } else { + ConvOvlResult = OR_No_Viable_Function; + } } } @@ -4787,6 +4818,9 @@ static void TryReferenceInitializationCore(Sema &S, else if (Initializer->refersToVectorElement()) FK = InitializationSequence:: FK_NonConstLValueReferenceBindingToVectorElement; + else if (Initializer->refersToMatrixElement()) + FK = InitializationSequence:: + FK_NonConstLValueReferenceBindingToMatrixElement; else llvm_unreachable("unexpected kind of compatible initializer"); break; @@ -4924,7 +4958,7 @@ static void TryReferenceInitializationCore(Sema &S, ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, TempEntity.getType(), /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, + Sema::AllowedExplicit::None, /*FIXME:InOverloadResolution=*/false, /*CStyle=*/Kind.isCStyleOrFunctionalCast(), /*AllowObjCWritebackConversion=*/false); @@ -5620,7 +5654,7 @@ void InitializationSequence::InitializeFrom(Sema &S, if (S.CheckObjCBridgeRelatedConversions(Initializer->getBeginLoc(), DestType, Initializer->getType(), Initializer) || - S.ConversionToObjCStringLiteralCheck(DestType, Initializer)) + S.CheckConversionToObjCLiteral(DestType, Initializer)) Args[0] = Initializer; } if (!isa<InitListExpr>(Initializer)) @@ -5854,6 +5888,19 @@ void InitializationSequence::InitializeFrom(Sema &S, return; } + // - Otherwise, if the initialization is direct-initialization, the source + // type is std::nullptr_t, and the destination type is bool, the initial + // value of the object being initialized is false. + if (!SourceType.isNull() && SourceType->isNullPtrType() && + DestType->isBooleanType() && + Kind.getKind() == InitializationKind::IK_Direct) { + AddConversionSequenceStep( + ImplicitConversionSequence::getNullptrToBool(SourceType, DestType, + Initializer->isGLValue()), + DestType); + return; + } + // - Otherwise, the initial value of the object being initialized is the // (possibly converted) value of the initializer expression. Standard // conversions (Clause 4) will be used, if necessary, to convert the @@ -5863,7 +5910,7 @@ void InitializationSequence::InitializeFrom(Sema &S, ImplicitConversionSequence ICS = S.TryImplicitConversion(Initializer, DestType, /*SuppressUserConversions*/true, - /*AllowExplicitConversions*/ false, + Sema::AllowedExplicit::None, /*InOverloadResolution*/ false, /*CStyle=*/Kind.isCStyleOrFunctionalCast(), allowObjCWritebackConversion); @@ -6416,12 +6463,14 @@ PerformConstructorInitialization(Sema &S, } S.MarkFunctionReferenced(Loc, Constructor); - CurInit = CXXTemporaryObjectExpr::Create( - S.Context, Constructor, - Entity.getType().getNonLValueExprType(S.Context), TSInfo, - ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates, - IsListInitialization, IsStdInitListInitialization, - ConstructorInitRequiresZeroInit); + CurInit = S.CheckForImmediateInvocation( + CXXTemporaryObjectExpr::Create( + S.Context, Constructor, + Entity.getType().getNonLValueExprType(S.Context), TSInfo, + ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates, + IsListInitialization, IsStdInitListInitialization, + ConstructorInitRequiresZeroInit), + Constructor); } else { CXXConstructExpr::ConstructionKind ConstructKind = CXXConstructExpr::CK_Complete; @@ -8159,9 +8208,13 @@ ExprResult InitializationSequence::Perform(Sema &S, if (const auto *ToPtrType = Step->Type->getAs<PointerType>()) { if (FromPtrType->getPointeeType()->hasAttr(attr::NoDeref) && !ToPtrType->getPointeeType()->hasAttr(attr::NoDeref)) { - S.Diag(CurInit.get()->getExprLoc(), - diag::warn_noderef_to_dereferenceable_pointer) - << CurInit.get()->getSourceRange(); + // Do not check static casts here because they are checked earlier + // in Sema::ActOnCXXNamedCast() + if (!Kind.isStaticCast()) { + S.Diag(CurInit.get()->getExprLoc(), + diag::warn_noderef_to_dereferenceable_pointer) + << CurInit.get()->getSourceRange(); + } } } } @@ -8762,7 +8815,7 @@ bool InitializationSequence::Diagnose(Sema &S, case FK_UTF8StringIntoPlainChar: S.Diag(Kind.getLocation(), diag::err_array_init_utf8_string_into_char) - << S.getLangOpts().CPlusPlus2a; + << S.getLangOpts().CPlusPlus20; break; case FK_ArrayTypeMismatch: case FK_NonConstantArrayInit: @@ -8889,6 +8942,11 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); break; + case FK_NonConstLValueReferenceBindingToMatrixElement: + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_matrix_element) + << DestType.isVolatileQualified() << Args[0]->getSourceRange(); + break; + case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) << DestType.getNonReferenceType() << OnlyArg->getType() @@ -9234,6 +9292,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "non-const lvalue reference bound to vector element"; break; + case FK_NonConstLValueReferenceBindingToMatrixElement: + OS << "non-const lvalue reference bound to matrix element"; + break; + case FK_NonConstLValueReferenceBindingToUnrelated: OS << "non-const lvalue reference bound to unrelated type"; break; diff --git a/clang/lib/Sema/SemaLambda.cpp b/clang/lib/Sema/SemaLambda.cpp index c2d14a44f53d..657ed13f207a 100644 --- a/clang/lib/Sema/SemaLambda.cpp +++ b/clang/lib/Sema/SemaLambda.cpp @@ -791,7 +791,8 @@ QualType Sema::buildLambdaInitCaptureInitialization( // deduce against. QualType DeductType = Context.getAutoDeductType(); TypeLocBuilder TLB; - TLB.pushTypeSpec(DeductType).setNameLoc(Loc); + AutoTypeLoc TL = TLB.push<AutoTypeLoc>(DeductType); + TL.setNameLoc(Loc); if (ByRef) { DeductType = BuildReferenceType(DeductType, true, Loc, Id); assert(!DeductType.isNull() && "can't build reference to auto"); @@ -799,7 +800,7 @@ QualType Sema::buildLambdaInitCaptureInitialization( } if (EllipsisLoc.isValid()) { if (Init->containsUnexpandedParameterPack()) { - Diag(EllipsisLoc, getLangOpts().CPlusPlus2a + Diag(EllipsisLoc, getLangOpts().CPlusPlus20 ? diag::warn_cxx17_compat_init_capture_pack : diag::ext_init_capture_pack); DeductType = Context.getPackExpansionType(DeductType, NumExpansions); @@ -989,8 +990,7 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // Attributes on the lambda apply to the method. ProcessDeclAttributes(CurScope, Method, ParamInfo); - // CUDA lambdas get implicit attributes based on the scope in which they're - // declared. + // CUDA lambdas get implicit host and device attributes. if (getLangOpts().CUDA) CUDASetLambdaAttrs(Method); @@ -1052,8 +1052,8 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // "&identifier", "this", or "* this". [ Note: The form [&,this] is // redundant but accepted for compatibility with ISO C++14. --end note ] if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) - Diag(C->Loc, !getLangOpts().CPlusPlus2a - ? diag::ext_equals_this_lambda_capture_cxx2a + Diag(C->Loc, !getLangOpts().CPlusPlus20 + ? diag::ext_equals_this_lambda_capture_cxx20 : diag::warn_cxx17_compat_equals_this_lambda_capture); // C++11 [expr.prim.lambda]p12: @@ -1233,7 +1233,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, // Enter a new evaluation context to insulate the lambda from any // cleanups from the enclosing full-expression. PushExpressionEvaluationContext( - ExpressionEvaluationContext::PotentiallyEvaluated); + LSI->CallOperator->isConsteval() + ? ExpressionEvaluationContext::ConstantEvaluated + : ExpressionEvaluationContext::PotentiallyEvaluated); } void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, @@ -1626,7 +1628,8 @@ FieldDecl *Sema::BuildCaptureField(RecordDecl *RD, // If the variable being captured has an invalid type, mark the class as // invalid as well. if (!FieldType->isDependentType()) { - if (RequireCompleteType(Loc, FieldType, diag::err_field_incomplete)) { + if (RequireCompleteSizedType(Loc, FieldType, + diag::err_field_incomplete_or_sizeless)) { RD->setInvalidDecl(); Field->setInvalidDecl(); } else { @@ -1744,7 +1747,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // Capturing 'this' implicitly with a default of '[=]' is deprecated, // because it results in a reference capture. Don't warn prior to // C++2a; there's nothing that can be done about it before then. - if (getLangOpts().CPlusPlus2a && IsImplicit && + if (getLangOpts().CPlusPlus20 && IsImplicit && CaptureDefault == LCD_ByCopy) { Diag(From.getLocation(), diag::warn_deprecated_this_capture); Diag(CaptureDefaultLoc, diag::note_deprecated_this_capture) @@ -1776,8 +1779,13 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, BuildCaptureField(Class, From); Captures.push_back(Capture); CaptureInits.push_back(Init.get()); + + if (LangOpts.CUDA) + CUDACheckLambdaCapture(CallOperator, From); } + Class->setCaptures(Captures); + // C++11 [expr.prim.lambda]p6: // The closure type for a lambda-expression with no lambda-capture // has a public non-virtual non-explicit const conversion function @@ -1807,7 +1815,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, CaptureDefaultLoc, - Captures, ExplicitParams, ExplicitResultType, CaptureInits, EndLoc, ContainsUnexpandedParameterPack); diff --git a/clang/lib/Sema/SemaLookup.cpp b/clang/lib/Sema/SemaLookup.cpp index 0ed51de0cc13..5757eaf3fac0 100644 --- a/clang/lib/Sema/SemaLookup.cpp +++ b/clang/lib/Sema/SemaLookup.cpp @@ -215,6 +215,7 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, case Sema::LookupOrdinaryName: case Sema::LookupRedeclarationWithLinkage: case Sema::LookupLocalFriendName: + case Sema::LookupDestructorName: IDNS = Decl::IDNS_Ordinary; if (CPlusPlus) { IDNS |= Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Namespace; @@ -378,11 +379,14 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, // type), per a generous reading of C++ [dcl.typedef]p3 and p4. The typedef // might carry additional semantic information, such as an alignment override. // However, per C++ [dcl.typedef]p5, when looking up a tag name, prefer a tag - // declaration over a typedef. + // declaration over a typedef. Also prefer a tag over a typedef for + // destructor name lookup because in some contexts we only accept a + // class-name in a destructor declaration. if (DUnderlying->getCanonicalDecl() != EUnderlying->getCanonicalDecl()) { assert(isa<TypeDecl>(DUnderlying) && isa<TypeDecl>(EUnderlying)); bool HaveTag = isa<TagDecl>(EUnderlying); - bool WantTag = Kind == Sema::LookupTagName; + bool WantTag = + Kind == Sema::LookupTagName || Kind == Sema::LookupDestructorName; return HaveTag != WantTag; } @@ -1149,73 +1153,14 @@ static bool isNamespaceOrTranslationUnitScope(Scope *S) { return false; } -// Find the next outer declaration context from this scope. This -// routine actually returns the semantic outer context, which may -// differ from the lexical context (encoded directly in the Scope -// stack) when we are parsing a member of a class template. In this -// case, the second element of the pair will be true, to indicate that -// name lookup should continue searching in this semantic context when -// it leaves the current template parameter scope. -static std::pair<DeclContext *, bool> findOuterContext(Scope *S) { - DeclContext *DC = S->getEntity(); - DeclContext *Lexical = nullptr; - for (Scope *OuterS = S->getParent(); OuterS; - OuterS = OuterS->getParent()) { - if (OuterS->getEntity()) { - Lexical = OuterS->getEntity(); - break; - } - } - - // C++ [temp.local]p8: - // In the definition of a member of a class template that appears - // outside of the namespace containing the class template - // definition, the name of a template-parameter hides the name of - // a member of this namespace. - // - // Example: - // - // namespace N { - // class C { }; - // - // template<class T> class B { - // void f(T); - // }; - // } - // - // template<class C> void N::B<C>::f(C) { - // C b; // C is the template parameter, not N::C - // } - // - // In this example, the lexical context we return is the - // TranslationUnit, while the semantic context is the namespace N. - if (!Lexical || !DC || !S->getParent() || - !S->getParent()->isTemplateParamScope()) - return std::make_pair(Lexical, false); - - // Find the outermost template parameter scope. - // For the example, this is the scope for the template parameters of - // template<class C>. - Scope *OutermostTemplateScope = S->getParent(); - while (OutermostTemplateScope->getParent() && - OutermostTemplateScope->getParent()->isTemplateParamScope()) - OutermostTemplateScope = OutermostTemplateScope->getParent(); - - // Find the namespace context in which the original scope occurs. In - // the example, this is namespace N. - DeclContext *Semantic = DC; - while (!Semantic->isFileContext()) - Semantic = Semantic->getParent(); - - // Find the declaration context just outside of the template - // parameter scope. This is the context in which the template is - // being lexically declaration (a namespace context). In the - // example, this is the global scope. - if (Lexical->isFileContext() && !Lexical->Equals(Semantic) && - Lexical->Encloses(Semantic)) - return std::make_pair(Semantic, true); - - return std::make_pair(Lexical, false); +/// Find the outer declaration context from this scope. This indicates the +/// context that we should search up to (exclusive) before considering the +/// parent of the specified scope. +static DeclContext *findOuterContext(Scope *S) { + for (Scope *OuterS = S->getParent(); OuterS; OuterS = OuterS->getParent()) + if (DeclContext *DC = OuterS->getLookupEntity()) + return DC; + return nullptr; } namespace { @@ -1282,13 +1227,11 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { UnqualUsingDirectiveSet UDirs(*this); bool VisitedUsingDirectives = false; bool LeftStartingScope = false; - DeclContext *OutsideOfTemplateParamDC = nullptr; // When performing a scope lookup, we want to find local extern decls. FindLocalExternScope FindLocals(R); for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { - DeclContext *Ctx = S->getEntity(); bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. for (; I != IEnd && S->isDeclScope(*I); ++I) { @@ -1320,7 +1263,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) - if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx)) + if (CXXRecordDecl *Record = + dyn_cast_or_null<CXXRecordDecl>(S->getEntity())) R.setNamingClass(Record); return true; } @@ -1334,24 +1278,8 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return false; } - if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && - S->getParent() && !S->getParent()->isTemplateParamScope()) { - // We've just searched the last template parameter scope and - // found nothing, so look into the contexts between the - // lexical and semantic declaration contexts returned by - // findOuterContext(). This implements the name lookup behavior - // of C++ [temp.local]p8. - Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = nullptr; - } - - if (Ctx) { - DeclContext *OuterCtx; - bool SearchAfterTemplateScope; - std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); - if (SearchAfterTemplateScope) - OutsideOfTemplateParamDC = OuterCtx; - + if (DeclContext *Ctx = S->getLookupEntity()) { + DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -1476,25 +1404,9 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { return true; } - DeclContext *Ctx = S->getEntity(); - if (!Ctx && S->isTemplateParamScope() && OutsideOfTemplateParamDC && - S->getParent() && !S->getParent()->isTemplateParamScope()) { - // We've just searched the last template parameter scope and - // found nothing, so look into the contexts between the - // lexical and semantic declaration contexts returned by - // findOuterContext(). This implements the name lookup behavior - // of C++ [temp.local]p8. - Ctx = OutsideOfTemplateParamDC; - OutsideOfTemplateParamDC = nullptr; - } - + DeclContext *Ctx = S->getLookupEntity(); if (Ctx) { - DeclContext *OuterCtx; - bool SearchAfterTemplateScope; - std::tie(OuterCtx, SearchAfterTemplateScope) = findOuterContext(S); - if (SearchAfterTemplateScope) - OutsideOfTemplateParamDC = OuterCtx; - + DeclContext *OuterCtx = findOuterContext(S); for (; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { // We do not directly look into transparent contexts, since // those entities will be found in the nearest enclosing @@ -1575,7 +1487,9 @@ llvm::DenseSet<Module*> &Sema::getLookupModules() { unsigned N = CodeSynthesisContexts.size(); for (unsigned I = CodeSynthesisContextLookupModules.size(); I != N; ++I) { - Module *M = getDefiningModule(*this, CodeSynthesisContexts[I].Entity); + Module *M = CodeSynthesisContexts[I].Entity ? + getDefiningModule(*this, CodeSynthesisContexts[I].Entity) : + nullptr; if (M && !LookupModulesCache.insert(M).second) M = nullptr; CodeSynthesisContextLookupModules.push_back(M); @@ -1704,7 +1618,8 @@ bool Sema::hasVisibleMemberSpecialization( /// path (by instantiating a template, you allow it to see the declarations that /// your module can see, including those later on in your module). bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { - assert(D->isHidden() && "should not call this: not in slow case"); + assert(!D->isUnconditionallyVisible() && + "should not call this: not in slow case"); Module *DeclModule = SemaRef.getOwningModule(D); assert(DeclModule && "hidden decl has no owning module"); @@ -2295,6 +2210,7 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, case LookupMemberName: case LookupRedeclarationWithLinkage: case LookupLocalFriendName: + case LookupDestructorName: BaseCallback = &CXXRecordDecl::FindOrdinaryMember; break; @@ -2959,7 +2875,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) { // These are fundamental types. case Type::Vector: case Type::ExtVector: + case Type::ConstantMatrix: case Type::Complex: + case Type::ExtInt: break; // Non-deduced auto types only get here for error cases. @@ -3985,14 +3903,12 @@ private: } } - // FIXME: C++ [temp.local]p8 - DeclContext *Entity = nullptr; - if (S->getEntity()) { + DeclContext *Entity = S->getLookupEntity(); + if (Entity) { // Look into this scope's declaration context, along with any of its // parent lookup contexts (e.g., enclosing classes), up to the point // where we hit the context stored in the next outer scope. - Entity = S->getEntity(); - DeclContext *OuterCtx = findOuterContext(S).first; // FIXME + DeclContext *OuterCtx = findOuterContext(S); for (DeclContext *Ctx = Entity; Ctx && !Ctx->Equals(OuterCtx); Ctx = Ctx->getLookupParent()) { @@ -5158,9 +5074,9 @@ TypoExpr *Sema::CorrectTypoDelayed( IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; - ExprEvalContexts.back().NumTypos++; - return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC)); + return createDelayedTypo(std::move(Consumer), std::move(TDG), std::move(TRC), + TypoName.getLoc()); } void TypoCorrection::addCorrectionDecl(NamedDecl *CDecl) { @@ -5342,9 +5258,8 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, /// Get a "quoted.h" or <angled.h> include path to use in a diagnostic /// suggesting the addition of a #include of the specified file. -static std::string getIncludeStringForHeader(Preprocessor &PP, - const FileEntry *E, - llvm::StringRef IncludingFile) { +static std::string getHeaderNameForHeader(Preprocessor &PP, const FileEntry *E, + llvm::StringRef IncludingFile) { bool IsSystem = false; auto Path = PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics( E, IncludingFile, &IsSystem); @@ -5358,25 +5273,10 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, assert(!Modules.empty()); auto NotePrevious = [&] { - unsigned DiagID; - switch (MIK) { - case MissingImportKind::Declaration: - DiagID = diag::note_previous_declaration; - break; - case MissingImportKind::Definition: - DiagID = diag::note_previous_definition; - break; - case MissingImportKind::DefaultArgument: - DiagID = diag::note_default_argument_declared_here; - break; - case MissingImportKind::ExplicitSpecialization: - DiagID = diag::note_explicit_specialization_declared_here; - break; - case MissingImportKind::PartialSpecialization: - DiagID = diag::note_partial_specialization_declared_here; - break; - } - Diag(DeclLoc, DiagID); + // FIXME: Suppress the note backtrace even under + // -fdiagnostics-show-note-include-stack. We don't care how this + // declaration was previously reached. + Diag(DeclLoc, diag::note_unreachable_entity) << (int)MIK; }; // Weed out duplicates from module list. @@ -5389,26 +5289,24 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, UniqueModules.push_back(M); } - llvm::StringRef IncludingFile; - if (const FileEntry *FE = - SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc))) - IncludingFile = FE->tryGetRealPathName(); + // Try to find a suitable header-name to #include. + std::string HeaderName; + if (const FileEntry *Header = + PP.getHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) { + if (const FileEntry *FE = + SourceMgr.getFileEntryForID(SourceMgr.getFileID(UseLoc))) + HeaderName = getHeaderNameForHeader(PP, Header, FE->tryGetRealPathName()); + } - if (UniqueModules.empty()) { - // All candidates were global module fragments. Try to suggest a #include. - const FileEntry *E = - PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, Modules[0], DeclLoc); + // If we have a #include we should suggest, or if all definition locations + // were in global module fragments, don't suggest an import. + if (!HeaderName.empty() || UniqueModules.empty()) { // FIXME: Find a smart place to suggest inserting a #include, and add // a FixItHint there. - Diag(UseLoc, diag::err_module_unimported_use_global_module_fragment) - << (int)MIK << Decl << !!E - << (E ? getIncludeStringForHeader(PP, E, IncludingFile) : ""); - // Produce a "previous" note if it will point to a header rather than some - // random global module fragment. - // FIXME: Suppress the note backtrace even under - // -fdiagnostics-show-note-include-stack. - if (E) - NotePrevious(); + Diag(UseLoc, diag::err_module_unimported_use_header) + << (int)MIK << Decl << !HeaderName.empty() << HeaderName; + // Produce a note showing where the entity was declared. + NotePrevious(); if (Recover) createImplicitModuleImportForErrorRecovery(UseLoc, Modules[0]); return; @@ -5430,16 +5328,6 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, Diag(UseLoc, diag::err_module_unimported_use_multiple) << (int)MIK << Decl << ModuleList; - } else if (const FileEntry *E = PP.getModuleHeaderToIncludeForDiagnostics( - UseLoc, Modules[0], DeclLoc)) { - // The right way to make the declaration visible is to include a header; - // suggest doing so. - // - // FIXME: Find a smart place to suggest inserting a #include, and add - // a FixItHint there. - Diag(UseLoc, diag::err_module_unimported_use_header) - << (int)MIK << Decl << Modules[0]->getFullModuleName() - << getIncludeStringForHeader(PP, E, IncludingFile); } else { // FIXME: Add a FixItHint that imports the corresponding module. Diag(UseLoc, diag::err_module_unimported_use) @@ -5500,9 +5388,10 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, TypoDiagnosticGenerator TDG, - TypoRecoveryCallback TRC) { + TypoRecoveryCallback TRC, + SourceLocation TypoLoc) { assert(TCC && "createDelayedTypo requires a valid TypoCorrectionConsumer"); - auto TE = new (Context) TypoExpr(Context.DependentTy); + auto TE = new (Context) TypoExpr(Context.DependentTy, TypoLoc); auto &State = DelayedTypos[TE]; State.Consumer = std::move(TCC); State.DiagHandler = std::move(TDG); diff --git a/clang/lib/Sema/SemaObjCProperty.cpp b/clang/lib/Sema/SemaObjCProperty.cpp index f6717f4cbe5e..e301c62dd2c0 100644 --- a/clang/lib/Sema/SemaObjCProperty.cpp +++ b/clang/lib/Sema/SemaObjCProperty.cpp @@ -35,24 +35,23 @@ using namespace clang; /// /// Returns OCL_None if the attributes as stated do not imply an ownership. /// Never returns OCL_Autoreleasing. -static Qualifiers::ObjCLifetime getImpliedARCOwnership( - ObjCPropertyDecl::PropertyAttributeKind attrs, - QualType type) { +static Qualifiers::ObjCLifetime +getImpliedARCOwnership(ObjCPropertyAttribute::Kind attrs, QualType type) { // retain, strong, copy, weak, and unsafe_unretained are only legal // on properties of retainable pointer type. - if (attrs & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy)) { + if (attrs & + (ObjCPropertyAttribute::kind_retain | ObjCPropertyAttribute::kind_strong | + ObjCPropertyAttribute::kind_copy)) { return Qualifiers::OCL_Strong; - } else if (attrs & ObjCPropertyDecl::OBJC_PR_weak) { + } else if (attrs & ObjCPropertyAttribute::kind_weak) { return Qualifiers::OCL_Weak; - } else if (attrs & ObjCPropertyDecl::OBJC_PR_unsafe_unretained) { + } else if (attrs & ObjCPropertyAttribute::kind_unsafe_unretained) { return Qualifiers::OCL_ExplicitNone; } // assign can appear on other types, so we have to check the // property type. - if (attrs & ObjCPropertyDecl::OBJC_PR_assign && + if (attrs & ObjCPropertyAttribute::kind_assign && type->isObjCRetainableType()) { return Qualifiers::OCL_ExplicitNone; } @@ -66,8 +65,7 @@ static void checkPropertyDeclWithOwnership(Sema &S, ObjCPropertyDecl *property) { if (property->isInvalidDecl()) return; - ObjCPropertyDecl::PropertyAttributeKind propertyKind - = property->getPropertyAttributes(); + ObjCPropertyAttribute::Kind propertyKind = property->getPropertyAttributes(); Qualifiers::ObjCLifetime propertyLifetime = property->getType().getObjCLifetime(); @@ -80,14 +78,14 @@ static void checkPropertyDeclWithOwnership(Sema &S, // attribute. That's okay, but restore reasonable invariants by // setting the property attribute according to the lifetime // qualifier. - ObjCPropertyDecl::PropertyAttributeKind attr; + ObjCPropertyAttribute::Kind attr; if (propertyLifetime == Qualifiers::OCL_Strong) { - attr = ObjCPropertyDecl::OBJC_PR_strong; + attr = ObjCPropertyAttribute::kind_strong; } else if (propertyLifetime == Qualifiers::OCL_Weak) { - attr = ObjCPropertyDecl::OBJC_PR_weak; + attr = ObjCPropertyAttribute::kind_weak; } else { assert(propertyLifetime == Qualifiers::OCL_ExplicitNone); - attr = ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + attr = ObjCPropertyAttribute::kind_unsafe_unretained; } property->setPropertyAttributes(attr); return; @@ -130,18 +128,19 @@ CheckPropertyAgainstProtocol(Sema &S, ObjCPropertyDecl *Prop, static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) { // In GC mode, just look for the __weak qualifier. if (S.getLangOpts().getGC() != LangOptions::NonGC) { - if (T.isObjCGCWeak()) return ObjCDeclSpec::DQ_PR_weak; + if (T.isObjCGCWeak()) + return ObjCPropertyAttribute::kind_weak; - // In ARC/MRC, look for an explicit ownership qualifier. - // For some reason, this only applies to __weak. + // In ARC/MRC, look for an explicit ownership qualifier. + // For some reason, this only applies to __weak. } else if (auto ownership = T.getObjCLifetime()) { switch (ownership) { case Qualifiers::OCL_Weak: - return ObjCDeclSpec::DQ_PR_weak; + return ObjCPropertyAttribute::kind_weak; case Qualifiers::OCL_Strong: - return ObjCDeclSpec::DQ_PR_strong; + return ObjCPropertyAttribute::kind_strong; case Qualifiers::OCL_ExplicitNone: - return ObjCDeclSpec::DQ_PR_unsafe_unretained; + return ObjCPropertyAttribute::kind_unsafe_unretained; case Qualifiers::OCL_Autoreleasing: case Qualifiers::OCL_None: return 0; @@ -153,22 +152,20 @@ static unsigned deducePropertyOwnershipFromType(Sema &S, QualType T) { } static const unsigned OwnershipMask = - (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_weak | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + (ObjCPropertyAttribute::kind_assign | ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_copy | ObjCPropertyAttribute::kind_weak | + ObjCPropertyAttribute::kind_strong | + ObjCPropertyAttribute::kind_unsafe_unretained); static unsigned getOwnershipRule(unsigned attr) { unsigned result = attr & OwnershipMask; // From an ownership perspective, assign and unsafe_unretained are // identical; make sure one also implies the other. - if (result & (ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained)) { - result |= ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained; + if (result & (ObjCPropertyAttribute::kind_assign | + ObjCPropertyAttribute::kind_unsafe_unretained)) { + result |= ObjCPropertyAttribute::kind_assign | + ObjCPropertyAttribute::kind_unsafe_unretained; } return result; @@ -183,15 +180,16 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, tok::ObjCKeywordKind MethodImplKind, DeclContext *lexicalDC) { unsigned Attributes = ODS.getPropertyAttributes(); - FD.D.setObjCWeakProperty((Attributes & ObjCDeclSpec::DQ_PR_weak) != 0); + FD.D.setObjCWeakProperty((Attributes & ObjCPropertyAttribute::kind_weak) != + 0); TypeSourceInfo *TSI = GetTypeForDeclarator(FD.D, S); QualType T = TSI->getType(); if (!getOwnershipRule(Attributes)) { Attributes |= deducePropertyOwnershipFromType(*this, T); } - bool isReadWrite = ((Attributes & ObjCDeclSpec::DQ_PR_readwrite) || + bool isReadWrite = ((Attributes & ObjCPropertyAttribute::kind_readwrite) || // default is readwrite! - !(Attributes & ObjCDeclSpec::DQ_PR_readonly)); + !(Attributes & ObjCPropertyAttribute::kind_readonly)); // Proceed with constructing the ObjCPropertyDecls. ObjCContainerDecl *ClassDecl = cast<ObjCContainerDecl>(CurContext); @@ -277,39 +275,39 @@ Decl *Sema::ActOnProperty(Scope *S, SourceLocation AtLoc, return Res; } -static ObjCPropertyDecl::PropertyAttributeKind +static ObjCPropertyAttribute::Kind makePropertyAttributesAsWritten(unsigned Attributes) { unsigned attributesAsWritten = 0; - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readonly; - if (Attributes & ObjCDeclSpec::DQ_PR_readwrite) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_readwrite; - if (Attributes & ObjCDeclSpec::DQ_PR_getter) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_getter; - if (Attributes & ObjCDeclSpec::DQ_PR_setter) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_setter; - if (Attributes & ObjCDeclSpec::DQ_PR_assign) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_assign; - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_retain; - if (Attributes & ObjCDeclSpec::DQ_PR_strong) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_strong; - if (Attributes & ObjCDeclSpec::DQ_PR_weak) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_weak; - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_copy; - if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_unsafe_unretained; - if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic; - if (Attributes & ObjCDeclSpec::DQ_PR_atomic) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; - if (Attributes & ObjCDeclSpec::DQ_PR_class) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class; - if (Attributes & ObjCDeclSpec::DQ_PR_direct) - attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_direct; - - return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten; + if (Attributes & ObjCPropertyAttribute::kind_readonly) + attributesAsWritten |= ObjCPropertyAttribute::kind_readonly; + if (Attributes & ObjCPropertyAttribute::kind_readwrite) + attributesAsWritten |= ObjCPropertyAttribute::kind_readwrite; + if (Attributes & ObjCPropertyAttribute::kind_getter) + attributesAsWritten |= ObjCPropertyAttribute::kind_getter; + if (Attributes & ObjCPropertyAttribute::kind_setter) + attributesAsWritten |= ObjCPropertyAttribute::kind_setter; + if (Attributes & ObjCPropertyAttribute::kind_assign) + attributesAsWritten |= ObjCPropertyAttribute::kind_assign; + if (Attributes & ObjCPropertyAttribute::kind_retain) + attributesAsWritten |= ObjCPropertyAttribute::kind_retain; + if (Attributes & ObjCPropertyAttribute::kind_strong) + attributesAsWritten |= ObjCPropertyAttribute::kind_strong; + if (Attributes & ObjCPropertyAttribute::kind_weak) + attributesAsWritten |= ObjCPropertyAttribute::kind_weak; + if (Attributes & ObjCPropertyAttribute::kind_copy) + attributesAsWritten |= ObjCPropertyAttribute::kind_copy; + if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) + attributesAsWritten |= ObjCPropertyAttribute::kind_unsafe_unretained; + if (Attributes & ObjCPropertyAttribute::kind_nonatomic) + attributesAsWritten |= ObjCPropertyAttribute::kind_nonatomic; + if (Attributes & ObjCPropertyAttribute::kind_atomic) + attributesAsWritten |= ObjCPropertyAttribute::kind_atomic; + if (Attributes & ObjCPropertyAttribute::kind_class) + attributesAsWritten |= ObjCPropertyAttribute::kind_class; + if (Attributes & ObjCPropertyAttribute::kind_direct) + attributesAsWritten |= ObjCPropertyAttribute::kind_direct; + + return (ObjCPropertyAttribute::Kind)attributesAsWritten; } static bool LocPropertyAttribute( ASTContext &Context, const char *attrName, @@ -347,12 +345,10 @@ static void checkAtomicPropertyMismatch(Sema &S, ObjCPropertyDecl *NewProperty, bool PropagateAtomicity) { // If the atomicity of both matches, we're done. - bool OldIsAtomic = - (OldProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) - == 0; - bool NewIsAtomic = - (NewProperty->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_nonatomic) - == 0; + bool OldIsAtomic = (OldProperty->getPropertyAttributes() & + ObjCPropertyAttribute::kind_nonatomic) == 0; + bool NewIsAtomic = (NewProperty->getPropertyAttributes() & + ObjCPropertyAttribute::kind_nonatomic) == 0; if (OldIsAtomic == NewIsAtomic) return; // Determine whether the given property is readonly and implicitly @@ -360,14 +356,16 @@ static void checkAtomicPropertyMismatch(Sema &S, auto isImplicitlyReadonlyAtomic = [](ObjCPropertyDecl *Property) -> bool { // Is it readonly? auto Attrs = Property->getPropertyAttributes(); - if ((Attrs & ObjCPropertyDecl::OBJC_PR_readonly) == 0) return false; + if ((Attrs & ObjCPropertyAttribute::kind_readonly) == 0) + return false; // Is it nonatomic? - if (Attrs & ObjCPropertyDecl::OBJC_PR_nonatomic) return false; + if (Attrs & ObjCPropertyAttribute::kind_nonatomic) + return false; // Was 'atomic' specified directly? if (Property->getPropertyAttributesAsWritten() & - ObjCPropertyDecl::OBJC_PR_atomic) + ObjCPropertyAttribute::kind_atomic) return false; return true; @@ -375,16 +373,16 @@ static void checkAtomicPropertyMismatch(Sema &S, // If we're allowed to propagate atomicity, and the new property did // not specify atomicity at all, propagate. - const unsigned AtomicityMask = - (ObjCPropertyDecl::OBJC_PR_atomic | ObjCPropertyDecl::OBJC_PR_nonatomic); + const unsigned AtomicityMask = (ObjCPropertyAttribute::kind_atomic | + ObjCPropertyAttribute::kind_nonatomic); if (PropagateAtomicity && ((NewProperty->getPropertyAttributesAsWritten() & AtomicityMask) == 0)) { unsigned Attrs = NewProperty->getPropertyAttributes(); Attrs = Attrs & ~AtomicityMask; if (OldIsAtomic) - Attrs |= ObjCPropertyDecl::OBJC_PR_atomic; + Attrs |= ObjCPropertyAttribute::kind_atomic; else - Attrs |= ObjCPropertyDecl::OBJC_PR_nonatomic; + Attrs |= ObjCPropertyAttribute::kind_nonatomic; NewProperty->overwritePropertyAttributes(Attrs); return; @@ -438,8 +436,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, return nullptr; } - bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) || - (Attributes & ObjCDeclSpec::DQ_PR_class); + bool isClassProperty = + (AttributesAsWritten & ObjCPropertyAttribute::kind_class) || + (Attributes & ObjCPropertyAttribute::kind_class); // Find the property in the extended class's primary class or // extensions. @@ -464,11 +463,11 @@ Sema::HandlePropertyInClassExtension(Scope *S, // This is a common error where the user often intended the original // declaration to be readonly. unsigned diag = - (Attributes & ObjCDeclSpec::DQ_PR_readwrite) && - (PIDecl->getPropertyAttributesAsWritten() & - ObjCPropertyDecl::OBJC_PR_readwrite) - ? diag::err_use_continuation_class_redeclaration_readwrite - : diag::err_use_continuation_class; + (Attributes & ObjCPropertyAttribute::kind_readwrite) && + (PIDecl->getPropertyAttributesAsWritten() & + ObjCPropertyAttribute::kind_readwrite) + ? diag::err_use_continuation_class_redeclaration_readwrite + : diag::err_use_continuation_class; Diag(AtLoc, diag) << CCPrimary->getDeclName(); Diag(PIDecl->getLocation(), diag::note_property_declare); @@ -478,15 +477,15 @@ Sema::HandlePropertyInClassExtension(Scope *S, // Check for consistency of getters. if (PIDecl->getGetterName() != GetterSel) { // If the getter was written explicitly, complain. - if (AttributesAsWritten & ObjCDeclSpec::DQ_PR_getter) { - Diag(AtLoc, diag::warn_property_redecl_getter_mismatch) - << PIDecl->getGetterName() << GetterSel; - Diag(PIDecl->getLocation(), diag::note_property_declare); - } + if (AttributesAsWritten & ObjCPropertyAttribute::kind_getter) { + Diag(AtLoc, diag::warn_property_redecl_getter_mismatch) + << PIDecl->getGetterName() << GetterSel; + Diag(PIDecl->getLocation(), diag::note_property_declare); + } // Always adopt the getter from the original declaration. GetterSel = PIDecl->getGetterName(); - Attributes |= ObjCDeclSpec::DQ_PR_getter; + Attributes |= ObjCPropertyAttribute::kind_getter; } // Check consistency of ownership. @@ -505,9 +504,9 @@ Sema::HandlePropertyInClassExtension(Scope *S, } // If the redeclaration is 'weak' but the original property is not, - if ((Attributes & ObjCPropertyDecl::OBJC_PR_weak) && - !(PIDecl->getPropertyAttributesAsWritten() - & ObjCPropertyDecl::OBJC_PR_weak) && + if ((Attributes & ObjCPropertyAttribute::kind_weak) && + !(PIDecl->getPropertyAttributesAsWritten() & + ObjCPropertyAttribute::kind_weak) && PIDecl->getType()->getAs<ObjCObjectPointerType>() && PIDecl->getType().getObjCLifetime() == Qualifiers::OCL_None) { Diag(AtLoc, diag::warn_property_implicitly_mismatched); @@ -584,8 +583,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // Property defaults to 'assign' if it is readwrite, unless this is ARC // and the type is retainable. bool isAssign; - if (Attributes & (ObjCDeclSpec::DQ_PR_assign | - ObjCDeclSpec::DQ_PR_unsafe_unretained)) { + if (Attributes & (ObjCPropertyAttribute::kind_assign | + ObjCPropertyAttribute::kind_unsafe_unretained)) { isAssign = true; } else if (getOwnershipRule(Attributes) || !isReadWrite) { isAssign = false; @@ -596,8 +595,8 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, // Issue a warning if property is 'assign' as default and its // object, which is gc'able conforms to NSCopying protocol - if (getLangOpts().getGC() != LangOptions::NonGC && - isAssign && !(Attributes & ObjCDeclSpec::DQ_PR_assign)) { + if (getLangOpts().getGC() != LangOptions::NonGC && isAssign && + !(Attributes & ObjCPropertyAttribute::kind_assign)) { if (const ObjCObjectPointerType *ObjPtrTy = T->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *IDecl = ObjPtrTy->getObjectType()->getInterface(); @@ -625,8 +624,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PropertyId, AtLoc, LParenLoc, T, TInfo); - bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) || - (Attributes & ObjCDeclSpec::DQ_PR_class); + bool isClassProperty = + (AttributesAsWritten & ObjCPropertyAttribute::kind_class) || + (Attributes & ObjCPropertyAttribute::kind_class); // Class property and instance property can have the same name. if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl( DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) { @@ -654,68 +654,68 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PDecl->setPropertyAttributesAsWritten( makePropertyAttributesAsWritten(AttributesAsWritten)); - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readonly); + if (Attributes & ObjCPropertyAttribute::kind_readonly) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readonly); - if (Attributes & ObjCDeclSpec::DQ_PR_getter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_getter); + if (Attributes & ObjCPropertyAttribute::kind_getter) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_getter); - if (Attributes & ObjCDeclSpec::DQ_PR_setter) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_setter); + if (Attributes & ObjCPropertyAttribute::kind_setter) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_setter); if (isReadWrite) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_readwrite); + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_readwrite); - if (Attributes & ObjCDeclSpec::DQ_PR_retain) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_retain); + if (Attributes & ObjCPropertyAttribute::kind_retain) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_retain); - if (Attributes & ObjCDeclSpec::DQ_PR_strong) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + if (Attributes & ObjCPropertyAttribute::kind_strong) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong); - if (Attributes & ObjCDeclSpec::DQ_PR_weak) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak); + if (Attributes & ObjCPropertyAttribute::kind_weak) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_weak); - if (Attributes & ObjCDeclSpec::DQ_PR_copy) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_copy); + if (Attributes & ObjCPropertyAttribute::kind_copy) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_copy); - if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained); if (isAssign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign); // In the semantic attributes, one of nonatomic or atomic is always set. - if (Attributes & ObjCDeclSpec::DQ_PR_nonatomic) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nonatomic); + if (Attributes & ObjCPropertyAttribute::kind_nonatomic) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nonatomic); else - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_atomic); + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_atomic); // 'unsafe_unretained' is alias for 'assign'. - if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_assign); + if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_assign); if (isAssign) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_unsafe_unretained); + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_unsafe_unretained); if (MethodImplKind == tok::objc_required) PDecl->setPropertyImplementation(ObjCPropertyDecl::Required); else if (MethodImplKind == tok::objc_optional) PDecl->setPropertyImplementation(ObjCPropertyDecl::Optional); - if (Attributes & ObjCDeclSpec::DQ_PR_nullability) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_nullability); + if (Attributes & ObjCPropertyAttribute::kind_nullability) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_nullability); - if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); + if (Attributes & ObjCPropertyAttribute::kind_null_resettable) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_null_resettable); - if (Attributes & ObjCDeclSpec::DQ_PR_class) - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class); + if (Attributes & ObjCPropertyAttribute::kind_class) + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_class); - if ((Attributes & ObjCDeclSpec::DQ_PR_direct) || + if ((Attributes & ObjCPropertyAttribute::kind_direct) || CDecl->hasAttr<ObjCDirectMembersAttr>()) { if (isa<ObjCProtocolDecl>(CDecl)) { Diag(PDecl->getLocation(), diag::err_objc_direct_on_protocol) << true; } else if (getLangOpts().ObjCRuntime.allowsDirectDispatch()) { - PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_direct); + PDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_direct); } else { Diag(PDecl->getLocation(), diag::warn_objc_direct_property_ignored) << PDecl->getDeclName(); @@ -781,10 +781,9 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, case Qualifiers::OCL_ExplicitNone: S.Diag(ivar->getLocation(), diag::err_arc_assign_property_ownership) - << property->getDeclName() - << ivar->getDeclName() - << ((property->getPropertyAttributesAsWritten() - & ObjCPropertyDecl::OBJC_PR_assign) != 0); + << property->getDeclName() << ivar->getDeclName() + << ((property->getPropertyAttributesAsWritten() & + ObjCPropertyAttribute::kind_assign) != 0); break; case Qualifiers::OCL_Autoreleasing: @@ -815,21 +814,20 @@ static void setImpliedPropertyAttributeForReadOnlyProperty( if (!ivar) { // if no backing ivar, make property 'strong'. - property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong); return; } // property assumes owenership of backing ivar. QualType ivarType = ivar->getType(); Qualifiers::ObjCLifetime ivarLifetime = ivarType.getObjCLifetime(); if (ivarLifetime == Qualifiers::OCL_Strong) - property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + property->setPropertyAttributes(ObjCPropertyAttribute::kind_strong); else if (ivarLifetime == Qualifiers::OCL_Weak) - property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak); + property->setPropertyAttributes(ObjCPropertyAttribute::kind_weak); } -static bool -isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2, - ObjCPropertyDecl::PropertyAttributeKind Kind) { +static bool isIncompatiblePropertyAttribute(unsigned Attr1, unsigned Attr2, + ObjCPropertyAttribute::Kind Kind) { return (Attr1 & Kind) != (Attr2 & Kind); } @@ -912,30 +910,31 @@ SelectPropertyForSynthesisFromProtocols(Sema &S, SourceLocation AtLoc, }; // The ownership might be incompatible unless the property has no explicit // ownership. - bool HasOwnership = (Attr & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong | - ObjCPropertyDecl::OBJC_PR_copy | - ObjCPropertyDecl::OBJC_PR_assign | - ObjCPropertyDecl::OBJC_PR_unsafe_unretained | - ObjCPropertyDecl::OBJC_PR_weak)) != 0; + bool HasOwnership = + (Attr & (ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong | + ObjCPropertyAttribute::kind_copy | + ObjCPropertyAttribute::kind_assign | + ObjCPropertyAttribute::kind_unsafe_unretained | + ObjCPropertyAttribute::kind_weak)) != 0; if (HasOwnership && isIncompatiblePropertyAttribute(OriginalAttributes, Attr, - ObjCPropertyDecl::OBJC_PR_copy)) { - Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_copy, "copy"); + ObjCPropertyAttribute::kind_copy)) { + Diag(OriginalAttributes & ObjCPropertyAttribute::kind_copy, "copy"); continue; } if (HasOwnership && areIncompatiblePropertyAttributes( OriginalAttributes, Attr, - ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong)) { - Diag(OriginalAttributes & (ObjCPropertyDecl::OBJC_PR_retain | - ObjCPropertyDecl::OBJC_PR_strong), + ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong)) { + Diag(OriginalAttributes & (ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong), "retain (or strong)"); continue; } if (isIncompatiblePropertyAttribute(OriginalAttributes, Attr, - ObjCPropertyDecl::OBJC_PR_atomic)) { - Diag(OriginalAttributes & ObjCPropertyDecl::OBJC_PR_atomic, "atomic"); + ObjCPropertyAttribute::kind_atomic)) { + Diag(OriginalAttributes & ObjCPropertyAttribute::kind_atomic, "atomic"); continue; } } @@ -1126,8 +1125,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return nullptr; } unsigned PIkind = property->getPropertyAttributesAsWritten(); - if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic | - ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) { + if ((PIkind & (ObjCPropertyAttribute::kind_atomic | + ObjCPropertyAttribute::kind_nonatomic)) == 0) { if (AtLoc.isValid()) Diag(AtLoc, diag::warn_implicit_atomic_property); else @@ -1143,10 +1142,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, return nullptr; } } - if (Synthesize&& - (PIkind & ObjCPropertyDecl::OBJC_PR_readonly) && - property->hasAttr<IBOutletAttr>() && - !AtLoc.isValid()) { + if (Synthesize && (PIkind & ObjCPropertyAttribute::kind_readonly) && + property->hasAttr<IBOutletAttr>() && !AtLoc.isValid()) { bool ReadWriteProperty = false; // Search into the class extensions and see if 'readonly property is // redeclared 'readwrite', then no warning is to be issued. @@ -1155,7 +1152,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!R.empty()) if (ObjCPropertyDecl *ExtProp = dyn_cast<ObjCPropertyDecl>(R[0])) { PIkind = ExtProp->getPropertyAttributesAsWritten(); - if (PIkind & ObjCPropertyDecl::OBJC_PR_readwrite) { + if (PIkind & ObjCPropertyAttribute::kind_readwrite) { ReadWriteProperty = true; break; } @@ -1232,16 +1229,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (getLangOpts().ObjCAutoRefCount && (property->getPropertyAttributesAsWritten() & - ObjCPropertyDecl::OBJC_PR_readonly) && + ObjCPropertyAttribute::kind_readonly) && PropertyIvarType->isObjCRetainableType()) { setImpliedPropertyAttributeForReadOnlyProperty(property, Ivar); } - ObjCPropertyDecl::PropertyAttributeKind kind - = property->getPropertyAttributes(); + ObjCPropertyAttribute::Kind kind = property->getPropertyAttributes(); bool isARCWeak = false; - if (kind & ObjCPropertyDecl::OBJC_PR_weak) { + if (kind & ObjCPropertyAttribute::kind_weak) { // Add GC __weak to the ivar type if the property is weak. if (getLangOpts().getGC() != LangOptions::NonGC) { assert(!getLangOpts().ObjCAutoRefCount); @@ -1312,7 +1308,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // It's an error if we have to do this and the user didn't // explicitly write an ownership attribute on the property. if (!hasWrittenStorageAttribute(property, QueryKind) && - !(kind & ObjCPropertyDecl::OBJC_PR_strong)) { + !(kind & ObjCPropertyAttribute::kind_strong)) { Diag(PropertyDiagLoc, diag::err_arc_objc_property_default_assign_on_object); Diag(property->getLocation(), diag::note_property_declare); @@ -1456,7 +1452,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, PropertyLoc); PIDecl->setGetterMethodDecl(OMD); } - + if (getLangOpts().CPlusPlus && Synthesize && !CompleteTypeErr && Ivar->getType()->isRecordType()) { // For Objective-C++, need to synthesize the AST for the IVAR object to be @@ -1551,7 +1547,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, ExprResult Res = BuildBinOp(S, PropertyDiagLoc, BO_Assign, lhs, rhs); if (property->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_atomic) { + ObjCPropertyAttribute::kind_atomic) { Expr *callExpr = Res.getAs<Expr>(); if (const CXXOperatorCallExpr *CXXCE = dyn_cast_or_null<CXXOperatorCallExpr>(callExpr)) @@ -1627,6 +1623,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, CatImplClass->addPropertyImplementation(PIDecl); } + if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic && + PIDecl->getPropertyDecl() && + PIDecl->getPropertyDecl()->isDirectProperty()) { + Diag(PropertyLoc, diag::err_objc_direct_dynamic_property); + Diag(PIDecl->getPropertyDecl()->getLocation(), + diag::note_previous_declaration); + return nullptr; + } + return PIDecl; } @@ -1642,10 +1647,8 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, ObjCPropertyDecl *SuperProperty, const IdentifierInfo *inheritedName, bool OverridingProtocolProperty) { - ObjCPropertyDecl::PropertyAttributeKind CAttr = - Property->getPropertyAttributes(); - ObjCPropertyDecl::PropertyAttributeKind SAttr = - SuperProperty->getPropertyAttributes(); + ObjCPropertyAttribute::Kind CAttr = Property->getPropertyAttributes(); + ObjCPropertyAttribute::Kind SAttr = SuperProperty->getPropertyAttributes(); // We allow readonly properties without an explicit ownership // (assign/unsafe_unretained/weak/retain/strong/copy) in super class @@ -1654,21 +1657,19 @@ Sema::DiagnosePropertyMismatch(ObjCPropertyDecl *Property, !getOwnershipRule(SAttr) && getOwnershipRule(CAttr)) ; else { - if ((CAttr & ObjCPropertyDecl::OBJC_PR_readonly) - && (SAttr & ObjCPropertyDecl::OBJC_PR_readwrite)) + if ((CAttr & ObjCPropertyAttribute::kind_readonly) && + (SAttr & ObjCPropertyAttribute::kind_readwrite)) Diag(Property->getLocation(), diag::warn_readonly_property) << Property->getDeclName() << inheritedName; - if ((CAttr & ObjCPropertyDecl::OBJC_PR_copy) - != (SAttr & ObjCPropertyDecl::OBJC_PR_copy)) + if ((CAttr & ObjCPropertyAttribute::kind_copy) != + (SAttr & ObjCPropertyAttribute::kind_copy)) Diag(Property->getLocation(), diag::warn_property_attribute) << Property->getDeclName() << "copy" << inheritedName; - else if (!(SAttr & ObjCPropertyDecl::OBJC_PR_readonly)){ - unsigned CAttrRetain = - (CAttr & - (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); - unsigned SAttrRetain = - (SAttr & - (ObjCPropertyDecl::OBJC_PR_retain | ObjCPropertyDecl::OBJC_PR_strong)); + else if (!(SAttr & ObjCPropertyAttribute::kind_readonly)) { + unsigned CAttrRetain = (CAttr & (ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong)); + unsigned SAttrRetain = (SAttr & (ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong)); bool CStrong = (CAttrRetain != 0); bool SStrong = (SAttrRetain != 0); if (CStrong != SStrong) @@ -1876,7 +1877,7 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl, ObjCPropertyDecl *Prop) { bool SuperClassImplementsGetter = false; bool SuperClassImplementsSetter = false; - if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) + if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly) SuperClassImplementsSetter = true; while (IDecl->getSuperClass()) { @@ -1919,7 +1920,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, continue; ObjCMethodDecl *ImpMethod = IMPDecl->getInstanceMethod(Prop->getGetterName()); if (ImpMethod && !ImpMethod->getBody()) { - if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) + if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_readonly) continue; ImpMethod = IMPDecl->getInstanceMethod(Prop->getSetterName()); if (ImpMethod && !ImpMethod->getBody()) @@ -1956,16 +1957,16 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl *IMPDecl, } // If property to be implemented in the super class, ignore. if (PropInSuperClass) { - if ((Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readwrite) && + if ((Prop->getPropertyAttributes() & + ObjCPropertyAttribute::kind_readwrite) && (PropInSuperClass->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_readonly) && + ObjCPropertyAttribute::kind_readonly) && !IMPDecl->getInstanceMethod(Prop->getSetterName()) && !IDecl->HasUserDeclaredSetterMethod(Prop)) { Diag(Prop->getLocation(), diag::warn_no_autosynthesis_property) << Prop->getIdentifier(); Diag(PropInSuperClass->getLocation(), diag::note_property_declare); - } - else { + } else { Diag(Prop->getLocation(), diag::warn_autosynthesis_property_in_superclass) << Prop->getIdentifier(); Diag(PropInSuperClass->getLocation(), diag::note_property_declare); @@ -2152,12 +2153,11 @@ void Sema::diagnoseNullResettableSynthesizedSetters(const ObjCImplDecl *impDecl) const auto *property = propertyImpl->getPropertyDecl(); // Warn about null_resettable properties with synthesized setters, // because the setter won't properly handle nil. - if (propertyImpl->getPropertyImplementation() - == ObjCPropertyImplDecl::Synthesize && + if (propertyImpl->getPropertyImplementation() == + ObjCPropertyImplDecl::Synthesize && (property->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_null_resettable) && - property->getGetterMethodDecl() && - property->getSetterMethodDecl()) { + ObjCPropertyAttribute::kind_null_resettable) && + property->getGetterMethodDecl() && property->getSetterMethodDecl()) { auto *getterImpl = propertyImpl->getGetterMethodDecl(); auto *setterImpl = propertyImpl->getSetterMethodDecl(); if ((!getterImpl || getterImpl->isSynthesizedAccessorStub()) && @@ -2195,8 +2195,8 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, unsigned Attributes = Property->getPropertyAttributes(); unsigned AttributesAsWritten = Property->getPropertyAttributesAsWritten(); - if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) && - !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) { + if (!(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic) && + !(AttributesAsWritten & ObjCPropertyAttribute::kind_nonatomic)) { GetterMethod = Property->isClassProperty() ? IMPDecl->getClassMethod(Property->getGetterName()) : IMPDecl->getInstanceMethod(Property->getGetterName()); @@ -2222,8 +2222,8 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, } // We only care about readwrite atomic property. - if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || - !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) + if ((Attributes & ObjCPropertyAttribute::kind_nonatomic) || + !(Attributes & ObjCPropertyAttribute::kind_readwrite)) continue; if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl( Property->getIdentifier(), Property->getQueryKind())) { @@ -2244,7 +2244,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, << (SetterMethod != nullptr); // fixit stuff. if (Property->getLParenLoc().isValid() && - !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic)) { + !(AttributesAsWritten & ObjCPropertyAttribute::kind_atomic)) { // @property () ... case. SourceLocation AfterLParen = getLocForEndOfToken(Property->getLParenLoc()); @@ -2260,8 +2260,7 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, Diag(Property->getLocation(), diag::note_atomic_property_fixup_suggest) << FixItHint::CreateInsertion(startLoc, "(nonatomic) "); - } - else + } else Diag(MethodLoc, diag::note_atomic_property_fixup_suggest); Diag(Property->getLocation(), diag::note_property_declare); } @@ -2421,6 +2420,40 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { DiagnosePropertyAccessorMismatch(property, GetterMethod, property->getLocation()); + // synthesizing accessors must not result in a direct method that is not + // monomorphic + if (!GetterMethod) { + if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) { + auto *ExistingGetter = CatDecl->getClassInterface()->lookupMethod( + property->getGetterName(), !IsClassProperty, true, false, CatDecl); + if (ExistingGetter) { + if (ExistingGetter->isDirectMethod() || property->isDirectProperty()) { + Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl) + << property->isDirectProperty() << 1 /* property */ + << ExistingGetter->isDirectMethod() + << ExistingGetter->getDeclName(); + Diag(ExistingGetter->getLocation(), diag::note_previous_declaration); + } + } + } + } + + if (!property->isReadOnly() && !SetterMethod) { + if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) { + auto *ExistingSetter = CatDecl->getClassInterface()->lookupMethod( + property->getSetterName(), !IsClassProperty, true, false, CatDecl); + if (ExistingSetter) { + if (ExistingSetter->isDirectMethod() || property->isDirectProperty()) { + Diag(property->getLocation(), diag::err_objc_direct_duplicate_decl) + << property->isDirectProperty() << 1 /* property */ + << ExistingSetter->isDirectMethod() + << ExistingSetter->getDeclName(); + Diag(ExistingSetter->getLocation(), diag::note_previous_declaration); + } + } + } + } + if (!property->isReadOnly() && SetterMethod) { if (Context.getCanonicalType(SetterMethod->getReturnType()) != Context.VoidTy) @@ -2455,7 +2488,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // If the property is null_resettable, the getter returns nonnull. if (property->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_null_resettable) { + ObjCPropertyAttribute::kind_null_resettable) { QualType modifiedTy = resultTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)) { if (*nullability == NullabilityKind::Unspecified) @@ -2534,7 +2567,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // If the property is null_resettable, the setter accepts a // nullable value. if (property->getPropertyAttributes() & - ObjCPropertyDecl::OBJC_PR_null_resettable) { + ObjCPropertyAttribute::kind_null_resettable) { QualType modifiedTy = paramTy; if (auto nullability = AttributedType::stripOuterNullability(modifiedTy)){ if (*nullability == NullabilityKind::Unspecified) @@ -2622,8 +2655,8 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if (!PDecl || PDecl->isInvalidDecl()) return; - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & ObjCDeclSpec::DQ_PR_readwrite)) + if ((Attributes & ObjCPropertyAttribute::kind_readonly) && + (Attributes & ObjCPropertyAttribute::kind_readwrite)) Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "readonly" << "readwrite"; @@ -2631,104 +2664,109 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, QualType PropertyTy = PropertyDecl->getType(); // Check for copy or retain on non-object types. - if ((Attributes & (ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong)) && + if ((Attributes & + (ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy | + ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong)) && !PropertyTy->isObjCRetainableType() && !PropertyDecl->hasAttr<ObjCNSObjectAttr>()) { Diag(Loc, diag::err_objc_property_requires_object) - << (Attributes & ObjCDeclSpec::DQ_PR_weak ? "weak" : - Attributes & ObjCDeclSpec::DQ_PR_copy ? "copy" : "retain (or strong)"); - Attributes &= ~(ObjCDeclSpec::DQ_PR_weak | ObjCDeclSpec::DQ_PR_copy | - ObjCDeclSpec::DQ_PR_retain | ObjCDeclSpec::DQ_PR_strong); + << (Attributes & ObjCPropertyAttribute::kind_weak + ? "weak" + : Attributes & ObjCPropertyAttribute::kind_copy + ? "copy" + : "retain (or strong)"); + Attributes &= + ~(ObjCPropertyAttribute::kind_weak | ObjCPropertyAttribute::kind_copy | + ObjCPropertyAttribute::kind_retain | + ObjCPropertyAttribute::kind_strong); PropertyDecl->setInvalidDecl(); } // Check for assign on object types. - if ((Attributes & ObjCDeclSpec::DQ_PR_assign) && - !(Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) && + if ((Attributes & ObjCPropertyAttribute::kind_assign) && + !(Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) && PropertyTy->isObjCRetainableType() && !PropertyTy->isObjCARCImplicitlyUnretainedType()) { Diag(Loc, diag::warn_objc_property_assign_on_object); } // Check for more than one of { assign, copy, retain }. - if (Attributes & ObjCDeclSpec::DQ_PR_assign) { - if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + if (Attributes & ObjCPropertyAttribute::kind_assign) { + if (Attributes & ObjCPropertyAttribute::kind_copy) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "copy"; - Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + Attributes &= ~ObjCPropertyAttribute::kind_copy; } - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + if (Attributes & ObjCPropertyAttribute::kind_retain) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + Attributes &= ~ObjCPropertyAttribute::kind_retain; } - if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + if (Attributes & ObjCPropertyAttribute::kind_strong) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "strong"; - Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + Attributes &= ~ObjCPropertyAttribute::kind_strong; } - if (getLangOpts().ObjCAutoRefCount && - (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + if (getLangOpts().ObjCAutoRefCount && + (Attributes & ObjCPropertyAttribute::kind_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "assign" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + Attributes &= ~ObjCPropertyAttribute::kind_weak; } if (PropertyDecl->hasAttr<IBOutletCollectionAttr>()) Diag(Loc, diag::warn_iboutletcollection_property_assign); - } else if (Attributes & ObjCDeclSpec::DQ_PR_unsafe_unretained) { - if (Attributes & ObjCDeclSpec::DQ_PR_copy) { + } else if (Attributes & ObjCPropertyAttribute::kind_unsafe_unretained) { + if (Attributes & ObjCPropertyAttribute::kind_copy) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "unsafe_unretained" << "copy"; - Attributes &= ~ObjCDeclSpec::DQ_PR_copy; + Attributes &= ~ObjCPropertyAttribute::kind_copy; } - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + if (Attributes & ObjCPropertyAttribute::kind_retain) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "unsafe_unretained" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + Attributes &= ~ObjCPropertyAttribute::kind_retain; } - if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + if (Attributes & ObjCPropertyAttribute::kind_strong) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "unsafe_unretained" << "strong"; - Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + Attributes &= ~ObjCPropertyAttribute::kind_strong; } - if (getLangOpts().ObjCAutoRefCount && - (Attributes & ObjCDeclSpec::DQ_PR_weak)) { + if (getLangOpts().ObjCAutoRefCount && + (Attributes & ObjCPropertyAttribute::kind_weak)) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "unsafe_unretained" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + Attributes &= ~ObjCPropertyAttribute::kind_weak; } - } else if (Attributes & ObjCDeclSpec::DQ_PR_copy) { - if (Attributes & ObjCDeclSpec::DQ_PR_retain) { + } else if (Attributes & ObjCPropertyAttribute::kind_copy) { + if (Attributes & ObjCPropertyAttribute::kind_retain) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "copy" << "retain"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; + Attributes &= ~ObjCPropertyAttribute::kind_retain; } - if (Attributes & ObjCDeclSpec::DQ_PR_strong) { + if (Attributes & ObjCPropertyAttribute::kind_strong) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "copy" << "strong"; - Attributes &= ~ObjCDeclSpec::DQ_PR_strong; + Attributes &= ~ObjCPropertyAttribute::kind_strong; } - if (Attributes & ObjCDeclSpec::DQ_PR_weak) { + if (Attributes & ObjCPropertyAttribute::kind_weak) { Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "copy" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + Attributes &= ~ObjCPropertyAttribute::kind_weak; } - } - else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) && - (Attributes & ObjCDeclSpec::DQ_PR_weak)) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "retain" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_retain; - } - else if ((Attributes & ObjCDeclSpec::DQ_PR_strong) && - (Attributes & ObjCDeclSpec::DQ_PR_weak)) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "strong" << "weak"; - Attributes &= ~ObjCDeclSpec::DQ_PR_weak; + } else if ((Attributes & ObjCPropertyAttribute::kind_retain) && + (Attributes & ObjCPropertyAttribute::kind_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "retain" + << "weak"; + Attributes &= ~ObjCPropertyAttribute::kind_retain; + } else if ((Attributes & ObjCPropertyAttribute::kind_strong) && + (Attributes & ObjCPropertyAttribute::kind_weak)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "strong" + << "weak"; + Attributes &= ~ObjCPropertyAttribute::kind_weak; } - if (Attributes & ObjCDeclSpec::DQ_PR_weak) { + if (Attributes & ObjCPropertyAttribute::kind_weak) { // 'weak' and 'nonnull' are mutually exclusive. if (auto nullability = PropertyTy->getNullability(Context)) { if (*nullability == NullabilityKind::NonNull) @@ -2737,41 +2775,40 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, } } - if ((Attributes & ObjCDeclSpec::DQ_PR_atomic) && - (Attributes & ObjCDeclSpec::DQ_PR_nonatomic)) { - Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) - << "atomic" << "nonatomic"; - Attributes &= ~ObjCDeclSpec::DQ_PR_atomic; + if ((Attributes & ObjCPropertyAttribute::kind_atomic) && + (Attributes & ObjCPropertyAttribute::kind_nonatomic)) { + Diag(Loc, diag::err_objc_property_attr_mutually_exclusive) << "atomic" + << "nonatomic"; + Attributes &= ~ObjCPropertyAttribute::kind_atomic; } // Warn if user supplied no assignment attribute, property is // readwrite, and this is an object type. if (!getOwnershipRule(Attributes) && PropertyTy->isObjCRetainableType()) { - if (Attributes & ObjCDeclSpec::DQ_PR_readonly) { + if (Attributes & ObjCPropertyAttribute::kind_readonly) { // do nothing } else if (getLangOpts().ObjCAutoRefCount) { // With arc, @property definitions should default to strong when // not specified. - PropertyDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); + PropertyDecl->setPropertyAttributes(ObjCPropertyAttribute::kind_strong); } else if (PropertyTy->isObjCObjectPointerType()) { - bool isAnyClassTy = - (PropertyTy->isObjCClassType() || - PropertyTy->isObjCQualifiedClassType()); - // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to - // issue any warning. - if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC) - ; - else if (propertyInPrimaryClass) { - // Don't issue warning on property with no life time in class - // extension as it is inherited from property in primary class. - // Skip this warning in gc-only mode. - if (getLangOpts().getGC() != LangOptions::GCOnly) - Diag(Loc, diag::warn_objc_property_no_assignment_attribute); - - // If non-gc code warn that this is likely inappropriate. - if (getLangOpts().getGC() == LangOptions::NonGC) - Diag(Loc, diag::warn_objc_property_default_assign_on_object); - } + bool isAnyClassTy = (PropertyTy->isObjCClassType() || + PropertyTy->isObjCQualifiedClassType()); + // In non-gc, non-arc mode, 'Class' is treated as a 'void *' no need to + // issue any warning. + if (isAnyClassTy && getLangOpts().getGC() == LangOptions::NonGC) + ; + else if (propertyInPrimaryClass) { + // Don't issue warning on property with no life time in class + // extension as it is inherited from property in primary class. + // Skip this warning in gc-only mode. + if (getLangOpts().getGC() != LangOptions::GCOnly) + Diag(Loc, diag::warn_objc_property_no_assignment_attribute); + + // If non-gc code warn that this is likely inappropriate. + if (getLangOpts().getGC() == LangOptions::NonGC) + Diag(Loc, diag::warn_objc_property_default_assign_on_object); + } } // FIXME: Implement warning dependent on NSCopying being @@ -2780,18 +2817,18 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, // (please trim this list while you are at it). } - if (!(Attributes & ObjCDeclSpec::DQ_PR_copy) - &&!(Attributes & ObjCDeclSpec::DQ_PR_readonly) - && getLangOpts().getGC() == LangOptions::GCOnly - && PropertyTy->isBlockPointerType()) + if (!(Attributes & ObjCPropertyAttribute::kind_copy) && + !(Attributes & ObjCPropertyAttribute::kind_readonly) && + getLangOpts().getGC() == LangOptions::GCOnly && + PropertyTy->isBlockPointerType()) Diag(Loc, diag::warn_objc_property_copy_missing_on_block); - else if ((Attributes & ObjCDeclSpec::DQ_PR_retain) && - !(Attributes & ObjCDeclSpec::DQ_PR_readonly) && - !(Attributes & ObjCDeclSpec::DQ_PR_strong) && + else if ((Attributes & ObjCPropertyAttribute::kind_retain) && + !(Attributes & ObjCPropertyAttribute::kind_readonly) && + !(Attributes & ObjCPropertyAttribute::kind_strong) && PropertyTy->isBlockPointerType()) - Diag(Loc, diag::warn_objc_property_retain_of_block); + Diag(Loc, diag::warn_objc_property_retain_of_block); - if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && - (Attributes & ObjCDeclSpec::DQ_PR_setter)) + if ((Attributes & ObjCPropertyAttribute::kind_readonly) && + (Attributes & ObjCPropertyAttribute::kind_setter)) Diag(Loc, diag::warn_objc_readonly_property_has_setter); } diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 3fce0e27e9b3..920463da4027 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/lib/Sema/SemaOpenMP.cpp @@ -18,12 +18,15 @@ #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclOpenMP.h" +#include "clang/AST/OpenMPClause.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" #include "clang/AST/TypeOrdering.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" @@ -31,7 +34,10 @@ #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/IndexedMap.h" #include "llvm/ADT/PointerEmbeddedInt.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/Frontend/OpenMP/OMPConstants.h" +#include <set> + using namespace clang; using namespace llvm::omp; @@ -47,9 +53,10 @@ static const Expr *checkMapClauseExpressionBase( namespace { /// Default data sharing attributes, which can be applied to directive. enum DefaultDataSharingAttributes { - DSA_unspecified = 0, /// Data sharing attribute not specified. - DSA_none = 1 << 0, /// Default data sharing attribute 'none'. - DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. + DSA_unspecified = 0, /// Data sharing attribute not specified. + DSA_none = 1 << 0, /// Default data sharing attribute 'none'. + DSA_shared = 1 << 1, /// Default data sharing attribute 'shared'. + DSA_firstprivate = 1 << 2, /// Default data sharing attribute 'firstprivate'. }; /// Stack for tracking declarations used in OpenMP directives and @@ -59,24 +66,35 @@ public: struct DSAVarData { OpenMPDirectiveKind DKind = OMPD_unknown; OpenMPClauseKind CKind = OMPC_unknown; + unsigned Modifier = 0; const Expr *RefExpr = nullptr; DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; DSAVarData() = default; DSAVarData(OpenMPDirectiveKind DKind, OpenMPClauseKind CKind, const Expr *RefExpr, DeclRefExpr *PrivateCopy, - SourceLocation ImplicitDSALoc) - : DKind(DKind), CKind(CKind), RefExpr(RefExpr), + SourceLocation ImplicitDSALoc, unsigned Modifier) + : DKind(DKind), CKind(CKind), Modifier(Modifier), RefExpr(RefExpr), PrivateCopy(PrivateCopy), ImplicitDSALoc(ImplicitDSALoc) {} }; using OperatorOffsetTy = llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>; using DoacrossDependMapTy = llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>; + /// Kind of the declaration used in the uses_allocators clauses. + enum class UsesAllocatorsDeclKind { + /// Predefined allocator + PredefinedAllocator, + /// User-defined allocator + UserDefinedAllocator, + /// The declaration that represent allocator trait + AllocatorTrait, + }; private: struct DSAInfo { OpenMPClauseKind Attributes = OMPC_unknown; + unsigned Modifier = 0; /// Pointer to a reference expression and a flag which shows that the /// variable is marked as lastprivate(true) or not (false). llvm::PointerIntPair<const Expr *, 1, bool> RefExpr; @@ -151,13 +169,21 @@ private: bool CancelRegion = false; bool LoopStart = false; bool BodyComplete = false; + SourceLocation PrevScanLocation; + SourceLocation PrevOrderedLocation; SourceLocation InnerTeamsRegionLoc; /// Reference to the taskgroup task_reduction reference expression. Expr *TaskgroupReductionRef = nullptr; llvm::DenseSet<QualType> MappedClassesQualTypes; + SmallVector<Expr *, 4> InnerUsedAllocators; + llvm::DenseSet<CanonicalDeclPtr<Decl>> ImplicitTaskFirstprivates; /// List of globals marked as declare target link in this target region /// (isOpenMPTargetExecutionDirective(Directive) == true). llvm::SmallVector<DeclRefExpr *, 4> DeclareTargetLinkVarDecls; + /// List of decls used in inclusive/exclusive clauses of the scan directive. + llvm::DenseSet<CanonicalDeclPtr<Decl>> UsedInScanDirective; + llvm::DenseMap<CanonicalDeclPtr<const Decl>, UsesAllocatorsDeclKind> + UsesAllocatorsDecls; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) : Directive(DKind), DirectiveName(Name), CurScope(CurScope), @@ -263,11 +289,18 @@ private: SmallVector<const OMPRequiresDecl *, 2> RequiresDecls; /// omp_allocator_handle_t type. QualType OMPAllocatorHandleT; + /// omp_depend_t type. + QualType OMPDependT; + /// omp_event_handle_t type. + QualType OMPEventHandleT; + /// omp_alloctrait_t type. + QualType OMPAlloctraitT; /// Expression for the predefined allocators. Expr *OMPPredefinedAllocators[OMPAllocateDeclAttr::OMPUserDefinedMemAlloc] = { nullptr}; /// Vector of previously encountered target directives SmallVector<SourceLocation, 2> TargetLocations; + SourceLocation AtomicLocation; public: explicit DSAStackTy(Sema &S) : SemaRef(S) {} @@ -276,6 +309,10 @@ public: void setOMPAllocatorHandleT(QualType Ty) { OMPAllocatorHandleT = Ty; } /// Gets omp_allocator_handle_t type. QualType getOMPAllocatorHandleT() const { return OMPAllocatorHandleT; } + /// Sets omp_alloctrait_t type. + void setOMPAlloctraitT(QualType Ty) { OMPAlloctraitT = Ty; } + /// Gets omp_alloctrait_t type. + QualType getOMPAlloctraitT() const { return OMPAlloctraitT; } /// Sets the given default allocator. void setAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind, Expr *Allocator) { @@ -285,6 +322,15 @@ public: Expr *getAllocator(OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind) const { return OMPPredefinedAllocators[AllocatorKind]; } + /// Sets omp_depend_t type. + void setOMPDependT(QualType Ty) { OMPDependT = Ty; } + /// Gets omp_depend_t type. + QualType getOMPDependT() const { return OMPDependT; } + + /// Sets omp_event_handle_t type. + void setOMPEventHandleT(QualType Ty) { OMPEventHandleT = Ty; } + /// Gets omp_event_handle_t type. + QualType getOMPEventHandleT() const { return OMPEventHandleT; } bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } OpenMPClauseKind getClauseParsingMode() const { @@ -439,13 +485,32 @@ public: /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). const LCDeclInfo isParentLoopControlVariable(const ValueDecl *D) const; + /// Check if the specified variable is a loop control variable for + /// current region. + /// \return The index of the loop control variable in the list of associated + /// for-loops (from outer to inner). + const LCDeclInfo isLoopControlVariable(const ValueDecl *D, + unsigned Level) const; /// Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. const ValueDecl *getParentLoopControlVariable(unsigned I) const; + /// Marks the specified decl \p D as used in scan directive. + void markDeclAsUsedInScanDirective(ValueDecl *D) { + if (SharingMapTy *Stack = getSecondOnStackOrNull()) + Stack->UsedInScanDirective.insert(D); + } + + /// Checks if the specified declaration was used in the inner scan directive. + bool isUsedInScanDirective(ValueDecl *D) const { + if (const SharingMapTy *Stack = getTopOfStackOrNull()) + return Stack->UsedInScanDirective.count(D) > 0; + return false; + } + /// Adds explicit data sharing attribute to the specified declaration. void addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy = nullptr); + DeclRefExpr *PrivateCopy = nullptr, unsigned Modifier = 0); /// Adds additional information for the reduction items with the reduction id /// represented as an operator. @@ -467,11 +532,15 @@ public: getTopMostTaskgroupReductionData(const ValueDecl *D, SourceRange &SR, const Expr *&ReductionRef, Expr *&TaskgroupDescriptor) const; - /// Return reduction reference expression for the current taskgroup. + /// Return reduction reference expression for the current taskgroup or + /// parallel/worksharing directives with task reductions. Expr *getTaskgroupReductionRef() const { - assert(getTopOfStack().Directive == OMPD_taskgroup && - "taskgroup reference expression requested for non taskgroup " - "directive."); + assert((getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && + "taskgroup reference expression requested for non taskgroup or " + "parallel/worksharing directive."); return getTopOfStack().TaskgroupReductionRef; } /// Checks if the given \p VD declaration is actually a taskgroup reduction @@ -487,6 +556,8 @@ public: const DSAVarData getTopDSA(ValueDecl *D, bool FromParent); /// Returns data-sharing attributes for the specified declaration. const DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent) const; + /// Returns data-sharing attributes for the specified declaration. + const DSAVarData getImplicitDSA(ValueDecl *D, unsigned Level) const; /// Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. @@ -552,7 +623,7 @@ public: /// Checks if the defined 'requires' directive has specified type of clause. template <typename ClauseType> - bool hasRequiresDeclWithClause() { + bool hasRequiresDeclWithClause() const { return llvm::any_of(RequiresDecls, [](const OMPRequiresDecl *D) { return llvm::any_of(D->clauselists(), [](const OMPClause *C) { return isa<ClauseType>(C); @@ -587,6 +658,18 @@ public: TargetLocations.push_back(LocStart); } + /// Add location for the first encountered atomicc directive. + void addAtomicDirectiveLoc(SourceLocation Loc) { + if (AtomicLocation.isInvalid()) + AtomicLocation = Loc; + } + + /// Returns the location of the first encountered atomic directive in the + /// module. + SourceLocation getAtomicDirectiveLoc() const { + return AtomicLocation; + } + // Return previously encountered target region locations. ArrayRef<SourceLocation> getEncounteredTargetLocs() const { return TargetLocations; @@ -602,6 +685,11 @@ public: getTopOfStack().DefaultAttr = DSA_shared; getTopOfStack().DefaultAttrLoc = Loc; } + /// Set default data sharing attribute to firstprivate. + void setDefaultDSAFirstPrivate(SourceLocation Loc) { + getTopOfStack().DefaultAttr = DSA_firstprivate; + getTopOfStack().DefaultAttrLoc = Loc; + } /// Set default data mapping attribute to Modifier:Kind void setDefaultDMAAttr(OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, @@ -612,10 +700,24 @@ public: } /// Check whether the implicit-behavior has been set in defaultmap bool checkDefaultmapCategory(OpenMPDefaultmapClauseKind VariableCategory) { + if (VariableCategory == OMPC_DEFAULTMAP_unknown) + return getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_aggregate] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown || + getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_scalar] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown || + getTopOfStack() + .DefaultmapMap[OMPC_DEFAULTMAP_pointer] + .ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown; return getTopOfStack().DefaultmapMap[VariableCategory].ImplicitBehavior != OMPC_DEFAULTMAP_MODIFIER_unknown; } + DefaultDataSharingAttributes getDefaultDSA(unsigned Level) const { + return getStackSize() <= Level ? DSA_unspecified + : getStackElemAtLevel(Level).DefaultAttr; + } DefaultDataSharingAttributes getDefaultDSA() const { return isStackEmpty() ? DSA_unspecified : getTopOfStack().DefaultAttr; @@ -738,6 +840,37 @@ public: return Top ? Top->CancelRegion : false; } + /// Mark that parent region already has scan directive. + void setParentHasScanDirective(SourceLocation Loc) { + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->PrevScanLocation = Loc; + } + /// Return true if current region has inner cancel construct. + bool doesParentHasScanDirective() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevScanLocation.isValid() : false; + } + /// Return true if current region has inner cancel construct. + SourceLocation getParentScanDirectiveLoc() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevScanLocation : SourceLocation(); + } + /// Mark that parent region already has ordered directive. + void setParentHasOrderedDirective(SourceLocation Loc) { + if (SharingMapTy *Parent = getSecondOnStackOrNull()) + Parent->PrevOrderedLocation = Loc; + } + /// Return true if current region has inner ordered construct. + bool doesParentHasOrderedDirective() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevOrderedLocation.isValid() : false; + } + /// Returns the location of the previously specified ordered directive. + SourceLocation getParentOrderedDirectiveLoc() const { + const SharingMapTy *Top = getSecondOnStackOrNull(); + return Top ? Top->PrevOrderedLocation : SourceLocation(); + } + /// Set collapse value for the region. void setAssociatedLoops(unsigned Val) { getTopOfStack().AssociatedLoops = Val; @@ -899,6 +1032,46 @@ public: "Expected target executable directive."); return getTopOfStack().DeclareTargetLinkVarDecls; } + + /// Adds list of allocators expressions. + void addInnerAllocatorExpr(Expr *E) { + getTopOfStack().InnerUsedAllocators.push_back(E); + } + /// Return list of used allocators. + ArrayRef<Expr *> getInnerAllocators() const { + return getTopOfStack().InnerUsedAllocators; + } + /// Marks the declaration as implicitly firstprivate nin the task-based + /// regions. + void addImplicitTaskFirstprivate(unsigned Level, Decl *D) { + getStackElemAtLevel(Level).ImplicitTaskFirstprivates.insert(D); + } + /// Checks if the decl is implicitly firstprivate in the task-based region. + bool isImplicitTaskFirstprivate(Decl *D) const { + return getTopOfStack().ImplicitTaskFirstprivates.count(D) > 0; + } + + /// Marks decl as used in uses_allocators clause as the allocator. + void addUsesAllocatorsDecl(const Decl *D, UsesAllocatorsDeclKind Kind) { + getTopOfStack().UsesAllocatorsDecls.try_emplace(D, Kind); + } + /// Checks if specified decl is used in uses allocator clause as the + /// allocator. + Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(unsigned Level, + const Decl *D) const { + const SharingMapTy &StackElem = getTopOfStack(); + auto I = StackElem.UsesAllocatorsDecls.find(D); + if (I == StackElem.UsesAllocatorsDecls.end()) + return None; + return I->getSecond(); + } + Optional<UsesAllocatorsDeclKind> isUsesAllocatorsDecl(const Decl *D) const { + const SharingMapTy &StackElem = getTopOfStack(); + auto I = StackElem.UsesAllocatorsDecls.find(D); + if (I == StackElem.UsesAllocatorsDecls.end()) + return None; + return I->getSecond(); + } }; bool isImplicitTaskingRegion(OpenMPDirectiveKind DKind) { @@ -1001,6 +1174,7 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, DVar.PrivateCopy = Data.PrivateCopy; DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + DVar.Modifier = Data.Modifier; return DVar; } @@ -1015,6 +1189,15 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(const_iterator &Iter, return DVar; case DSA_none: return DVar; + case DSA_firstprivate: + if (VD->getStorageDuration() == SD_Static && + VD->getDeclContext()->isFileContext()) { + DVar.CKind = OMPC_unknown; + } else { + DVar.CKind = OMPC_firstprivate; + } + DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; + return DVar; case DSA_unspecified: // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, implicitly determined, p.2] @@ -1113,6 +1296,19 @@ DSAStackTy::isLoopControlVariable(const ValueDecl *D) const { } const DSAStackTy::LCDeclInfo +DSAStackTy::isLoopControlVariable(const ValueDecl *D, unsigned Level) const { + assert(!isStackEmpty() && "Data-sharing attributes stack is empty"); + D = getCanonicalDecl(D); + for (unsigned I = Level + 1; I > 0; --I) { + const SharingMapTy &StackElem = getStackElemAtLevel(I - 1); + auto It = StackElem.LCVMap.find(D); + if (It != StackElem.LCVMap.end()) + return It->second; + } + return {0, nullptr}; +} + +const DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(const ValueDecl *D) const { const SharingMapTy *Parent = getSecondOnStackOrNull(); assert(Parent && "Data-sharing attributes stack is empty"); @@ -1135,19 +1331,21 @@ const ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) const { } void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, - DeclRefExpr *PrivateCopy) { + DeclRefExpr *PrivateCopy, unsigned Modifier) { D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { DSAInfo &Data = Threadprivates[D]; Data.Attributes = A; Data.RefExpr.setPointer(E); Data.PrivateCopy = nullptr; + Data.Modifier = Modifier; } else { DSAInfo &Data = getTopOfStack().SharingMap[D]; assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || (isLoopControlVariable(D).first && A == OMPC_private)); + Data.Modifier = Modifier; if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) { Data.RefExpr.setInt(/*IntVal=*/true); return; @@ -1159,6 +1357,7 @@ void DSAStackTy::addDSA(const ValueDecl *D, const Expr *E, OpenMPClauseKind A, Data.PrivateCopy = PrivateCopy; if (PrivateCopy) { DSAInfo &Data = getTopOfStack().SharingMap[PrivateCopy->getDecl()]; + Data.Modifier = Modifier; Data.Attributes = A; Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); Data.PrivateCopy = nullptr; @@ -1207,7 +1406,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, "Additional reduction info may be specified only for reduction items."); ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - getTopOfStack().Directive == OMPD_taskgroup && + (getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(BOK, SR); @@ -1230,7 +1432,10 @@ void DSAStackTy::addTaskgroupReductionData(const ValueDecl *D, SourceRange SR, "Additional reduction info may be specified only for reduction items."); ReductionData &ReductionData = getTopOfStack().ReductionMap[D]; assert(ReductionData.ReductionRange.isInvalid() && - getTopOfStack().Directive == OMPD_taskgroup && + (getTopOfStack().Directive == OMPD_taskgroup || + ((isOpenMPParallelDirective(getTopOfStack().Directive) || + isOpenMPWorksharingDirective(getTopOfStack().Directive)) && + !isOpenMPSimdDirective(getTopOfStack().Directive))) && "Additional reduction info may be specified only once for reduction " "items."); ReductionData.set(ReductionRef, SR); @@ -1251,7 +1456,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); - if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + if (Data.Attributes != OMPC_reduction || + Data.Modifier != OMPC_REDUCTION_task) continue; const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || @@ -1263,8 +1469,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "expression for the descriptor is not " "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; - return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task); } return DSAVarData(); } @@ -1276,7 +1482,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( assert(!isStackEmpty() && "Data-sharing attributes stack is empty."); for (const_iterator I = begin() + 1, E = end(); I != E; ++I) { const DSAInfo &Data = I->SharingMap.lookup(D); - if (Data.Attributes != OMPC_reduction || I->Directive != OMPD_taskgroup) + if (Data.Attributes != OMPC_reduction || + Data.Modifier != OMPC_REDUCTION_task) continue; const ReductionData &ReductionData = I->ReductionMap.lookup(D); if (!ReductionData.ReductionOp || @@ -1288,8 +1495,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopMostTaskgroupReductionData( "expression for the descriptor is not " "set."); TaskgroupDescriptor = I->TaskgroupReductionRef; - return DSAVarData(OMPD_taskgroup, OMPC_reduction, Data.RefExpr.getPointer(), - Data.PrivateCopy, I->DefaultAttrLoc); + return DSAVarData(I->Directive, OMPC_reduction, Data.RefExpr.getPointer(), + Data.PrivateCopy, I->DefaultAttrLoc, OMPC_REDUCTION_task); } return DSAVarData(); } @@ -1364,6 +1571,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, if (TI != Threadprivates.end()) { DVar.RefExpr = TI->getSecond().RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; + DVar.Modifier = TI->getSecond().Modifier; return DVar; } if (VD && VD->hasAttr<OMPThreadPrivateDeclAttr>()) { @@ -1447,15 +1655,18 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; - auto It = I->SharingMap.find(D); - if (It != I->SharingMap.end()) { - const DSAInfo &Data = It->getSecond(); - DVar.RefExpr = Data.RefExpr.getPointer(); - DVar.PrivateCopy = Data.PrivateCopy; - DVar.CKind = Data.Attributes; - DVar.ImplicitDSALoc = I->DefaultAttrLoc; - DVar.DKind = I->Directive; - return DVar; + if (I != EndI) { + auto It = I->SharingMap.find(D); + if (It != I->SharingMap.end()) { + const DSAInfo &Data = It->getSecond(); + DVar.RefExpr = Data.RefExpr.getPointer(); + DVar.PrivateCopy = Data.PrivateCopy; + DVar.CKind = Data.Attributes; + DVar.ImplicitDSALoc = I->DefaultAttrLoc; + DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; + return DVar; + } } DVar.CKind = OMPC_shared; @@ -1493,6 +1704,8 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, const_iterator EndI = end(); if (FromParent && I != EndI) ++I; + if (I == EndI) + return DVar; auto It = I->SharingMap.find(D); if (It != I->SharingMap.end()) { const DSAInfo &Data = It->getSecond(); @@ -1501,6 +1714,7 @@ const DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, DVar.CKind = Data.Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; DVar.DKind = I->Directive; + DVar.Modifier = Data.Modifier; } return DVar; @@ -1520,6 +1734,15 @@ const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, return getDSA(StartI, D); } +const DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, + unsigned Level) const { + if (getStackSize() <= Level) + return DSAVarData(); + D = getCanonicalDecl(D); + const_iterator StartI = std::next(begin(), getStackSize() - 1 - Level); + return getDSA(StartI, D); +} + const DSAStackTy::DSAVarData DSAStackTy::hasDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> CPred, @@ -1640,23 +1863,28 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPDeviceCode(SourceLocation Loc, unsigned DiagID) { assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && "Expected OpenMP device compilation."); - FunctionEmissionStatus FES = getEmissionStatus(getCurFunctionDecl()); + + FunctionDecl *FD = getCurFunctionDecl(); DeviceDiagBuilder::Kind Kind = DeviceDiagBuilder::K_Nop; - switch (FES) { - case FunctionEmissionStatus::Emitted: - Kind = DeviceDiagBuilder::K_Immediate; - break; - case FunctionEmissionStatus::Unknown: - Kind = isOpenMPDeviceDelayedContext(*this) ? DeviceDiagBuilder::K_Deferred - : DeviceDiagBuilder::K_Immediate; - break; - case FunctionEmissionStatus::TemplateDiscarded: - case FunctionEmissionStatus::OMPDiscarded: - Kind = DeviceDiagBuilder::K_Nop; - break; - case FunctionEmissionStatus::CUDADiscarded: - llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); - break; + if (FD) { + FunctionEmissionStatus FES = getEmissionStatus(FD); + switch (FES) { + case FunctionEmissionStatus::Emitted: + Kind = DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::Unknown: + Kind = isOpenMPDeviceDelayedContext(*this) + ? DeviceDiagBuilder::K_Deferred + : DeviceDiagBuilder::K_Immediate; + break; + case FunctionEmissionStatus::TemplateDiscarded: + case FunctionEmissionStatus::OMPDiscarded: + Kind = DeviceDiagBuilder::K_Nop; + break; + case FunctionEmissionStatus::CUDADiscarded: + llvm_unreachable("CUDADiscarded unexpected in OpenMP device compilation"); + break; + } } return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); @@ -1685,107 +1913,6 @@ Sema::DeviceDiagBuilder Sema::diagIfOpenMPHostCode(SourceLocation Loc, return DeviceDiagBuilder(Kind, Loc, DiagID, getCurFunctionDecl(), *this); } -void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee, - bool CheckForDelayedContext) { - assert(LangOpts.OpenMP && LangOpts.OpenMPIsDevice && - "Expected OpenMP device compilation."); - assert(Callee && "Callee may not be null."); - Callee = Callee->getMostRecentDecl(); - FunctionDecl *Caller = getCurFunctionDecl(); - - // host only function are not available on the device. - if (Caller) { - FunctionEmissionStatus CallerS = getEmissionStatus(Caller); - FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); - assert(CallerS != FunctionEmissionStatus::CUDADiscarded && - CalleeS != FunctionEmissionStatus::CUDADiscarded && - "CUDADiscarded unexpected in OpenMP device function check"); - if ((CallerS == FunctionEmissionStatus::Emitted || - (!isOpenMPDeviceDelayedContext(*this) && - CallerS == FunctionEmissionStatus::Unknown)) && - CalleeS == FunctionEmissionStatus::OMPDiscarded) { - StringRef HostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_host); - Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; - Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << HostDevTy; - return; - } - } - // If the caller is known-emitted, mark the callee as known-emitted. - // Otherwise, mark the call in our call graph so we can traverse it later. - if ((CheckForDelayedContext && !isOpenMPDeviceDelayedContext(*this)) || - (!Caller && !CheckForDelayedContext) || - (Caller && getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) - markKnownEmitted(*this, Caller, Callee, Loc, - [CheckForDelayedContext](Sema &S, FunctionDecl *FD) { - return CheckForDelayedContext && - S.getEmissionStatus(FD) == - FunctionEmissionStatus::Emitted; - }); - else if (Caller) - DeviceCallGraph[Caller].insert({Callee, Loc}); -} - -void Sema::checkOpenMPHostFunction(SourceLocation Loc, FunctionDecl *Callee, - bool CheckCaller) { - assert(LangOpts.OpenMP && !LangOpts.OpenMPIsDevice && - "Expected OpenMP host compilation."); - assert(Callee && "Callee may not be null."); - Callee = Callee->getMostRecentDecl(); - FunctionDecl *Caller = getCurFunctionDecl(); - - // device only function are not available on the host. - if (Caller) { - FunctionEmissionStatus CallerS = getEmissionStatus(Caller); - FunctionEmissionStatus CalleeS = getEmissionStatus(Callee); - assert( - (LangOpts.CUDA || (CallerS != FunctionEmissionStatus::CUDADiscarded && - CalleeS != FunctionEmissionStatus::CUDADiscarded)) && - "CUDADiscarded unexpected in OpenMP host function check"); - if (CallerS == FunctionEmissionStatus::Emitted && - CalleeS == FunctionEmissionStatus::OMPDiscarded) { - StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_nohost); - Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; - Diag(Callee->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << NoHostDevTy; - return; - } - } - // If the caller is known-emitted, mark the callee as known-emitted. - // Otherwise, mark the call in our call graph so we can traverse it later. - if (!shouldIgnoreInHostDeviceCheck(Callee)) { - if ((!CheckCaller && !Caller) || - (Caller && - getEmissionStatus(Caller) == FunctionEmissionStatus::Emitted)) - markKnownEmitted( - *this, Caller, Callee, Loc, [CheckCaller](Sema &S, FunctionDecl *FD) { - return CheckCaller && - S.getEmissionStatus(FD) == FunctionEmissionStatus::Emitted; - }); - else if (Caller) - DeviceCallGraph[Caller].insert({Callee, Loc}); - } -} - -void Sema::checkOpenMPDeviceExpr(const Expr *E) { - assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && - "OpenMP device compilation mode is expected."); - QualType Ty = E->getType(); - if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || - ((Ty->isFloat128Type() || - (Ty->isRealFloatingType() && Context.getTypeSize(Ty) == 128)) && - !Context.getTargetInfo().hasFloat128Type()) || - (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && - !Context.getTargetInfo().hasInt128Type())) - targetDiag(E->getExprLoc(), diag::err_omp_unsupported_type) - << static_cast<unsigned>(Context.getTypeSize(Ty)) << Ty - << Context.getTargetInfo().getTriple().str() << E->getSourceRange(); -} - static OpenMPDefaultmapClauseKind getVariableCategoryFromDecl(const LangOptions &LO, const ValueDecl *VD) { if (LO.OpenMP <= 45) { @@ -1901,7 +2028,8 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) || isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) || - isa<MemberExpr>(EI->getAssociatedExpression())) { + isa<MemberExpr>(EI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(EI->getAssociatedExpression())) { IsVariableAssociatedWithSection = true; // There is nothing more we need to know about this variable. return true; @@ -1935,14 +2063,23 @@ bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level, ((IsVariableUsedInMapClause && DSAStack->getCaptureRegion(Level, OpenMPCaptureLevel) == OMPD_target) || - !DSAStack->hasExplicitDSA( - D, - [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, - Level, /*NotLastprivate=*/true)) && + !(DSAStack->hasExplicitDSA( + D, + [](OpenMPClauseKind K) -> bool { + return K == OMPC_firstprivate; + }, + Level, /*NotLastprivate=*/true) || + DSAStack->isUsesAllocatorsDecl(Level, D))) && // If the variable is artificial and must be captured by value - try to // capture by value. !(isa<OMPCapturedExprDecl>(D) && !D->hasAttr<OMPCaptureNoInitAttr>() && - !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()); + !cast<OMPCapturedExprDecl>(D)->getInit()->isGLValue()) && + // If the variable is implicitly firstprivate and scalar - capture by + // copy + !(DSAStack->getDefaultDSA() == DSA_firstprivate && + !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K != OMPC_unknown; }, Level) && + !DSAStack->isLoopControlVariable(D, Level).first); } // When passing data by copy, we need to make sure it fits the uintptr size @@ -2010,7 +2147,23 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, // if (OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD)) return nullptr; - return VD; + CapturedRegionScopeInfo *CSI = nullptr; + for (FunctionScopeInfo *FSI : llvm::drop_begin( + llvm::reverse(FunctionScopes), + CheckScopeInfo ? (FunctionScopes.size() - (StopAt + 1)) : 0)) { + if (!isa<CapturingScopeInfo>(FSI)) + return nullptr; + if (auto *RSI = dyn_cast<CapturedRegionScopeInfo>(FSI)) + if (RSI->CapRegionKind == CR_OpenMP) { + CSI = RSI; + break; + } + } + SmallVector<OpenMPDirectiveKind, 4> Regions; + getOpenMPCaptureRegions(Regions, + DSAStack->getDirective(CSI->OpenMPLevel)); + if (Regions[CSI->OpenMPCaptureLevel] != OMPD_task) + return VD; } } @@ -2039,20 +2192,27 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, isImplicitOrExplicitTaskingRegion(DSAStack->getCurrentDirective())) || (VD && DSAStack->isForceVarCapturing())) return VD ? VD : Info.second; - DSAStackTy::DSAVarData DVarPrivate = + DSAStackTy::DSAVarData DVarTop = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); - if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) - return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + if (DVarTop.CKind != OMPC_unknown && isOpenMPPrivate(DVarTop.CKind)) + return VD ? VD : cast<VarDecl>(DVarTop.PrivateCopy->getDecl()); // Threadprivate variables must not be captured. - if (isOpenMPThreadPrivate(DVarPrivate.CKind)) + if (isOpenMPThreadPrivate(DVarTop.CKind)) return nullptr; // The variable is not private or it is the variable in the directive with // default(none) clause and not used in any clause. - DVarPrivate = DSAStack->hasDSA(D, isOpenMPPrivate, - [](OpenMPDirectiveKind) { return true; }, - DSAStack->isClauseParsingMode()); + DSAStackTy::DSAVarData DVarPrivate = DSAStack->hasDSA( + D, isOpenMPPrivate, [](OpenMPDirectiveKind) { return true; }, + DSAStack->isClauseParsingMode()); + // Global shared must not be captured. + if (VD && !VD->hasLocalStorage() && DVarPrivate.CKind == OMPC_unknown && + ((DSAStack->getDefaultDSA() != DSA_none && + DSAStack->getDefaultDSA() != DSA_firstprivate) || + DVarTop.CKind == OMPC_shared)) + return nullptr; if (DVarPrivate.CKind != OMPC_unknown || - (VD && DSAStack->getDefaultDSA() == DSA_none)) + (VD && (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate))) return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } return nullptr; @@ -2060,9 +2220,7 @@ VarDecl *Sema::isOpenMPCapturedDecl(ValueDecl *D, bool CheckScopeInfo, void Sema::adjustOpenMPTargetScopeIndex(unsigned &FunctionScopesIndex, unsigned Level) const { - SmallVector<OpenMPDirectiveKind, 4> Regions; - getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level)); - FunctionScopesIndex -= Regions.size(); + FunctionScopesIndex -= getOpenMPCaptureLevels(DSAStack->getDirective(Level)); } void Sema::startOpenMPLoop() { @@ -2079,39 +2237,77 @@ void Sema::startOpenMPCXXRangeFor() { } } -bool Sema::isOpenMPPrivateDecl(const ValueDecl *D, unsigned Level) const { +OpenMPClauseKind Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level, + unsigned CapLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); + if (DSAStack->hasExplicitDirective( + [](OpenMPDirectiveKind K) { return isOpenMPTaskingDirective(K); }, + Level)) { + bool IsTriviallyCopyable = + D->getType().getNonReferenceType().isTriviallyCopyableType(Context); + OpenMPDirectiveKind DKind = DSAStack->getDirective(Level); + SmallVector<OpenMPDirectiveKind, 4> CaptureRegions; + getOpenMPCaptureRegions(CaptureRegions, DKind); + if (isOpenMPTaskingDirective(CaptureRegions[CapLevel]) && + (IsTriviallyCopyable || + !isOpenMPTaskLoopDirective(CaptureRegions[CapLevel]))) { + if (DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true)) + return OMPC_firstprivate; + DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level); + if (DVar.CKind != OMPC_shared && + !DSAStack->isLoopControlVariable(D, Level).first && !DVar.RefExpr) { + DSAStack->addImplicitTaskFirstprivate(Level, D); + return OMPC_firstprivate; + } + } + } if (isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { if (DSAStack->getAssociatedLoops() > 0 && !DSAStack->isLoopStarted()) { DSAStack->resetPossibleLoopCounter(D); DSAStack->loopStart(); - return true; + return OMPC_private; } if ((DSAStack->getPossiblyLoopCunter() == D->getCanonicalDecl() || DSAStack->isLoopControlVariable(D).first) && !DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K != OMPC_private; }, Level) && !isOpenMPSimdDirective(DSAStack->getCurrentDirective())) - return true; + return OMPC_private; } if (const auto *VD = dyn_cast<VarDecl>(D)) { if (DSAStack->isThreadPrivate(const_cast<VarDecl *>(VD)) && DSAStack->isForceVarCapturing() && !DSAStack->hasExplicitDSA( D, [](OpenMPClauseKind K) { return K == OMPC_copyin; }, Level)) - return true; - } - return DSAStack->hasExplicitDSA( - D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || - (DSAStack->isClauseParsingMode() && - DSAStack->getClauseParsingMode() == OMPC_private) || - // Consider taskgroup reduction descriptor variable a private to avoid - // possible capture in the region. - (DSAStack->hasExplicitDirective( - [](OpenMPDirectiveKind K) { return K == OMPD_taskgroup; }, - Level) && - DSAStack->isTaskgroupReductionRef(D, Level)); + return OMPC_private; + } + // User-defined allocators are private since they must be defined in the + // context of target region. + if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level) && + DSAStack->isUsesAllocatorsDecl(Level, D).getValueOr( + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) == + DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator) + return OMPC_private; + return (DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) { return K == OMPC_private; }, Level) || + (DSAStack->isClauseParsingMode() && + DSAStack->getClauseParsingMode() == OMPC_private) || + // Consider taskgroup reduction descriptor variable a private + // to avoid possible capture in the region. + (DSAStack->hasExplicitDirective( + [](OpenMPDirectiveKind K) { + return K == OMPD_taskgroup || + ((isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K)) && + !isOpenMPSimdDirective(K)); + }, + Level) && + DSAStack->isTaskgroupReductionRef(D, Level))) + ? OMPC_private + : OMPC_unknown; } void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, @@ -2148,68 +2344,101 @@ void Sema::setOpenMPCaptureKind(FieldDecl *FD, const ValueDecl *D, } } if (OMPC != OMPC_unknown) - FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, OMPC)); + FD->addAttr(OMPCaptureKindAttr::CreateImplicit(Context, unsigned(OMPC))); } -bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, - unsigned Level) const { +bool Sema::isOpenMPTargetCapturedDecl(const ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); // Return true if the current level is no longer enclosed in a target region. + SmallVector<OpenMPDirectiveKind, 4> Regions; + getOpenMPCaptureRegions(Regions, DSAStack->getDirective(Level)); const auto *VD = dyn_cast<VarDecl>(D); return VD && !VD->hasLocalStorage() && DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, - Level); + Level) && + Regions[CaptureLevel] != OMPD_task; +} + +bool Sema::isOpenMPGlobalCapturedDecl(ValueDecl *D, unsigned Level, + unsigned CaptureLevel) const { + assert(LangOpts.OpenMP && "OpenMP is not allowed"); + // Return true if the current level is no longer enclosed in a target region. + + if (const auto *VD = dyn_cast<VarDecl>(D)) { + if (!VD->hasLocalStorage()) { + DSAStackTy::DSAVarData TopDVar = + DSAStack->getTopDSA(D, /*FromParent=*/false); + unsigned NumLevels = + getOpenMPCaptureLevels(DSAStack->getDirective(Level)); + if (Level == 0) + return (NumLevels == CaptureLevel + 1) && TopDVar.CKind != OMPC_shared; + DSAStackTy::DSAVarData DVar = DSAStack->getImplicitDSA(D, Level - 1); + return DVar.CKind != OMPC_shared || + isOpenMPGlobalCapturedDecl( + D, Level - 1, + getOpenMPCaptureLevels(DSAStack->getDirective(Level - 1)) - 1); + } + } + return true; } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } -void Sema::finalizeOpenMPDelayedAnalysis() { +void Sema::ActOnOpenMPBeginDeclareVariant(SourceLocation Loc, + OMPTraitInfo &TI) { + if (!OMPDeclareVariantScopes.empty()) { + Diag(Loc, diag::warn_nested_declare_variant); + return; + } + OMPDeclareVariantScopes.push_back(OMPDeclareVariantScope(TI)); +} + +void Sema::ActOnOpenMPEndDeclareVariant() { + assert(isInOpenMPDeclareVariantScope() && + "Not in OpenMP declare variant scope!"); + + OMPDeclareVariantScopes.pop_back(); +} + +void Sema::finalizeOpenMPDelayedAnalysis(const FunctionDecl *Caller, + const FunctionDecl *Callee, + SourceLocation Loc) { assert(LangOpts.OpenMP && "Expected OpenMP compilation mode."); - // Diagnose implicit declare target functions and their callees. - for (const auto &CallerCallees : DeviceCallGraph) { - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType( - CallerCallees.getFirst()->getMostRecentDecl()); - // Ignore host functions during device analyzis. - if (LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_Host) - continue; - // Ignore nohost functions during host analyzis. - if (!LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) - continue; - for (const std::pair<CanonicalDeclPtr<FunctionDecl>, SourceLocation> - &Callee : CallerCallees.getSecond()) { - const FunctionDecl *FD = Callee.first->getMostRecentDecl(); - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType(FD); - if (LangOpts.OpenMPIsDevice && DevTy && - *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { - // Diagnose host function called during device codegen. - StringRef HostDevTy = getOpenMPSimpleClauseTypeName( - OMPC_device_type, OMPC_DEVICE_TYPE_host); - Diag(Callee.second, diag::err_omp_wrong_device_function_call) - << HostDevTy << 0; - Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), - diag::note_omp_marked_device_type_here) - << HostDevTy; - continue; - } + Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = + OMPDeclareTargetDeclAttr::getDeviceType(Caller->getMostRecentDecl()); + // Ignore host functions during device analyzis. + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) + return; + // Ignore nohost functions during host analyzis. + if (!LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) + return; + const FunctionDecl *FD = Callee->getMostRecentDecl(); + DevTy = OMPDeclareTargetDeclAttr::getDeviceType(FD); + if (LangOpts.OpenMPIsDevice && DevTy && + *DevTy == OMPDeclareTargetDeclAttr::DT_Host) { + // Diagnose host function called during device codegen. + StringRef HostDevTy = + getOpenMPSimpleClauseTypeName(OMPC_device_type, OMPC_DEVICE_TYPE_host); + Diag(Loc, diag::err_omp_wrong_device_function_call) << HostDevTy << 0; + Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), + diag::note_omp_marked_device_type_here) + << HostDevTy; + return; + } if (!LangOpts.OpenMPIsDevice && DevTy && *DevTy == OMPDeclareTargetDeclAttr::DT_NoHost) { // Diagnose nohost function called during host codegen. StringRef NoHostDevTy = getOpenMPSimpleClauseTypeName( OMPC_device_type, OMPC_DEVICE_TYPE_nohost); - Diag(Callee.second, diag::err_omp_wrong_device_function_call) - << NoHostDevTy << 1; + Diag(Loc, diag::err_omp_wrong_device_function_call) << NoHostDevTy << 1; Diag(FD->getAttr<OMPDeclareTargetDeclAttr>()->getLocation(), diag::note_omp_marked_device_type_here) << NoHostDevTy; - continue; } - } - } } void Sema::StartOpenMPDSABlock(OpenMPDirectiveKind DKind, @@ -2228,14 +2457,86 @@ void Sema::EndOpenMPClause() { DSAStack->setClauseParsingMode(/*K=*/OMPC_unknown); } -static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, - ArrayRef<OMPClause *> Clauses); static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, SourceRange &ERange, bool AllowArraySection = false); + +/// Check consistency of the reduction clauses. +static void checkReductionClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses) { + bool InscanFound = false; + SourceLocation InscanLoc; + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions. + // A reduction clause without the inscan reduction-modifier may not appear on + // a construct on which a reduction clause with the inscan reduction-modifier + // appears. + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast<OMPReductionClause>(C); + if (RC->getModifier() == OMPC_REDUCTION_inscan) { + InscanFound = true; + InscanLoc = RC->getModifierLoc(); + continue; + } + if (RC->getModifier() == OMPC_REDUCTION_task) { + // OpenMP 5.0, 2.19.5.4 reduction Clause. + // A reduction clause with the task reduction-modifier may only appear on + // a parallel construct, a worksharing construct or a combined or + // composite construct for which any of the aforementioned constructs is a + // constituent construct and simd or loop are not constituent constructs. + OpenMPDirectiveKind CurDir = Stack->getCurrentDirective(); + if (!(isOpenMPParallelDirective(CurDir) || + isOpenMPWorksharingDirective(CurDir)) || + isOpenMPSimdDirective(CurDir)) + S.Diag(RC->getModifierLoc(), + diag::err_omp_reduction_task_not_parallel_or_worksharing); + continue; + } + } + if (InscanFound) { + for (OMPClause *C : Clauses) { + if (C->getClauseKind() != OMPC_reduction) + continue; + auto *RC = cast<OMPReductionClause>(C); + if (RC->getModifier() != OMPC_REDUCTION_inscan) { + S.Diag(RC->getModifier() == OMPC_REDUCTION_unknown + ? RC->getBeginLoc() + : RC->getModifierLoc(), + diag::err_omp_inscan_reduction_expected); + S.Diag(InscanLoc, diag::note_omp_previous_inscan_reduction); + continue; + } + for (Expr *Ref : RC->varlists()) { + assert(Ref && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = Ref; + auto Res = getPrivateItem(S, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + ValueDecl *D = Res.first; + if (!D) + continue; + if (!Stack->isUsedInScanDirective(getCanonicalDecl(D))) { + S.Diag(Ref->getExprLoc(), + diag::err_omp_reduction_not_inclusive_exclusive) + << Ref->getSourceRange(); + } + } + } + } +} + +static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, + ArrayRef<OMPClause *> Clauses); static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, bool WithInit); +static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, + const ValueDecl *D, + const DSAStackTy::DSAVarData &DVar, + bool IsLoopIterVar = false); + void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // OpenMP [2.14.3.5, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a lastprivate @@ -2305,10 +2606,56 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { Clause->setPrivateRefs(PrivateRefs); continue; } + if (auto *Clause = dyn_cast<OMPUsesAllocatorsClause>(C)) { + for (unsigned I = 0, E = Clause->getNumberOfAllocators(); I < E; ++I) { + OMPUsesAllocatorsClause::Data D = Clause->getAllocatorData(I); + auto *DRE = dyn_cast<DeclRefExpr>(D.Allocator->IgnoreParenImpCasts()); + if (!DRE) + continue; + ValueDecl *VD = DRE->getDecl(); + if (!VD || !isa<VarDecl>(VD)) + continue; + DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(VD, /*FromParent=*/false); + // OpenMP [2.12.5, target Construct] + // Memory allocators that appear in a uses_allocators clause cannot + // appear in other data-sharing attribute clauses or data-mapping + // attribute clauses in the same construct. + Expr *MapExpr = nullptr; + if (DVar.RefExpr || + DSAStack->checkMappableExprComponentListsForDecl( + VD, /*CurrentRegionOnly=*/true, + [VD, &MapExpr]( + OMPClauseMappableExprCommon::MappableExprComponentListRef + MapExprComponents, + OpenMPClauseKind C) { + auto MI = MapExprComponents.rbegin(); + auto ME = MapExprComponents.rend(); + if (MI != ME && + MI->getAssociatedDeclaration()->getCanonicalDecl() == + VD->getCanonicalDecl()) { + MapExpr = MI->getAssociatedExpression(); + return true; + } + return false; + })) { + Diag(D.Allocator->getExprLoc(), + diag::err_omp_allocator_used_in_clauses) + << D.Allocator->getSourceRange(); + if (DVar.RefExpr) + reportOriginalDsa(*this, DSAStack, VD, DVar); + else + Diag(MapExpr->getExprLoc(), diag::note_used_here) + << MapExpr->getSourceRange(); + } + } + continue; + } } // Check allocate clauses. if (!CurContext->isDependentContext()) checkAllocateClauses(*this, DSAStack, D->clauses()); + checkReductionClauses(*this, DSAStack, D->clauses()); } DSAStack->pop(); @@ -2618,15 +2965,14 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { static OMPAllocateDeclAttr::AllocatorTypeTy getAllocatorKind(Sema &S, DSAStackTy *Stack, Expr *Allocator) { if (!Allocator) - return OMPAllocateDeclAttr::OMPDefaultMemAlloc; + return OMPAllocateDeclAttr::OMPNullMemAlloc; if (Allocator->isTypeDependent() || Allocator->isValueDependent() || Allocator->isInstantiationDependent() || Allocator->containsUnexpandedParameterPack()) return OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; auto AllocatorKindRes = OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; const Expr *AE = Allocator->IgnoreParenImpCasts(); - for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; - I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); const Expr *DefAllocator = Stack->getAllocator(AllocatorKind); llvm::FoldingSetNodeID AEId, DAEId; @@ -2799,18 +3145,26 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, /// current compilation unit. ArrayRef<SourceLocation> TargetLocations = DSAStack->getEncounteredTargetLocs(); - if (!TargetLocations.empty()) { + SourceLocation AtomicLoc = DSAStack->getAtomicDirectiveLoc(); + if (!TargetLocations.empty() || !AtomicLoc.isInvalid()) { for (const OMPClause *CNew : ClauseList) { // Check if any of the requires clauses affect target regions. if (isa<OMPUnifiedSharedMemoryClause>(CNew) || isa<OMPUnifiedAddressClause>(CNew) || isa<OMPReverseOffloadClause>(CNew) || isa<OMPDynamicAllocatorsClause>(CNew)) { - Diag(Loc, diag::err_omp_target_before_requires) - << getOpenMPClauseName(CNew->getClauseKind()); + Diag(Loc, diag::err_omp_directive_before_requires) + << "target" << getOpenMPClauseName(CNew->getClauseKind()); for (SourceLocation TargetLoc : TargetLocations) { - Diag(TargetLoc, diag::note_omp_requires_encountered_target); + Diag(TargetLoc, diag::note_omp_requires_encountered_directive) + << "target"; } + } else if (!AtomicLoc.isInvalid() && + isa<OMPAtomicDefaultMemOrderClause>(CNew)) { + Diag(Loc, diag::err_omp_directive_before_requires) + << "atomic" << getOpenMPClauseName(CNew->getClauseKind()); + Diag(AtomicLoc, diag::note_omp_requires_encountered_directive) + << "atomic"; } } } @@ -2824,7 +3178,7 @@ OMPRequiresDecl *Sema::CheckOMPRequiresDecl(SourceLocation Loc, static void reportOriginalDsa(Sema &SemaRef, const DSAStackTy *Stack, const ValueDecl *D, const DSAStackTy::DSAVarData &DVar, - bool IsLoopIterVar = false) { + bool IsLoopIterVar) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(DVar.CKind); @@ -2944,6 +3298,16 @@ class DSAAttrChecker final : public StmtVisitor<DSAAttrChecker, void> { Visit(S->getInnermostCapturedStmt()->getCapturedStmt()); TryCaptureCXXThisMembers = SavedTryCaptureCXXThisMembers; } + // In tasks firstprivates are not captured anymore, need to analyze them + // explicitly. + if (isOpenMPTaskingDirective(S->getDirectiveKind()) && + !isOpenMPTaskLoopDirective(S->getDirectiveKind())) { + for (OMPClause *C : S->clauses()) + if (auto *FC = dyn_cast<OMPFirstprivateClause>(C)) { + for (Expr *Ref : FC->varlists()) + Visit(Ref); + } + } } public: @@ -2966,7 +3330,11 @@ public: return; VD = VD->getCanonicalDecl(); // Skip internally declared variables. - if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD)) + if (VD->hasLocalStorage() && CS && !CS->capturesVariable(VD) && + !Stack->isImplicitTaskFirstprivate(VD)) + return; + // Skip allocators in uses_allocators clauses. + if (Stack->isUsesAllocatorsDecl(VD).hasValue()) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(VD, /*FromParent=*/false); @@ -2979,7 +3347,8 @@ public: OMPDeclareTargetDeclAttr::isDeclareTargetDeclaration(VD); if (VD->hasGlobalStorage() && CS && !CS->capturesVariable(VD) && (Stack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || - !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link)) + !Res || *Res != OMPDeclareTargetDeclAttr::MT_Link) && + !Stack->isImplicitTaskFirstprivate(VD)) return; SourceLocation ELoc = E->getExprLoc(); @@ -2988,10 +3357,19 @@ public: // in the construct, and does not have a predetermined data-sharing // attribute, must have its data-sharing attribute explicitly determined // by being listed in a data-sharing attribute clause. - if (DVar.CKind == OMPC_unknown && Stack->getDefaultDSA() == DSA_none && + if (DVar.CKind == OMPC_unknown && + (Stack->getDefaultDSA() == DSA_none || + Stack->getDefaultDSA() == DSA_firstprivate) && isImplicitOrExplicitTaskingRegion(DKind) && VarsWithInheritedDSA.count(VD) == 0) { - VarsWithInheritedDSA[VD] = E; + bool InheritedDSA = Stack->getDefaultDSA() == DSA_none; + if (!InheritedDSA && Stack->getDefaultDSA() == DSA_firstprivate) { + DSAStackTy::DSAVarData DVar = + Stack->getImplicitDSA(VD, /*FromParent=*/false); + InheritedDSA = DVar.CKind == OMPC_unknown; + } + if (InheritedDSA) + VarsWithInheritedDSA[VD] = E; return; } @@ -3036,7 +3414,7 @@ public: StackComponents, OpenMPClauseKind) { // Variable is used if it has been marked as an array, array - // section or the variable iself. + // section, array shaping or the variable iself. return StackComponents.size() == 1 || std::all_of( std::next(StackComponents.rbegin()), @@ -3047,6 +3425,8 @@ public: nullptr && (isa<OMPArraySectionExpr>( MC.getAssociatedExpression()) || + isa<OMPArrayShapingExpr>( + MC.getAssociatedExpression()) || isa<ArraySubscriptExpr>( MC.getAssociatedExpression())); }); @@ -3091,7 +3471,9 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, /*FromParent=*/false); - if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + if (((isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared) || + (Stack->getDefaultDSA() == DSA_firstprivate && + DVar.CKind == OMPC_firstprivate && !DVar.RefExpr)) && !Stack->isLoopControlVariable(VD).first) { ImplicitFirstprivate.push_back(E); return; @@ -3112,7 +3494,7 @@ public: return; auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl()); OpenMPDirectiveKind DKind = Stack->getCurrentDirective(); - if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParens())) { + if (auto *TE = dyn_cast<CXXThisExpr>(E->getBase()->IgnoreParenCasts())) { if (!FD) return; DSAStackTy::DSAVarData DVar = Stack->getTopDSA(FD, /*FromParent=*/false); @@ -3204,8 +3586,10 @@ public: // Do both expressions have the same kind? if (CCI->getAssociatedExpression()->getStmtClass() != SC.getAssociatedExpression()->getStmtClass()) - if (!(isa<OMPArraySectionExpr>( - SC.getAssociatedExpression()) && + if (!((isa<OMPArraySectionExpr>( + SC.getAssociatedExpression()) || + isa<OMPArrayShapingExpr>( + SC.getAssociatedExpression())) && isa<ArraySubscriptExpr>( CCI->getAssociatedExpression()))) return false; @@ -3516,7 +3900,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { }; // Start a captured region for 'parallel'. ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - ParamsParallel, /*OpenMPCaptureLevel=*/1); + ParamsParallel, /*OpenMPCaptureLevel=*/0); QualType Args[] = {VoidPtrTy}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; @@ -3537,7 +3921,7 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params, /*OpenMPCaptureLevel=*/2); + Params, /*OpenMPCaptureLevel=*/1); // Mark this captured region as inlined, because we don't use outlined // function directly. getCurCapturedRegion()->TheCapturedDecl->addAttr( @@ -3688,6 +4072,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: @@ -3695,8 +4081,11 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_end_declare_target: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } } @@ -3841,6 +4230,36 @@ void Sema::tryCaptureOpenMPLambdas(ValueDecl *V) { } } +static bool checkOrderedOrderSpecified(Sema &S, + const ArrayRef<OMPClause *> Clauses) { + const OMPOrderedClause *Ordered = nullptr; + const OMPOrderClause *Order = nullptr; + + for (const OMPClause *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_ordered) + Ordered = cast<OMPOrderedClause>(Clause); + else if (Clause->getClauseKind() == OMPC_order) { + Order = cast<OMPOrderClause>(Clause); + if (Order->getKind() != OMPC_ORDER_concurrent) + Order = nullptr; + } + if (Ordered && Order) + break; + } + + if (Ordered && Order) { + S.Diag(Order->getKindKwLoc(), + diag::err_omp_simple_clause_incompatible_with_ordered) + << getOpenMPClauseName(OMPC_order) + << getOpenMPSimpleClauseTypeName(OMPC_order, OMPC_ORDER_concurrent) + << SourceRange(Order->getBeginLoc(), Order->getEndLoc()); + S.Diag(Ordered->getBeginLoc(), diag::note_omp_ordered_param) + << 0 << SourceRange(Ordered->getBeginLoc(), Ordered->getEndLoc()); + return true; + } + return false; +} + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { bool ErrorFound = false; @@ -3859,7 +4278,8 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, SmallVector<const OMPClauseWithPreInit *, 4> PICs; // This is required for proper codegen. for (OMPClause *Clause : Clauses) { - if (isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && + if (!LangOpts.OpenMPSimd && + isOpenMPTaskingDirective(DSAStack->getCurrentDirective()) && Clause->getClauseKind() == OMPC_in_reduction) { // Capture taskgroup task_reduction descriptors inside the tasking regions // with the corresponding in_reduction items. @@ -3897,6 +4317,9 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, else if (Clause->getClauseKind() == OMPC_linear) LCs.push_back(cast<OMPLinearClause>(Clause)); } + // Capture allocator expressions if used. + for (Expr *E : DSAStack->getInnerAllocators()) + MarkDeclarationsReferencedInExpr(E); // OpenMP, 2.7.1 Loop Construct, Restrictions // The nonmonotonic modifier cannot be specified if an ordered clause is // specified. @@ -3908,10 +4331,18 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, Diag(SC->getFirstScheduleModifier() == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? SC->getFirstScheduleModifierLoc() : SC->getSecondScheduleModifierLoc(), - diag::err_omp_schedule_nonmonotonic_ordered) + diag::err_omp_simple_clause_incompatible_with_ordered) + << getOpenMPClauseName(OMPC_schedule) + << getOpenMPSimpleClauseTypeName(OMPC_schedule, + OMPC_SCHEDULE_MODIFIER_nonmonotonic) << SourceRange(OC->getBeginLoc(), OC->getEndLoc()); ErrorFound = true; } + // OpenMP 5.0, 2.9.2 Worksharing-Loop Construct, Restrictions. + // If an order(concurrent) clause is present, an ordered clause may not appear + // on the same directive. + if (checkOrderedOrderSpecified(*this, Clauses)) + ErrorFound = true; if (!LCs.empty() && OC && OC->getNumForLoops()) { for (const OMPLinearClause *C : LCs) { Diag(C->getBeginLoc(), diag::err_omp_linear_ordered) @@ -3952,6 +4383,21 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } } + if (ThisCaptureRegion == OMPD_target) { + // Capture allocator traits in the target region. They are used implicitly + // and, thus, are not captured by default. + for (OMPClause *C : Clauses) { + if (const auto *UAC = dyn_cast<OMPUsesAllocatorsClause>(C)) { + for (unsigned I = 0, End = UAC->getNumberOfAllocators(); I < End; + ++I) { + OMPUsesAllocatorsClause::Data D = UAC->getAllocatorData(I); + if (Expr *E = D.AllocatorTraits) + MarkDeclarationsReferencedInExpr(E); + } + continue; + } + } + } if (++CompletedRegions == CaptureRegions.size()) DSAStack->setBodyComplete(); SR = ActOnCapturedRegionEnd(SR.get()); @@ -3991,12 +4437,14 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ShouldBeInParallelRegion, ShouldBeInOrderedRegion, ShouldBeInTargetRegion, - ShouldBeInTeamsRegion + ShouldBeInTeamsRegion, + ShouldBeInLoopSimdRegion, } Recommend = NoRecommend; if (isOpenMPSimdDirective(ParentRegion) && ((SemaRef.LangOpts.OpenMP <= 45 && CurrentRegion != OMPD_ordered) || (SemaRef.LangOpts.OpenMP >= 50 && CurrentRegion != OMPD_ordered && - CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic))) { + CurrentRegion != OMPD_simd && CurrentRegion != OMPD_atomic && + CurrentRegion != OMPD_scan))) { // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. // OpenMP [2.8.1,simd Construct, Restrictions] @@ -4041,7 +4489,7 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, if (ParentRegion == OMPD_unknown && !isOpenMPNestingTeamsDirective(CurrentRegion) && CurrentRegion != OMPD_cancellation_point && - CurrentRegion != OMPD_cancel) + CurrentRegion != OMPD_cancel && CurrentRegion != OMPD_scan) return false; if (CurrentRegion == OMPD_cancellation_point || CurrentRegion == OMPD_cancel) { @@ -4066,7 +4514,12 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ParentRegion == OMPD_distribute_parallel_for || ParentRegion == OMPD_teams_distribute_parallel_for || ParentRegion == OMPD_target_teams_distribute_parallel_for)) || - (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || + (CancelRegion == OMPD_taskgroup && + (ParentRegion == OMPD_task || + (SemaRef.getLangOpts().OpenMP >= 50 && + (ParentRegion == OMPD_taskloop || + ParentRegion == OMPD_master_taskloop || + ParentRegion == OMPD_parallel_master_taskloop)))) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || ParentRegion == OMPD_parallel_sections))); @@ -4150,6 +4603,17 @@ static bool checkNestingOfRegions(Sema &SemaRef, const DSAStackTy *Stack, ParentRegion != OMPD_target); OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; + } else if (CurrentRegion == OMPD_scan) { + // OpenMP [2.16, Nesting of Regions] + // If specified, a teams construct must be contained within a target + // construct. + NestingProhibited = + SemaRef.LangOpts.OpenMP < 50 || + (ParentRegion != OMPD_simd && ParentRegion != OMPD_for && + ParentRegion != OMPD_for_simd && ParentRegion != OMPD_parallel_for && + ParentRegion != OMPD_parallel_for_simd); + OrphanSeen = ParentRegion == OMPD_unknown; + Recommend = ShouldBeInLoopSimdRegion; } if (!NestingProhibited && !isOpenMPTargetExecutionDirective(CurrentRegion) && @@ -4216,7 +4680,7 @@ static bool checkIfClauses(Sema &S, OpenMPDirectiveKind Kind, bool ErrorFound = false; unsigned NamedModifiersNumber = 0; llvm::IndexedMap<const OMPIfClause *, Kind2Unsigned> FoundNameModifiers; - FoundNameModifiers.resize(unsigned(OMPD_unknown) + 1); + FoundNameModifiers.resize(llvm::omp::Directive_enumSize + 1); SmallVector<SourceLocation, 4> NameModifierLoc; for (const OMPClause *C : Clauses) { if (const auto *IC = dyn_cast_or_null<OMPIfClause>(C)) { @@ -4353,6 +4817,30 @@ static std::pair<ValueDecl *, bool> getPrivateItem(Sema &S, Expr *&RefExpr, getCanonicalDecl(DE ? DE->getDecl() : ME->getMemberDecl()), false); } +namespace { +/// Checks if the allocator is used in uses_allocators clause to be allowed in +/// target regions. +class AllocatorChecker final : public ConstStmtVisitor<AllocatorChecker, bool> { + DSAStackTy *S = nullptr; + +public: + bool VisitDeclRefExpr(const DeclRefExpr *E) { + return S->isUsesAllocatorsDecl(E->getDecl()) + .getValueOr( + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait) == + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait; + } + bool VisitStmt(const Stmt *S) { + for (const Stmt *Child : S->children()) { + if (Child && Visit(Child)) + return true; + } + return false; + } + explicit AllocatorChecker(DSAStackTy *S) : S(S) {} +}; +} // namespace + static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, ArrayRef<OMPClause *> Clauses) { assert(!S.CurContext->isDependentContext() && @@ -4421,6 +4909,22 @@ static void checkAllocateClauses(Sema &S, DSAStackTy *Stack, } for (OMPClause *C : AllocateRange) { auto *AC = cast<OMPAllocateClause>(C); + if (S.getLangOpts().OpenMP >= 50 && + !Stack->hasRequiresDeclWithClause<OMPDynamicAllocatorsClause>() && + isOpenMPTargetExecutionDirective(Stack->getCurrentDirective()) && + AC->getAllocator()) { + Expr *Allocator = AC->getAllocator(); + // OpenMP, 2.12.5 target Construct + // Memory allocators that do not appear in a uses_allocators clause cannot + // appear as an allocator in an allocate clause or be used in the target + // region unless a requires directive with the dynamic_allocators clause + // is present in the same compilation unit. + AllocatorChecker Checker(Stack); + if (Checker.Visit(Allocator)) + S.Diag(Allocator->getExprLoc(), + diag::err_omp_allocator_not_in_uses_allocators) + << Allocator->getSourceRange(); + } OMPAllocateDeclAttr::AllocatorTypeTy AllocatorKind = getAllocatorKind(S, Stack, AC->getAllocator()); // OpenMP, 2.11.4 allocate Clause, Restrictions. @@ -4513,6 +5017,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (E) ImplicitFirstprivates.emplace_back(E); } + // OpenMP 5.0, 2.10.1 task Construct + // [detach clause]... The event-handle will be considered as if it was + // specified on a firstprivate clause. + if (auto *DC = dyn_cast<OMPDetachClause>(C)) + ImplicitFirstprivates.push_back(DC->getEventHandler()); } if (!ImplicitFirstprivates.empty()) { if (OMPClause *Implicit = ActOnOpenMPFirstprivateClause( @@ -4648,6 +5157,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( "No associated statement allowed for 'omp flush' directive"); Res = ActOnOpenMPFlushDirective(ClausesWithImplicit, StartLoc, EndLoc); break; + case OMPD_depobj: + assert(AStmt == nullptr && + "No associated statement allowed for 'omp depobj' directive"); + Res = ActOnOpenMPDepobjDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; + case OMPD_scan: + assert(AStmt == nullptr && + "No associated statement allowed for 'omp scan' directive"); + Res = ActOnOpenMPScanDirective(ClausesWithImplicit, StartLoc, EndLoc); + break; case OMPD_ordered: Res = ActOnOpenMPOrderedDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc); @@ -4848,15 +5367,20 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPD_declare_simd: case OMPD_requires: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } ErrorFound = Res.isInvalid() || ErrorFound; - // Check variables in the clauses if default(none) was specified. - if (DSAStack->getDefaultDSA() == DSA_none) { + // Check variables in the clauses if default(none) or + // default(firstprivate) was specified. + if (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate) { DSAAttrChecker DSAChecker(DSAStack, *this, nullptr); for (OMPClause *C : Clauses) { switch (C->getClauseKind()) { @@ -4876,6 +5400,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( break; continue; case OMPC_schedule: + case OMPC_detach: break; case OMPC_grainsize: case OMPC_num_tasks: @@ -4915,6 +5440,10 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -4924,11 +5453,19 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: continue; case OMPC_allocator: case OMPC_flush: + case OMPC_depobj: case OMPC_threadprivate: case OMPC_uniform: case OMPC_unknown: @@ -4939,6 +5476,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + default: llvm_unreachable("Unexpected clause"); } for (Stmt *CC : C->children()) { @@ -4946,14 +5484,15 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( DSAChecker.Visit(CC); } } - for (auto &P : DSAChecker.getVarsWithInheritedDSA()) + for (const auto &P : DSAChecker.getVarsWithInheritedDSA()) VarsWithInheritedDSA[P.getFirst()] = P.getSecond(); } for (const auto &P : VarsWithInheritedDSA) { if (P.getFirst()->isImplicit() || isa<OMPCapturedExprDecl>(P.getFirst())) continue; ErrorFound = true; - if (DSAStack->getDefaultDSA() == DSA_none) { + if (DSAStack->getDefaultDSA() == DSA_none || + DSAStack->getDefaultDSA() == DSA_firstprivate) { Diag(P.second->getExprLoc(), diag::err_omp_no_dsa_for_variable) << P.first << P.second->getSourceRange(); Diag(DSAStack->getDefaultDSALocation(), diag::note_omp_default_dsa_none); @@ -4973,12 +5512,6 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( if (ErrorFound) return StmtError(); - if (!(Res.getAs<OMPExecutableDirective>()->isStandaloneDirective())) { - Res.getAs<OMPExecutableDirective>() - ->getStructuredBlock() - ->setIsOMPStructuredBlock(true); - } - if (!CurContext->isDependentContext() && isOpenMPTargetExecutionDirective(Kind) && !(DSAStack->hasRequiresDeclWithClause<OMPUnifiedSharedMemoryClause>() || @@ -5166,7 +5699,8 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( E->containsUnexpandedParameterPack()) continue; (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind, - PVD->getOriginalType()); + PVD->getOriginalType(), + /*IsDeclareSimd=*/true); continue; } } @@ -5186,7 +5720,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) continue; (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind, - E->getType()); + E->getType(), /*IsDeclareSimd=*/true); continue; } Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) @@ -5264,9 +5798,170 @@ static void setPrototype(Sema &S, FunctionDecl *FD, FunctionDecl *FDWithProto, FD->setParams(Params); } +Sema::OMPDeclareVariantScope::OMPDeclareVariantScope(OMPTraitInfo &TI) + : TI(&TI), NameSuffix(TI.getMangledName()) {} + +FunctionDecl * +Sema::ActOnStartOfFunctionDefinitionInOpenMPDeclareVariantScope(Scope *S, + Declarator &D) { + IdentifierInfo *BaseII = D.getIdentifier(); + LookupResult Lookup(*this, DeclarationName(BaseII), D.getIdentifierLoc(), + LookupOrdinaryName); + LookupParsedName(Lookup, S, &D.getCXXScopeSpec()); + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType FType = TInfo->getType(); + + bool IsConstexpr = D.getDeclSpec().getConstexprSpecifier() == CSK_constexpr; + bool IsConsteval = D.getDeclSpec().getConstexprSpecifier() == CSK_consteval; + + FunctionDecl *BaseFD = nullptr; + for (auto *Candidate : Lookup) { + auto *UDecl = dyn_cast<FunctionDecl>(Candidate->getUnderlyingDecl()); + if (!UDecl) + continue; + + // Don't specialize constexpr/consteval functions with + // non-constexpr/consteval functions. + if (UDecl->isConstexpr() && !IsConstexpr) + continue; + if (UDecl->isConsteval() && !IsConsteval) + continue; + + QualType NewType = Context.mergeFunctionTypes( + FType, UDecl->getType(), /* OfBlockPointer */ false, + /* Unqualified */ false, /* AllowCXX */ true); + if (NewType.isNull()) + continue; + + // Found a base! + BaseFD = UDecl; + break; + } + if (!BaseFD) { + BaseFD = cast<FunctionDecl>(ActOnDeclarator(S, D)); + BaseFD->setImplicit(true); + } + + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + std::string MangledName; + MangledName += D.getIdentifier()->getName(); + MangledName += getOpenMPVariantManglingSeparatorStr(); + MangledName += DVScope.NameSuffix; + IdentifierInfo &VariantII = Context.Idents.get(MangledName); + + VariantII.setMangledOpenMPVariantName(true); + D.SetIdentifier(&VariantII, D.getBeginLoc()); + return BaseFD; +} + +void Sema::ActOnFinishedFunctionDefinitionInOpenMPDeclareVariantScope( + FunctionDecl *FD, FunctionDecl *BaseFD) { + // Do not mark function as is used to prevent its emission if this is the + // only place where it is used. + EnterExpressionEvaluationContext Unevaluated( + *this, Sema::ExpressionEvaluationContext::Unevaluated); + + Expr *VariantFuncRef = DeclRefExpr::Create( + Context, NestedNameSpecifierLoc(), SourceLocation(), FD, + /* RefersToEnclosingVariableOrCapture */ false, + /* NameLoc */ FD->getLocation(), FD->getType(), ExprValueKind::VK_RValue); + + OMPDeclareVariantScope &DVScope = OMPDeclareVariantScopes.back(); + auto *OMPDeclareVariantA = OMPDeclareVariantAttr::CreateImplicit( + Context, VariantFuncRef, DVScope.TI); + BaseFD->addAttr(OMPDeclareVariantA); +} + +ExprResult Sema::ActOnOpenMPCall(ExprResult Call, Scope *Scope, + SourceLocation LParenLoc, + MultiExprArg ArgExprs, + SourceLocation RParenLoc, Expr *ExecConfig) { + // The common case is a regular call we do not want to specialize at all. Try + // to make that case fast by bailing early. + CallExpr *CE = dyn_cast<CallExpr>(Call.get()); + if (!CE) + return Call; + + FunctionDecl *CalleeFnDecl = CE->getDirectCallee(); + if (!CalleeFnDecl) + return Call; + + if (!CalleeFnDecl->hasAttr<OMPDeclareVariantAttr>()) + return Call; + + ASTContext &Context = getASTContext(); + OMPContext OMPCtx(getLangOpts().OpenMPIsDevice, + Context.getTargetInfo().getTriple()); + + SmallVector<Expr *, 4> Exprs; + SmallVector<VariantMatchInfo, 4> VMIs; + while (CalleeFnDecl) { + for (OMPDeclareVariantAttr *A : + CalleeFnDecl->specific_attrs<OMPDeclareVariantAttr>()) { + Expr *VariantRef = A->getVariantFuncRef(); + + VariantMatchInfo VMI; + OMPTraitInfo &TI = A->getTraitInfo(); + TI.getAsVariantMatchInfo(Context, VMI); + if (!isVariantApplicableInContext(VMI, OMPCtx, /* DeviceSetOnly */ false)) + continue; + + VMIs.push_back(VMI); + Exprs.push_back(VariantRef); + } + + CalleeFnDecl = CalleeFnDecl->getPreviousDecl(); + } + + ExprResult NewCall; + do { + int BestIdx = getBestVariantMatchForContext(VMIs, OMPCtx); + if (BestIdx < 0) + return Call; + Expr *BestExpr = cast<DeclRefExpr>(Exprs[BestIdx]); + Decl *BestDecl = cast<DeclRefExpr>(BestExpr)->getDecl(); + + { + // Try to build a (member) call expression for the current best applicable + // variant expression. We allow this to fail in which case we continue + // with the next best variant expression. The fail case is part of the + // implementation defined behavior in the OpenMP standard when it talks + // about what differences in the function prototypes: "Any differences + // that the specific OpenMP context requires in the prototype of the + // variant from the base function prototype are implementation defined." + // This wording is there to allow the specialized variant to have a + // different type than the base function. This is intended and OK but if + // we cannot create a call the difference is not in the "implementation + // defined range" we allow. + Sema::TentativeAnalysisScope Trap(*this); + + if (auto *SpecializedMethod = dyn_cast<CXXMethodDecl>(BestDecl)) { + auto *MemberCall = dyn_cast<CXXMemberCallExpr>(CE); + BestExpr = MemberExpr::CreateImplicit( + Context, MemberCall->getImplicitObjectArgument(), + /* IsArrow */ false, SpecializedMethod, Context.BoundMemberTy, + MemberCall->getValueKind(), MemberCall->getObjectKind()); + } + NewCall = BuildCallExpr(Scope, BestExpr, LParenLoc, ArgExprs, RParenLoc, + ExecConfig); + if (NewCall.isUsable()) + break; + } + + VMIs.erase(VMIs.begin() + BestIdx); + Exprs.erase(Exprs.begin() + BestIdx); + } while (!VMIs.empty()); + + if (!NewCall.isUsable()) + return Call; + return PseudoObjectExpr::Create(Context, CE, {NewCall.get()}, 0); +} + Optional<std::pair<FunctionDecl *, Expr *>> Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, - Expr *VariantRef, SourceRange SR) { + Expr *VariantRef, OMPTraitInfo &TI, + SourceRange SR) { if (!DG || DG.get().isNull()) return None; @@ -5319,12 +6014,41 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return None; } + auto ShouldDelayChecks = [](Expr *&E, bool) { + return E && (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || + E->isInstantiationDependent()); + }; // Do not check templates, wait until instantiation. - if (VariantRef->isTypeDependent() || VariantRef->isValueDependent() || - VariantRef->containsUnexpandedParameterPack() || - VariantRef->isInstantiationDependent() || FD->isDependentContext()) + if (FD->isDependentContext() || ShouldDelayChecks(VariantRef, false) || + TI.anyScoreOrCondition(ShouldDelayChecks)) return std::make_pair(FD, VariantRef); + // Deal with non-constant score and user condition expressions. + auto HandleNonConstantScoresAndConditions = [this](Expr *&E, + bool IsScore) -> bool { + llvm::APSInt Result; + if (!E || E->isIntegerConstantExpr(Result, Context)) + return false; + + if (IsScore) { + // We warn on non-constant scores and pretend they were not present. + Diag(E->getExprLoc(), diag::warn_omp_declare_variant_score_not_constant) + << E; + E = nullptr; + } else { + // We could replace a non-constant user condition with "false" but we + // will soon need to handle these anyway for the dynamic version of + // OpenMP context selectors. + Diag(E->getExprLoc(), + diag::err_omp_declare_variant_user_condition_not_constant) + << E; + } + return true; + }; + if (TI.anyScoreOrCondition(HandleNonConstantScoresAndConditions)) + return None; + // Convert VariantRef expression to the type of the original function to // resolve possible conflicts. ExprResult VariantRefCast; @@ -5355,7 +6079,7 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, ImplicitConversionSequence ICS = TryImplicitConversion(VariantRef, FnPtrType.getUnqualifiedType(), /*SuppressUserConversions=*/false, - /*AllowExplicit=*/false, + AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false); @@ -5497,94 +6221,13 @@ Sema::checkOpenMPDeclareVariantFunction(Sema::DeclGroupPtrTy DG, return std::make_pair(FD, cast<Expr>(DRE)); } -void Sema::ActOnOpenMPDeclareVariantDirective( - FunctionDecl *FD, Expr *VariantRef, SourceRange SR, - ArrayRef<OMPCtxSelectorData> Data) { - if (Data.empty()) - return; - SmallVector<Expr *, 4> CtxScores; - SmallVector<unsigned, 4> CtxSets; - SmallVector<unsigned, 4> Ctxs; - SmallVector<StringRef, 4> ImplVendors, DeviceKinds; - bool IsError = false; - for (const OMPCtxSelectorData &D : Data) { - OpenMPContextSelectorSetKind CtxSet = D.CtxSet; - OpenMPContextSelectorKind Ctx = D.Ctx; - if (CtxSet == OMP_CTX_SET_unknown || Ctx == OMP_CTX_unknown) - return; - Expr *Score = nullptr; - if (D.Score.isUsable()) { - Score = D.Score.get(); - if (!Score->isTypeDependent() && !Score->isValueDependent() && - !Score->isInstantiationDependent() && - !Score->containsUnexpandedParameterPack()) { - Score = - PerformOpenMPImplicitIntegerConversion(Score->getExprLoc(), Score) - .get(); - if (Score) - Score = VerifyIntegerConstantExpression(Score).get(); - } - } else { - // OpenMP 5.0, 2.3.3 Matching and Scoring Context Selectors. - // The kind, arch, and isa selectors are given the values 2^l, 2^(l+1) and - // 2^(l+2), respectively, where l is the number of traits in the construct - // set. - // TODO: implement correct logic for isa and arch traits. - // TODO: take the construct context set into account when it is - // implemented. - int L = 0; // Currently set the number of traits in construct set to 0, - // since the construct trait set in not supported yet. - if (CtxSet == OMP_CTX_SET_device && Ctx == OMP_CTX_kind) - Score = ActOnIntegerConstant(SourceLocation(), std::pow(2, L)).get(); - else - Score = ActOnIntegerConstant(SourceLocation(), 0).get(); - } - switch (Ctx) { - case OMP_CTX_vendor: - assert(CtxSet == OMP_CTX_SET_implementation && - "Expected implementation context selector set."); - ImplVendors.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_kind: - assert(CtxSet == OMP_CTX_SET_device && - "Expected device context selector set."); - DeviceKinds.append(D.Names.begin(), D.Names.end()); - break; - case OMP_CTX_unknown: - llvm_unreachable("Unknown context selector kind."); - } - IsError = IsError || !Score; - CtxSets.push_back(CtxSet); - Ctxs.push_back(Ctx); - CtxScores.push_back(Score); - } - if (!IsError) { - auto *NewAttr = OMPDeclareVariantAttr::CreateImplicit( - Context, VariantRef, CtxScores.begin(), CtxScores.size(), - CtxSets.begin(), CtxSets.size(), Ctxs.begin(), Ctxs.size(), - ImplVendors.begin(), ImplVendors.size(), DeviceKinds.begin(), - DeviceKinds.size(), SR); - FD->addAttr(NewAttr); - } -} - -void Sema::markOpenMPDeclareVariantFuncsReferenced(SourceLocation Loc, - FunctionDecl *Func, - bool MightBeOdrUse) { - assert(LangOpts.OpenMP && "Expected OpenMP mode."); - - if (!Func->isDependentContext() && Func->hasAttrs()) { - for (OMPDeclareVariantAttr *A : - Func->specific_attrs<OMPDeclareVariantAttr>()) { - // TODO: add checks for active OpenMP context where possible. - Expr *VariantRef = A->getVariantFuncRef(); - auto *DRE = cast<DeclRefExpr>(VariantRef->IgnoreParenImpCasts()); - auto *F = cast<FunctionDecl>(DRE->getDecl()); - if (!F->isDefined() && F->isTemplateInstantiation()) - InstantiateFunctionDefinition(Loc, F->getFirstDecl()); - MarkFunctionReferenced(Loc, F, MightBeOdrUse); - } - } +void Sema::ActOnOpenMPDeclareVariantDirective(FunctionDecl *FD, + Expr *VariantRef, + OMPTraitInfo &TI, + SourceRange SR) { + auto *NewAttr = + OMPDeclareVariantAttr::CreateImplicit(Context, VariantRef, &TI, SR); + FD->addAttr(NewAttr); } StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, @@ -5605,6 +6248,7 @@ StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } @@ -6300,8 +6944,8 @@ bool OpenMPIterationSpaceChecker::checkAndSetInc(Expr *S) { static ExprResult tryBuildCapture(Sema &SemaRef, Expr *Capture, llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { - if (SemaRef.CurContext->isDependentContext()) - return ExprResult(Capture); + if (SemaRef.CurContext->isDependentContext() || Capture->containsErrors()) + return Capture; if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) return SemaRef.PerformImplicitConversion( Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, @@ -6315,221 +6959,344 @@ tryBuildCapture(Sema &SemaRef, Expr *Capture, return Res; } -/// Build the expression to calculate the number of iterations. -Expr *OpenMPIterationSpaceChecker::buildNumIterations( - Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, - llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { - ExprResult Diff; - QualType VarType = LCDecl->getType().getNonReferenceType(); - if (VarType->isIntegerType() || VarType->isPointerType() || - SemaRef.getLangOpts().CPlusPlus) { - Expr *LBVal = LB; - Expr *UBVal = UB; - // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : - // max(LB(MinVal), LB(MaxVal)) - if (InitDependOnLC) { - const LoopIterationSpace &IS = - ResultIterSpaces[ResultIterSpaces.size() - 1 - - InitDependOnLC.getValueOr( - CondDependOnLC.getValueOr(0))]; - if (!IS.MinValue || !IS.MaxValue) - return nullptr; - // OuterVar = Min - ExprResult MinValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); - if (!MinValue.isUsable()) - return nullptr; - - ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MinValue.get()); - if (!LBMinVal.isUsable()) - return nullptr; - // OuterVar = Min, LBVal - LBMinVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); - if (!LBMinVal.isUsable()) - return nullptr; - // (OuterVar = Min, LBVal) - LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); - if (!LBMinVal.isUsable()) - return nullptr; - - // OuterVar = Max - ExprResult MaxValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); - if (!MaxValue.isUsable()) - return nullptr; - - ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MaxValue.get()); - if (!LBMaxVal.isUsable()) - return nullptr; - // OuterVar = Max, LBVal - LBMaxVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); - if (!LBMaxVal.isUsable()) - return nullptr; - // (OuterVar = Max, LBVal) - LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); - if (!LBMaxVal.isUsable()) - return nullptr; - - Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); - Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); - if (!LBMin || !LBMax) - return nullptr; - // LB(MinVal) < LB(MaxVal) - ExprResult MinLessMaxRes = - SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); - if (!MinLessMaxRes.isUsable()) - return nullptr; - Expr *MinLessMax = - tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); - if (!MinLessMax) - return nullptr; - if (TestIsLessOp.getValue()) { - // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), - // LB(MaxVal)) - ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, - MinLessMax, LBMin, LBMax); - if (!MinLB.isUsable()) - return nullptr; - LBVal = MinLB.get(); - } else { - // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), - // LB(MaxVal)) - ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, - MinLessMax, LBMax, LBMin); - if (!MaxLB.isUsable()) - return nullptr; - LBVal = MaxLB.get(); - } +/// Calculate number of iterations, transforming to unsigned, if number of +/// iterations may be larger than the original type. +static Expr * +calculateNumIters(Sema &SemaRef, Scope *S, SourceLocation DefaultLoc, + Expr *Lower, Expr *Upper, Expr *Step, QualType LCTy, + bool TestIsStrictOp, bool RoundToStep, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) { + ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) + return nullptr; + llvm::APSInt LRes, URes, SRes; + bool IsLowerConst = Lower->isIntegerConstantExpr(LRes, SemaRef.Context); + bool IsStepConst = Step->isIntegerConstantExpr(SRes, SemaRef.Context); + bool NoNeedToConvert = IsLowerConst && !RoundToStep && + ((!TestIsStrictOp && LRes.isNonNegative()) || + (TestIsStrictOp && LRes.isStrictlyPositive())); + bool NeedToReorganize = false; + // Check if any subexpressions in Lower -Step [+ 1] lead to overflow. + if (!NoNeedToConvert && IsLowerConst && + (TestIsStrictOp || (RoundToStep && IsStepConst))) { + NoNeedToConvert = true; + if (RoundToStep) { + unsigned BW = LRes.getBitWidth() > SRes.getBitWidth() + ? LRes.getBitWidth() + : SRes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + SRes = SRes.extend(BW + 1); + SRes.setIsSigned(true); + LRes -= SRes; + NoNeedToConvert = LRes.trunc(BW).extend(BW + 1) == LRes; + LRes = LRes.trunc(BW); + } + if (TestIsStrictOp) { + unsigned BW = LRes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + ++LRes; + NoNeedToConvert = + NoNeedToConvert && LRes.trunc(BW).extend(BW + 1) == LRes; + // truncate to the original bitwidth. + LRes = LRes.trunc(BW); + } + NeedToReorganize = NoNeedToConvert; + } + bool IsUpperConst = Upper->isIntegerConstantExpr(URes, SemaRef.Context); + if (NoNeedToConvert && IsLowerConst && IsUpperConst && + (!RoundToStep || IsStepConst)) { + unsigned BW = LRes.getBitWidth() > URes.getBitWidth() ? LRes.getBitWidth() + : URes.getBitWidth(); + LRes = LRes.extend(BW + 1); + LRes.setIsSigned(true); + URes = URes.extend(BW + 1); + URes.setIsSigned(true); + URes -= LRes; + NoNeedToConvert = URes.trunc(BW).extend(BW + 1) == URes; + NeedToReorganize = NoNeedToConvert; + } + // If the boundaries are not constant or (Lower - Step [+ 1]) is not constant + // or less than zero (Upper - (Lower - Step [+ 1]) may overflow) - promote to + // unsigned. + if ((!NoNeedToConvert || (LRes.isNegative() && !IsUpperConst)) && + !LCTy->isDependentType() && LCTy->isIntegerType()) { + QualType LowerTy = Lower->getType(); + QualType UpperTy = Upper->getType(); + uint64_t LowerSize = SemaRef.Context.getTypeSize(LowerTy); + uint64_t UpperSize = SemaRef.Context.getTypeSize(UpperTy); + if ((LowerSize <= UpperSize && UpperTy->hasSignedIntegerRepresentation()) || + (LowerSize > UpperSize && LowerTy->hasSignedIntegerRepresentation())) { + QualType CastType = SemaRef.Context.getIntTypeForBitwidth( + LowerSize > UpperSize ? LowerSize : UpperSize, /*Signed=*/0); + Upper = + SemaRef + .PerformImplicitConversion( + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(), + CastType, Sema::AA_Converting) + .get(); + Lower = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(); + NewStep = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, NewStep.get()); } - // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : - // min(UB(MinVal), UB(MaxVal)) - if (CondDependOnLC) { - const LoopIterationSpace &IS = - ResultIterSpaces[ResultIterSpaces.size() - 1 - - InitDependOnLC.getValueOr( - CondDependOnLC.getValueOr(0))]; - if (!IS.MinValue || !IS.MaxValue) - return nullptr; - // OuterVar = Min - ExprResult MinValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); - if (!MinValue.isUsable()) - return nullptr; - - ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MinValue.get()); - if (!UBMinVal.isUsable()) - return nullptr; - // OuterVar = Min, UBVal - UBMinVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); - if (!UBMinVal.isUsable()) - return nullptr; - // (OuterVar = Min, UBVal) - UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); - if (!UBMinVal.isUsable()) - return nullptr; + } + if (!Lower || !Upper || NewStep.isInvalid()) + return nullptr; - // OuterVar = Max - ExprResult MaxValue = - SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); - if (!MaxValue.isUsable()) + ExprResult Diff; + // If need to reorganize, then calculate the form as Upper - (Lower - Step [+ + // 1]). + if (NeedToReorganize) { + Diff = Lower; + + if (RoundToStep) { + // Lower - Step + Diff = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) return nullptr; + } - ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, - IS.CounterVar, MaxValue.get()); - if (!UBMaxVal.isUsable()) - return nullptr; - // OuterVar = Max, UBVal - UBMaxVal = - SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); - if (!UBMaxVal.isUsable()) - return nullptr; - // (OuterVar = Max, UBVal) - UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); - if (!UBMaxVal.isUsable()) - return nullptr; + // Lower - Step [+ 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Add, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return nullptr; - Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); - Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); - if (!UBMin || !UBMax) - return nullptr; - // UB(MinVal) > UB(MaxVal) - ExprResult MinGreaterMaxRes = - SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); - if (!MinGreaterMaxRes.isUsable()) - return nullptr; - Expr *MinGreaterMax = - tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); - if (!MinGreaterMax) - return nullptr; - if (TestIsLessOp.getValue()) { - // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), - // UB(MaxVal)) - ExprResult MaxUB = SemaRef.ActOnConditionalOp( - DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); - if (!MaxUB.isUsable()) - return nullptr; - UBVal = MaxUB.get(); - } else { - // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), - // UB(MaxVal)) - ExprResult MinUB = SemaRef.ActOnConditionalOp( - DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); - if (!MinUB.isUsable()) - return nullptr; - UBVal = MinUB.get(); - } - } - // Upper - Lower - Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; - Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; - Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); - Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); - if (!Upper || !Lower) + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); + if (!Diff.isUsable()) return nullptr; + // Upper - (Lower - Step [+ 1]). + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); + if (!Diff.isUsable()) + return nullptr; + } else { Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); - if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) { + if (!Diff.isUsable() && LCTy->getAsCXXRecordDecl()) { // BuildBinOp already emitted error, this one is to point user to upper // and lower bound, and to tell what is passed to 'operator-'. SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx) << Upper->getSourceRange() << Lower->getSourceRange(); return nullptr; } + + if (!Diff.isUsable()) + return nullptr; + + // Upper - Lower [- 1] + if (TestIsStrictOp) + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, Diff.get(), + SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + if (!Diff.isUsable()) + return nullptr; + + if (RoundToStep) { + // Upper - Lower [- 1] + Step + Diff = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); + if (!Diff.isUsable()) + return nullptr; + } } + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return nullptr; - // Upper - Lower [- 1] - if (TestIsStrictOp) - Diff = SemaRef.BuildBinOp( - S, DefaultLoc, BO_Sub, Diff.get(), - SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + // (Upper - Lower [- 1] + Step) / Step or (Upper - Lower) / Step + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; - // Upper - Lower [- 1] + Step - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); - if (!NewStep.isUsable()) - return nullptr; - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); - if (!Diff.isUsable()) + return Diff.get(); +} + +/// Build the expression to calculate the number of iterations. +Expr *OpenMPIterationSpaceChecker::buildNumIterations( + Scope *S, ArrayRef<LoopIterationSpace> ResultIterSpaces, bool LimitedType, + llvm::MapVector<const Expr *, DeclRefExpr *> &Captures) const { + QualType VarType = LCDecl->getType().getNonReferenceType(); + if (!VarType->isIntegerType() && !VarType->isPointerType() && + !SemaRef.getLangOpts().CPlusPlus) return nullptr; + Expr *LBVal = LB; + Expr *UBVal = UB; + // LB = TestIsLessOp.getValue() ? min(LB(MinVal), LB(MaxVal)) : + // max(LB(MinVal), LB(MaxVal)) + if (InitDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) + ExprResult LBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!LBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, LBVal + LBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMinVal.get(), LBVal); + if (!LBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, LBVal) + LBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMinVal.get()); + if (!LBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult LBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, LBVal + LBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, LBMaxVal.get(), LBVal); + if (!LBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, LBVal) + LBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, LBMaxVal.get()); + if (!LBMaxVal.isUsable()) + return nullptr; + + Expr *LBMin = tryBuildCapture(SemaRef, LBMinVal.get(), Captures).get(); + Expr *LBMax = tryBuildCapture(SemaRef, LBMaxVal.get(), Captures).get(); + if (!LBMin || !LBMax) + return nullptr; + // LB(MinVal) < LB(MaxVal) + ExprResult MinLessMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_LT, LBMin, LBMax); + if (!MinLessMaxRes.isUsable()) + return nullptr; + Expr *MinLessMax = + tryBuildCapture(SemaRef, MinLessMaxRes.get(), Captures).get(); + if (!MinLessMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // LB(MinVal) < LB(MaxVal) ? LB(MinVal) : LB(MaxVal) - min(LB(MinVal), + // LB(MaxVal)) + ExprResult MinLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMin, LBMax); + if (!MinLB.isUsable()) + return nullptr; + LBVal = MinLB.get(); + } else { + // LB(MinVal) < LB(MaxVal) ? LB(MaxVal) : LB(MinVal) - max(LB(MinVal), + // LB(MaxVal)) + ExprResult MaxLB = SemaRef.ActOnConditionalOp(DefaultLoc, DefaultLoc, + MinLessMax, LBMax, LBMin); + if (!MaxLB.isUsable()) + return nullptr; + LBVal = MaxLB.get(); + } + } + // UB = TestIsLessOp.getValue() ? max(UB(MinVal), UB(MaxVal)) : + // min(UB(MinVal), UB(MaxVal)) + if (CondDependOnLC) { + const LoopIterationSpace &IS = + ResultIterSpaces[ResultIterSpaces.size() - 1 - + InitDependOnLC.getValueOr( + CondDependOnLC.getValueOr(0))]; + if (!IS.MinValue || !IS.MaxValue) + return nullptr; + // OuterVar = Min + ExprResult MinValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MinValue); + if (!MinValue.isUsable()) + return nullptr; + + ExprResult UBMinVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MinValue.get()); + if (!UBMinVal.isUsable()) + return nullptr; + // OuterVar = Min, UBVal + UBMinVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMinVal.get(), UBVal); + if (!UBMinVal.isUsable()) + return nullptr; + // (OuterVar = Min, UBVal) + UBMinVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMinVal.get()); + if (!UBMinVal.isUsable()) + return nullptr; + + // OuterVar = Max + ExprResult MaxValue = + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, IS.MaxValue); + if (!MaxValue.isUsable()) + return nullptr; + + ExprResult UBMaxVal = SemaRef.BuildBinOp(S, DefaultLoc, BO_Assign, + IS.CounterVar, MaxValue.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + // OuterVar = Max, UBVal + UBMaxVal = + SemaRef.BuildBinOp(S, DefaultLoc, BO_Comma, UBMaxVal.get(), UBVal); + if (!UBMaxVal.isUsable()) + return nullptr; + // (OuterVar = Max, UBVal) + UBMaxVal = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, UBMaxVal.get()); + if (!UBMaxVal.isUsable()) + return nullptr; + + Expr *UBMin = tryBuildCapture(SemaRef, UBMinVal.get(), Captures).get(); + Expr *UBMax = tryBuildCapture(SemaRef, UBMaxVal.get(), Captures).get(); + if (!UBMin || !UBMax) + return nullptr; + // UB(MinVal) > UB(MaxVal) + ExprResult MinGreaterMaxRes = + SemaRef.BuildBinOp(S, DefaultLoc, BO_GT, UBMin, UBMax); + if (!MinGreaterMaxRes.isUsable()) + return nullptr; + Expr *MinGreaterMax = + tryBuildCapture(SemaRef, MinGreaterMaxRes.get(), Captures).get(); + if (!MinGreaterMax) + return nullptr; + if (TestIsLessOp.getValue()) { + // UB(MinVal) > UB(MaxVal) ? UB(MinVal) : UB(MaxVal) - max(UB(MinVal), + // UB(MaxVal)) + ExprResult MaxUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMin, UBMax); + if (!MaxUB.isUsable()) + return nullptr; + UBVal = MaxUB.get(); + } else { + // UB(MinVal) > UB(MaxVal) ? UB(MaxVal) : UB(MinVal) - min(UB(MinVal), + // UB(MaxVal)) + ExprResult MinUB = SemaRef.ActOnConditionalOp( + DefaultLoc, DefaultLoc, MinGreaterMax, UBMax, UBMin); + if (!MinUB.isUsable()) + return nullptr; + UBVal = MinUB.get(); + } + } + Expr *UBExpr = TestIsLessOp.getValue() ? UBVal : LBVal; + Expr *LBExpr = TestIsLessOp.getValue() ? LBVal : UBVal; + Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); + Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); + if (!Upper || !Lower) return nullptr; - // (Upper - Lower [- 1] + Step) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + ExprResult Diff = + calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, + TestIsStrictOp, /*RoundToStep=*/true, Captures); if (!Diff.isUsable()) return nullptr; @@ -6603,55 +7370,37 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( MaxExpr = Upper; // Build minimum/maximum value based on number of iterations. - ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); + ExprResult Diff = + calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, Step, VarType, + TestIsStrictOp, /*RoundToStep=*/false, Captures); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Upper - Lower [- 1] - if (TestIsStrictOp) - Diff = SemaRef.BuildBinOp( - S, DefaultLoc, BO_Sub, Diff.get(), - SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); + // ((Upper - Lower [- 1]) / Step) * Step + // Parentheses (for dumping/debugging purposes only). + Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Upper - Lower [- 1] + Step ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); if (!NewStep.isUsable()) return std::make_pair(nullptr, nullptr); - - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - - // (Upper - Lower [- 1]) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // ((Upper - Lower [- 1]) / Step) * Step // Parentheses (for dumping/debugging purposes only). Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Mul, Diff.get(), NewStep.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - - // Convert to the original type or ptrdiff_t, if original type is pointer. - if (!VarType->isAnyPointerType() && - !SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) { - Diff = SemaRef.PerformImplicitConversion( - Diff.get(), VarType, Sema::AA_Converting, /*AllowExplicit=*/true); - } else if (VarType->isAnyPointerType() && - !SemaRef.Context.hasSameType( - Diff.get()->getType(), - SemaRef.Context.getUnsignedPointerDiffType())) { + // Convert to the ptrdiff_t, if original type is pointer. + if (VarType->isAnyPointerType() && + !SemaRef.Context.hasSameType( + Diff.get()->getType(), + SemaRef.Context.getUnsignedPointerDiffType())) { Diff = SemaRef.PerformImplicitConversion( Diff.get(), SemaRef.Context.getUnsignedPointerDiffType(), Sema::AA_Converting, /*AllowExplicit=*/true); @@ -6659,33 +7408,43 @@ std::pair<Expr *, Expr *> OpenMPIterationSpaceChecker::buildMinMaxValues( if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - if (TestIsLessOp.getValue()) { // MinExpr = Lower; // MaxExpr = Lower + (((Upper - Lower [- 1]) / Step) * Step) - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Lower, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Add, + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Lower).get(), + Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - MaxExpr = Diff.get(); } else { // MaxExpr = Upper; // MinExpr = Upper - (((Upper - Lower [- 1]) / Step) * Step) - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Diff.get()); - if (!Diff.isUsable()) - return std::make_pair(nullptr, nullptr); - Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue*/ false); + Diff = SemaRef.BuildBinOp( + S, DefaultLoc, BO_Sub, + SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Upper).get(), + Diff.get()); if (!Diff.isUsable()) return std::make_pair(nullptr, nullptr); - MinExpr = Diff.get(); } + // Convert to the original type. + if (SemaRef.Context.hasSameType(Diff.get()->getType(), VarType)) + Diff = SemaRef.PerformImplicitConversion(Diff.get(), VarType, + Sema::AA_Converting, + /*AllowExplicit=*/true); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + Diff = SemaRef.ActOnFinishFullExpr(Diff.get(), /*DiscardedValue=*/false); + if (!Diff.isUsable()) + return std::make_pair(nullptr, nullptr); + + if (TestIsLessOp.getValue()) + MaxExpr = Diff.get(); + else + MinExpr = Diff.get(); + return std::make_pair(MinExpr, MaxExpr); } @@ -6791,44 +7550,23 @@ Expr *OpenMPIterationSpaceChecker::buildOrderedLoopData( if (!Cnt) return nullptr; } - ExprResult Diff; QualType VarType = LCDecl->getType().getNonReferenceType(); - if (VarType->isIntegerType() || VarType->isPointerType() || - SemaRef.getLangOpts().CPlusPlus) { - // Upper - Lower - Expr *Upper = TestIsLessOp.getValue() - ? Cnt - : tryBuildCapture(SemaRef, UB, Captures).get(); - Expr *Lower = TestIsLessOp.getValue() - ? tryBuildCapture(SemaRef, LB, Captures).get() - : Cnt; - if (!Upper || !Lower) - return nullptr; - - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Sub, Upper, Lower); - - if (!Diff.isUsable() && VarType->getAsCXXRecordDecl()) { - // BuildBinOp already emitted error, this one is to point user to upper - // and lower bound, and to tell what is passed to 'operator-'. - SemaRef.Diag(Upper->getBeginLoc(), diag::err_omp_loop_diff_cxx) - << Upper->getSourceRange() << Lower->getSourceRange(); - return nullptr; - } - } - - if (!Diff.isUsable()) + if (!VarType->isIntegerType() && !VarType->isPointerType() && + !SemaRef.getLangOpts().CPlusPlus) return nullptr; - - // Parentheses (for dumping/debugging purposes only). - Diff = SemaRef.ActOnParenExpr(DefaultLoc, DefaultLoc, Diff.get()); - if (!Diff.isUsable()) + // Upper - Lower + Expr *Upper = TestIsLessOp.getValue() + ? Cnt + : tryBuildCapture(SemaRef, LB, Captures).get(); + Expr *Lower = TestIsLessOp.getValue() + ? tryBuildCapture(SemaRef, LB, Captures).get() + : Cnt; + if (!Upper || !Lower) return nullptr; - ExprResult NewStep = tryBuildCapture(SemaRef, Step, Captures); - if (!NewStep.isUsable()) - return nullptr; - // (Upper - Lower) / Step - Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); + ExprResult Diff = calculateNumIters(SemaRef, S, DefaultLoc, Lower, Upper, + Step, VarType, /*TestIsStrictOp=*/false, + /*RoundToStep=*/false, Captures); if (!Diff.isUsable()) return nullptr; @@ -8088,8 +8826,9 @@ Sema::ActOnOpenMPForDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, } setFunctionHasBranchProtectedScope(); - return OMPForDirective::Create(Context, StartLoc, EndLoc, NestedLoopCount, - Clauses, AStmt, B, DSAStack->isCancelRegion()); + return OMPForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPForSimdDirective( @@ -8166,6 +8905,7 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPSectionsDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } @@ -8326,9 +9066,9 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( } setFunctionHasBranchProtectedScope(); - return OMPParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + return OMPParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelForSimdDirective( @@ -8392,8 +9132,9 @@ Sema::ActOnOpenMPParallelMasterDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); - return OMPParallelMasterDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPParallelMasterDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef()); } StmtResult @@ -8432,7 +9173,31 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); return OMPParallelSectionsDirective::Create( - Context, StartLoc, EndLoc, Clauses, AStmt, DSAStack->isCancelRegion()); + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); +} + +/// detach and mergeable clauses are mutially exclusive, check for it. +static bool checkDetachMergeableClauses(Sema &S, + ArrayRef<OMPClause *> Clauses) { + const OMPClause *PrevClause = nullptr; + bool ErrorFound = false; + for (const OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_detach || + C->getClauseKind() == OMPC_mergeable) { + if (!PrevClause) { + PrevClause = C; + } else if (PrevClause->getClauseKind() != C->getClauseKind()) { + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) + << getOpenMPClauseName(C->getClauseKind()) + << getOpenMPClauseName(PrevClause->getClauseKind()); + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) + << getOpenMPClauseName(PrevClause->getClauseKind()); + ErrorFound = true; + } + } + } + return ErrorFound; } StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, @@ -8441,6 +9206,12 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); + // OpenMP 5.0, 2.10.1 task Construct + // If a detach clause appears on the directive, then a mergeable clause cannot + // appear on the same directive. + if (checkDetachMergeableClauses(*this, Clauses)) + return StmtError(); + auto *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the @@ -8489,10 +9260,94 @@ StmtResult Sema::ActOnOpenMPTaskgroupDirective(ArrayRef<OMPClause *> Clauses, StmtResult Sema::ActOnOpenMPFlushDirective(ArrayRef<OMPClause *> Clauses, SourceLocation StartLoc, SourceLocation EndLoc) { - assert(Clauses.size() <= 1 && "Extra clauses in flush directive"); + OMPFlushClause *FC = nullptr; + OMPClause *OrderClause = nullptr; + for (OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_flush) + FC = cast<OMPFlushClause>(C); + else + OrderClause = C; + } + OpenMPClauseKind MemOrderKind = OMPC_unknown; + SourceLocation MemOrderLoc; + for (const OMPClause *C : Clauses) { + if (C->getClauseKind() == OMPC_acq_rel || + C->getClauseKind() == OMPC_acquire || + C->getClauseKind() == OMPC_release) { + if (MemOrderKind != OMPC_unknown) { + Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses) + << getOpenMPDirectiveName(OMPD_flush) << 1 + << SourceRange(C->getBeginLoc(), C->getEndLoc()); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); + } else { + MemOrderKind = C->getClauseKind(); + MemOrderLoc = C->getBeginLoc(); + } + } + } + if (FC && OrderClause) { + Diag(FC->getLParenLoc(), diag::err_omp_flush_order_clause_and_list) + << getOpenMPClauseName(OrderClause->getClauseKind()); + Diag(OrderClause->getBeginLoc(), diag::note_omp_flush_order_clause_here) + << getOpenMPClauseName(OrderClause->getClauseKind()); + return StmtError(); + } return OMPFlushDirective::Create(Context, StartLoc, EndLoc, Clauses); } +StmtResult Sema::ActOnOpenMPDepobjDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (Clauses.empty()) { + Diag(StartLoc, diag::err_omp_depobj_expected); + return StmtError(); + } else if (Clauses[0]->getClauseKind() != OMPC_depobj) { + Diag(Clauses[0]->getBeginLoc(), diag::err_omp_depobj_expected); + return StmtError(); + } + // Only depobj expression and another single clause is allowed. + if (Clauses.size() > 2) { + Diag(Clauses[2]->getBeginLoc(), + diag::err_omp_depobj_single_clause_expected); + return StmtError(); + } else if (Clauses.size() < 1) { + Diag(Clauses[0]->getEndLoc(), diag::err_omp_depobj_single_clause_expected); + return StmtError(); + } + return OMPDepobjDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + +StmtResult Sema::ActOnOpenMPScanDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // Check that exactly one clause is specified. + if (Clauses.size() != 1) { + Diag(Clauses.empty() ? EndLoc : Clauses[1]->getBeginLoc(), + diag::err_omp_scan_single_clause_expected); + return StmtError(); + } + // Check that scan directive is used in the scopeof the OpenMP loop body. + if (Scope *S = DSAStack->getCurScope()) { + Scope *ParentS = S->getParent(); + if (!ParentS || ParentS->getParent() != ParentS->getBreakParent() || + !ParentS->getBreakParent()->isOpenMPLoopScope()) + return StmtError(Diag(StartLoc, diag::err_omp_orphaned_device_directive) + << getOpenMPDirectiveName(OMPD_scan) << 5); + } + // Check that only one instance of scan directives is used in the same outer + // region. + if (DSAStack->doesParentHasScanDirective()) { + Diag(StartLoc, diag::err_omp_several_directives_in_region) << "scan"; + Diag(DSAStack->getParentScanDirectiveLoc(), + diag::note_omp_previous_directive) + << "scan"; + return StmtError(); + } + DSAStack->setParentHasScanDirective(StartLoc); + return OMPScanDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -8555,13 +9410,29 @@ StmtResult Sema::ActOnOpenMPOrderedDirective(ArrayRef<OMPClause *> Clauses, SourceLocation ErrLoc = TC ? TC->getBeginLoc() : StartLoc; Diag(ErrLoc, diag::err_omp_ordered_directive_with_param) << (TC != nullptr); - Diag(Param->getBeginLoc(), diag::note_omp_ordered_param); + Diag(Param->getBeginLoc(), diag::note_omp_ordered_param) << 1; ErrorFound = true; } } if ((!AStmt && !DependFound) || ErrorFound) return StmtError(); + // OpenMP 5.0, 2.17.9, ordered Construct, Restrictions. + // During execution of an iteration of a worksharing-loop or a loop nest + // within a worksharing-loop, simd, or worksharing-loop SIMD region, a thread + // must not execute more than one ordered region corresponding to an ordered + // construct without a depend clause. + if (!DependFound) { + if (DSAStack->doesParentHasOrderedDirective()) { + Diag(StartLoc, diag::err_omp_several_directives_in_region) << "ordered"; + Diag(DSAStack->getParentOrderedDirectiveLoc(), + diag::note_omp_previous_directive) + << "ordered"; + return StmtError(); + } + DSAStack->setParentHasOrderedDirective(StartLoc); + } + if (AStmt) { assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); @@ -8817,6 +9688,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { + // Register location of the first atomic directive. + DSAStack->addAtomicDirectiveLoc(StartLoc); if (!AStmt) return StmtError(); @@ -8828,6 +9701,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, // longjmp() and throw() must not violate the entry/exit criteria. OpenMPClauseKind AtomicKind = OMPC_unknown; SourceLocation AtomicKindLoc; + OpenMPClauseKind MemOrderKind = OMPC_unknown; + SourceLocation MemOrderLoc; for (const OMPClause *C : Clauses) { if (C->getClauseKind() == OMPC_read || C->getClauseKind() == OMPC_write || C->getClauseKind() == OMPC_update || @@ -8835,13 +9710,51 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, if (AtomicKind != OMPC_unknown) { Diag(C->getBeginLoc(), diag::err_omp_atomic_several_clauses) << SourceRange(C->getBeginLoc(), C->getEndLoc()); - Diag(AtomicKindLoc, diag::note_omp_atomic_previous_clause) + Diag(AtomicKindLoc, diag::note_omp_previous_mem_order_clause) << getOpenMPClauseName(AtomicKind); } else { AtomicKind = C->getClauseKind(); AtomicKindLoc = C->getBeginLoc(); } } + if (C->getClauseKind() == OMPC_seq_cst || + C->getClauseKind() == OMPC_acq_rel || + C->getClauseKind() == OMPC_acquire || + C->getClauseKind() == OMPC_release || + C->getClauseKind() == OMPC_relaxed) { + if (MemOrderKind != OMPC_unknown) { + Diag(C->getBeginLoc(), diag::err_omp_several_mem_order_clauses) + << getOpenMPDirectiveName(OMPD_atomic) << 0 + << SourceRange(C->getBeginLoc(), C->getEndLoc()); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); + } else { + MemOrderKind = C->getClauseKind(); + MemOrderLoc = C->getBeginLoc(); + } + } + } + // OpenMP 5.0, 2.17.7 atomic Construct, Restrictions + // If atomic-clause is read then memory-order-clause must not be acq_rel or + // release. + // If atomic-clause is write then memory-order-clause must not be acq_rel or + // acquire. + // If atomic-clause is update or not present then memory-order-clause must not + // be acq_rel or acquire. + if ((AtomicKind == OMPC_read && + (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_release)) || + ((AtomicKind == OMPC_write || AtomicKind == OMPC_update || + AtomicKind == OMPC_unknown) && + (MemOrderKind == OMPC_acq_rel || MemOrderKind == OMPC_acquire))) { + SourceLocation Loc = AtomicKindLoc; + if (AtomicKind == OMPC_unknown) + Loc = StartLoc; + Diag(Loc, diag::err_omp_atomic_incompatible_mem_order_clause) + << getOpenMPClauseName(AtomicKind) + << (AtomicKind == OMPC_unknown ? 1 : 0) + << getOpenMPClauseName(MemOrderKind); + Diag(MemOrderLoc, diag::note_omp_previous_mem_order_clause) + << getOpenMPClauseName(MemOrderKind); } Stmt *Body = CS->getCapturedStmt(); @@ -9338,8 +10251,9 @@ Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses, setFunctionHasBranchProtectedScope(); - return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, - AStmt); + return OMPTargetParallelDirective::Create( + Context, StartLoc, EndLoc, Clauses, AStmt, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetParallelForDirective( @@ -9391,9 +10305,9 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( } setFunctionHasBranchProtectedScope(); - return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, - B, DSAStack->isCancelRegion()); + return OMPTargetParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } /// Check for existence of a map clause in the list of clauses. @@ -9418,12 +10332,18 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); - // OpenMP [2.10.1, Restrictions, p. 97] - // At least one map clause must appear on the directive. - if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr)) { + // OpenMP [2.12.2, target data Construct, Restrictions] + // At least one map, use_device_addr or use_device_ptr clause must appear on + // the directive. + if (!hasClauses(Clauses, OMPC_map, OMPC_use_device_ptr) && + (LangOpts.OpenMP < 50 || !hasClauses(Clauses, OMPC_use_device_addr))) { + StringRef Expected; + if (LangOpts.OpenMP < 50) + Expected = "'map' or 'use_device_ptr'"; + else + Expected = "'map', 'use_device_ptr', or 'use_device_addr'"; Diag(StartLoc, diag::err_omp_no_clause_for_directive) - << "'map' or 'use_device_ptr'" - << getOpenMPDirectiveName(OMPD_target_data); + << Expected << getOpenMPDirectiveName(OMPD_target_data); return StmtError(); } @@ -9604,12 +10524,10 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, if (!PrevClause) PrevClause = C; else if (PrevClause->getClauseKind() != C->getClauseKind()) { - S.Diag(C->getBeginLoc(), - diag::err_omp_grainsize_num_tasks_mutually_exclusive) + S.Diag(C->getBeginLoc(), diag::err_omp_clauses_mutually_exclusive) << getOpenMPClauseName(C->getClauseKind()) << getOpenMPClauseName(PrevClause->getClauseKind()); - S.Diag(PrevClause->getBeginLoc(), - diag::note_omp_previous_grainsize_num_tasks) + S.Diag(PrevClause->getBeginLoc(), diag::note_omp_previous_clause) << getOpenMPClauseName(PrevClause->getClauseKind()); ErrorFound = true; } @@ -9678,7 +10596,8 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPTaskLoopDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( @@ -9763,7 +10682,8 @@ StmtResult Sema::ActOnOpenMPMasterTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPMasterTaskLoopDirective::Create(Context, StartLoc, EndLoc, - NestedLoopCount, Clauses, AStmt, B); + NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPMasterTaskLoopSimdDirective( @@ -9867,7 +10787,8 @@ StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopDirective( setFunctionHasBranchProtectedScope(); return OMPParallelMasterTaskLoopDirective::Create( - Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, + DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPParallelMasterTaskLoopSimdDirective( @@ -10004,7 +10925,7 @@ StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( setFunctionHasBranchProtectedScope(); return OMPDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( @@ -10301,7 +11222,6 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( CS->getCapturedDecl()->setNothrow(); } - OMPLoopDirective::HelperExprs B; // In presence of clause 'collapse' with number of loops, it will // define the nested loops number. @@ -10446,7 +11366,7 @@ StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( return OMPTeamsDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, @@ -10575,7 +11495,7 @@ StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( setFunctionHasBranchProtectedScope(); return OMPTargetTeamsDistributeParallelForDirective::Create( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B, - DSAStack->isCancelRegion()); + DSAStack->getTaskgroupReductionRef(), DSAStack->isCancelRegion()); } StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForSimdDirective( @@ -10721,9 +11641,6 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_ordered: Res = ActOnOpenMPOrderedClause(StartLoc, EndLoc, LParenLoc, Expr); break; - case OMPC_device: - Res = ActOnOpenMPDeviceClause(Expr, StartLoc, LParenLoc, EndLoc); - break; case OMPC_num_teams: Res = ActOnOpenMPNumTeamsClause(Expr, StartLoc, LParenLoc, EndLoc); break; @@ -10742,6 +11659,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_hint: Res = ActOnOpenMPHintClause(Expr, StartLoc, LParenLoc, EndLoc); break; + case OMPC_depobj: + Res = ActOnOpenMPDepobjClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_detach: + Res = ActOnOpenMPDetachClause(Expr, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_device: case OMPC_if: case OMPC_default: case OMPC_proc_bind: @@ -10768,6 +11692,10 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -10780,6 +11708,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -10789,6 +11718,13 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -10918,10 +11854,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -10939,6 +11879,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with if-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -10988,10 +11929,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_teams: @@ -11013,6 +11958,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_threads-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11063,10 +12009,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11085,6 +12035,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11135,10 +12086,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11157,6 +12112,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with thread_limit-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11208,10 +12164,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11229,6 +12189,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11280,10 +12241,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11301,6 +12266,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with schedule clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11351,10 +12317,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11373,6 +12343,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with num_teams-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11425,10 +12396,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_taskwait: case OMPD_cancellation_point: case OMPD_flush: + case OMPD_depobj: + case OMPD_scan: case OMPD_declare_reduction: case OMPD_declare_mapper: case OMPD_declare_simd: case OMPD_declare_variant: + case OMPD_begin_declare_variant: + case OMPD_end_declare_variant: case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_simd: @@ -11447,6 +12422,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPD_requires: llvm_unreachable("Unexpected OpenMP directive with grainsize-clause"); case OMPD_unknown: + default: llvm_unreachable("Unknown OpenMP directive"); } break; @@ -11474,11 +12450,16 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_threads: case OMPC_simd: @@ -11491,6 +12472,7 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -11500,6 +12482,14 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Unexpected OpenMP clause."); } return CaptureRegion; @@ -11747,8 +12737,7 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, return true; // Build the predefined allocator expressions. bool ErrorFound = false; - for (int I = OMPAllocateDeclAttr::OMPDefaultMemAlloc; - I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); StringRef Allocator = OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); @@ -11775,7 +12764,8 @@ static bool findOMPAllocatorHandleT(Sema &S, SourceLocation Loc, Stack->setAllocator(AllocatorKind, Res.get()); } if (ErrorFound) { - S.Diag(Loc, diag::err_implied_omp_allocator_handle_t_not_found); + S.Diag(Loc, diag::err_omp_implied_type_not_found) + << "omp_allocator_handle_t"; return false; } OMPAllocatorHandleT.addConst(); @@ -11852,9 +12842,8 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( OMPClause *Res = nullptr; switch (Kind) { case OMPC_default: - Res = - ActOnOpenMPDefaultClause(static_cast<OpenMPDefaultClauseKind>(Argument), - ArgumentLoc, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPDefaultClause(static_cast<DefaultKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_proc_bind: Res = ActOnOpenMPProcBindClause(static_cast<ProcBindKind>(Argument), @@ -11865,6 +12854,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( static_cast<OpenMPAtomicDefaultMemOrderClauseKind>(Argument), ArgumentLoc, StartLoc, LParenLoc, EndLoc); break; + case OMPC_order: + Res = ActOnOpenMPOrderClause(static_cast<OpenMPOrderClauseKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_update: + Res = ActOnOpenMPUpdateClause(static_cast<OpenMPDependClauseKind>(Argument), + ArgumentLoc, StartLoc, LParenLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -11891,11 +12888,15 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: - case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: case OMPC_device: case OMPC_threads: @@ -11915,6 +12916,7 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -11923,6 +12925,13 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -11946,34 +12955,36 @@ getListOfPossibleValues(OpenMPClauseKind K, unsigned First, unsigned Last, else if (I + Skipped + 1 != Last) Out << ", "; } - return Out.str(); + return std::string(Out.str()); } -OMPClause *Sema::ActOnOpenMPDefaultClause(OpenMPDefaultClauseKind Kind, +OMPClause *Sema::ActOnOpenMPDefaultClause(DefaultKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - if (Kind == OMPC_DEFAULT_unknown) { - static_assert(OMPC_DEFAULT_unknown > 0, - "OMPC_DEFAULT_unknown not greater than 0"); + if (Kind == OMP_DEFAULT_unknown) { Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) << getListOfPossibleValues(OMPC_default, /*First=*/0, - /*Last=*/OMPC_DEFAULT_unknown) + /*Last=*/unsigned(OMP_DEFAULT_unknown)) << getOpenMPClauseName(OMPC_default); return nullptr; } + switch (Kind) { - case OMPC_DEFAULT_none: + case OMP_DEFAULT_none: DSAStack->setDefaultDSANone(KindKwLoc); break; - case OMPC_DEFAULT_shared: + case OMP_DEFAULT_shared: DSAStack->setDefaultDSAShared(KindKwLoc); break; - case OMPC_DEFAULT_unknown: - llvm_unreachable("Clause kind is not allowed."); + case OMP_DEFAULT_firstprivate: + DSAStack->setDefaultDSAFirstPrivate(KindKwLoc); break; + default: + llvm_unreachable("DSA unexpected in OpenMP default clause"); } + return new (Context) OMPDefaultClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); } @@ -12010,6 +13021,43 @@ OMPClause *Sema::ActOnOpenMPAtomicDefaultMemOrderClause( LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPOrderClause(OpenMPOrderClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_ORDER_unknown) { + static_assert(OMPC_ORDER_unknown > 0, + "OMPC_ORDER_unknown not greater than 0"); + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_order, /*First=*/0, + /*Last=*/OMPC_ORDER_unknown) + << getOpenMPClauseName(OMPC_order); + return nullptr; + } + return new (Context) + OMPOrderClause(Kind, KindKwLoc, StartLoc, LParenLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPUpdateClause(OpenMPDependClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DEPEND_unknown || Kind == OMPC_DEPEND_source || + Kind == OMPC_DEPEND_sink || Kind == OMPC_DEPEND_depobj) { + unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink, + OMPC_DEPEND_depobj}; + Diag(KindKwLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, Except) + << getOpenMPClauseName(OMPC_update); + return nullptr; + } + return OMPUpdateClause::Create(Context, StartLoc, LParenLoc, KindKwLoc, Kind, + EndLoc); +} + OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( OpenMPClauseKind Kind, ArrayRef<unsigned> Argument, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -12047,6 +13095,12 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind], EndLoc); break; + case OMPC_device: + assert(Argument.size() == 1 && ArgumentLoc.size() == 1); + Res = ActOnOpenMPDeviceClause( + static_cast<OpenMPDeviceClauseModifier>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -12073,13 +13127,17 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_read: case OMPC_write: case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_depend: - case OMPC_device: case OMPC_threads: case OMPC_simd: case OMPC_map: @@ -12095,6 +13153,7 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_unified_address: case OMPC_unified_shared_memory: @@ -12104,6 +13163,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12170,7 +13237,9 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( // OpenMP, 2.7.1, Loop Construct, Restrictions // The nonmonotonic modifier can only be specified with schedule(dynamic) or // schedule(guided). - if ((M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || + // OpenMP 5.0 does not have this restriction. + if (LangOpts.OpenMP < 50 && + (M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic || M2 == OMPC_SCHEDULE_MODIFIER_nonmonotonic) && Kind != OMPC_SCHEDULE_dynamic && Kind != OMPC_SCHEDULE_guided) { Diag(M1 == OMPC_SCHEDULE_MODIFIER_nonmonotonic ? M1Loc : M2Loc, @@ -12250,6 +13319,18 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_seq_cst: Res = ActOnOpenMPSeqCstClause(StartLoc, EndLoc); break; + case OMPC_acq_rel: + Res = ActOnOpenMPAcqRelClause(StartLoc, EndLoc); + break; + case OMPC_acquire: + Res = ActOnOpenMPAcquireClause(StartLoc, EndLoc); + break; + case OMPC_release: + Res = ActOnOpenMPReleaseClause(StartLoc, EndLoc); + break; + case OMPC_relaxed: + Res = ActOnOpenMPRelaxedClause(StartLoc, EndLoc); + break; case OMPC_threads: Res = ActOnOpenMPThreadsClause(StartLoc, EndLoc); break; @@ -12271,6 +13352,9 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_dynamic_allocators: Res = ActOnOpenMPDynamicAllocatorsClause(StartLoc, EndLoc); break; + case OMPC_destroy: + Res = ActOnOpenMPDestroyClause(StartLoc, EndLoc); + break; case OMPC_if: case OMPC_final: case OMPC_num_threads: @@ -12295,6 +13379,7 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_threadprivate: case OMPC_allocate: case OMPC_flush: + case OMPC_depobj: case OMPC_depend: case OMPC_device: case OMPC_map: @@ -12311,11 +13396,19 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_to: case OMPC_from: case OMPC_use_device_ptr: + case OMPC_use_device_addr: case OMPC_is_device_ptr: case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: case OMPC_nontemporal: + case OMPC_order: + case OMPC_detach: + case OMPC_inclusive: + case OMPC_exclusive: + case OMPC_uses_allocators: + case OMPC_affinity: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12349,7 +13442,7 @@ OMPClause *Sema::ActOnOpenMPWriteClause(SourceLocation StartLoc, OMPClause *Sema::ActOnOpenMPUpdateClause(SourceLocation StartLoc, SourceLocation EndLoc) { - return new (Context) OMPUpdateClause(StartLoc, EndLoc); + return OMPUpdateClause::Create(Context, StartLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPCaptureClause(SourceLocation StartLoc, @@ -12362,6 +13455,26 @@ OMPClause *Sema::ActOnOpenMPSeqCstClause(SourceLocation StartLoc, return new (Context) OMPSeqCstClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPAcqRelClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPAcqRelClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPAcquireClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPAcquireClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPReleaseClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPReleaseClause(StartLoc, EndLoc); +} + +OMPClause *Sema::ActOnOpenMPRelaxedClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPRelaxedClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPThreadsClause(SourceLocation StartLoc, SourceLocation EndLoc) { return new (Context) OMPThreadsClause(StartLoc, EndLoc); @@ -12397,14 +13510,19 @@ OMPClause *Sema::ActOnOpenMPDynamicAllocatorsClause(SourceLocation StartLoc, return new (Context) OMPDynamicAllocatorsClause(StartLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPDestroyClause(SourceLocation StartLoc, + SourceLocation EndLoc) { + return new (Context) OMPDestroyClause(StartLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPVarListClause( - OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *TailExpr, + OpenMPClauseKind Kind, ArrayRef<Expr *> VarList, Expr *DepModOrTailExpr, const OMPVarListLocTy &Locs, SourceLocation ColonLoc, CXXScopeSpec &ReductionOrMapperIdScopeSpec, DeclarationNameInfo &ReductionOrMapperId, int ExtraModifier, ArrayRef<OpenMPMapModifierKind> MapTypeModifiers, ArrayRef<SourceLocation> MapTypeModifiersLoc, bool IsMapTypeImplicit, - SourceLocation DepLinMapLastLoc) { + SourceLocation ExtraModifierLoc) { SourceLocation StartLoc = Locs.StartLoc; SourceLocation LParenLoc = Locs.LParenLoc; SourceLocation EndLoc = Locs.EndLoc; @@ -12421,15 +13539,18 @@ OMPClause *Sema::ActOnOpenMPVarListClause( "Unexpected lastprivate modifier."); Res = ActOnOpenMPLastprivateClause( VarList, static_cast<OpenMPLastprivateModifier>(ExtraModifier), - DepLinMapLastLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); + ExtraModifierLoc, ColonLoc, StartLoc, LParenLoc, EndLoc); break; case OMPC_shared: Res = ActOnOpenMPSharedClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_reduction: - Res = ActOnOpenMPReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, - EndLoc, ReductionOrMapperIdScopeSpec, - ReductionOrMapperId); + assert(0 <= ExtraModifier && ExtraModifier <= OMPC_REDUCTION_unknown && + "Unexpected lastprivate modifier."); + Res = ActOnOpenMPReductionClause( + VarList, static_cast<OpenMPReductionClauseModifier>(ExtraModifier), + StartLoc, LParenLoc, ExtraModifierLoc, ColonLoc, EndLoc, + ReductionOrMapperIdScopeSpec, ReductionOrMapperId); break; case OMPC_task_reduction: Res = ActOnOpenMPTaskReductionClause(VarList, StartLoc, LParenLoc, ColonLoc, @@ -12445,13 +13566,13 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_LINEAR_unknown && "Unexpected linear modifier."); Res = ActOnOpenMPLinearClause( - VarList, TailExpr, StartLoc, LParenLoc, - static_cast<OpenMPLinearClauseKind>(ExtraModifier), DepLinMapLastLoc, + VarList, DepModOrTailExpr, StartLoc, LParenLoc, + static_cast<OpenMPLinearClauseKind>(ExtraModifier), ExtraModifierLoc, ColonLoc, EndLoc); break; case OMPC_aligned: - Res = ActOnOpenMPAlignedClause(VarList, TailExpr, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAlignedClause(VarList, DepModOrTailExpr, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_copyin: Res = ActOnOpenMPCopyinClause(VarList, StartLoc, LParenLoc, EndLoc); @@ -12466,8 +13587,8 @@ OMPClause *Sema::ActOnOpenMPVarListClause( assert(0 <= ExtraModifier && ExtraModifier <= OMPC_DEPEND_unknown && "Unexpected depend modifier."); Res = ActOnOpenMPDependClause( - static_cast<OpenMPDependClauseKind>(ExtraModifier), DepLinMapLastLoc, - ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); + DepModOrTailExpr, static_cast<OpenMPDependClauseKind>(ExtraModifier), + ExtraModifierLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: assert(0 <= ExtraModifier && ExtraModifier <= OMPC_MAP_unknown && @@ -12475,7 +13596,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPMapClause( MapTypeModifiers, MapTypeModifiersLoc, ReductionOrMapperIdScopeSpec, ReductionOrMapperId, static_cast<OpenMPMapClauseKind>(ExtraModifier), - IsMapTypeImplicit, DepLinMapLastLoc, ColonLoc, VarList, Locs); + IsMapTypeImplicit, ExtraModifierLoc, ColonLoc, VarList, Locs); break; case OMPC_to: Res = ActOnOpenMPToClause(VarList, ReductionOrMapperIdScopeSpec, @@ -12488,17 +13609,31 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_use_device_ptr: Res = ActOnOpenMPUseDevicePtrClause(VarList, Locs); break; + case OMPC_use_device_addr: + Res = ActOnOpenMPUseDeviceAddrClause(VarList, Locs); + break; case OMPC_is_device_ptr: Res = ActOnOpenMPIsDevicePtrClause(VarList, Locs); break; case OMPC_allocate: - Res = ActOnOpenMPAllocateClause(TailExpr, VarList, StartLoc, LParenLoc, - ColonLoc, EndLoc); + Res = ActOnOpenMPAllocateClause(DepModOrTailExpr, VarList, StartLoc, + LParenLoc, ColonLoc, EndLoc); break; case OMPC_nontemporal: Res = ActOnOpenMPNontemporalClause(VarList, StartLoc, LParenLoc, EndLoc); break; + case OMPC_inclusive: + Res = ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_exclusive: + Res = ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_affinity: + Res = ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, EndLoc, + DepModOrTailExpr, VarList); + break; case OMPC_if: + case OMPC_depobj: case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -12518,6 +13653,10 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_update: case OMPC_capture: case OMPC_seq_cst: + case OMPC_acq_rel: + case OMPC_acquire: + case OMPC_release: + case OMPC_relaxed: case OMPC_device: case OMPC_threads: case OMPC_simd: @@ -12539,6 +13678,11 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_atomic_default_mem_order: case OMPC_device_type: case OMPC_match: + case OMPC_order: + case OMPC_destroy: + case OMPC_detach: + case OMPC_uses_allocators: + default: llvm_unreachable("Clause is not allowed."); } return Res; @@ -12985,7 +14129,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, ExprCaptures.push_back(Ref->getDecl()); } } - DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + if (!IsImplicitClause) + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); Vars.push_back((VD || CurContext->isDependentContext()) ? RefExpr->IgnoreParens() : Ref); @@ -13518,6 +14663,12 @@ struct ReductionData { SmallVector<Expr *, 8> RHSs; /// Reduction operation expression. SmallVector<Expr *, 8> ReductionOps; + /// inscan copy operation expressions. + SmallVector<Expr *, 8> InscanCopyOps; + /// inscan copy temp array expressions for prefix sums. + SmallVector<Expr *, 8> InscanCopyArrayTemps; + /// inscan copy temp array element expressions for prefix sums. + SmallVector<Expr *, 8> InscanCopyArrayElems; /// Taskgroup descriptors for the corresponding reduction items in /// in_reduction clauses. SmallVector<Expr *, 8> TaskgroupDescriptors; @@ -13525,14 +14676,21 @@ struct ReductionData { SmallVector<Decl *, 4> ExprCaptures; /// List of postupdate expressions. SmallVector<Expr *, 4> ExprPostUpdates; + /// Reduction modifier. + unsigned RedModifier = 0; ReductionData() = delete; /// Reserves required memory for the reduction data. - ReductionData(unsigned Size) { + ReductionData(unsigned Size, unsigned Modifier = 0) : RedModifier(Modifier) { Vars.reserve(Size); Privates.reserve(Size); LHSs.reserve(Size); RHSs.reserve(Size); ReductionOps.reserve(Size); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.reserve(Size); + InscanCopyArrayTemps.reserve(Size); + InscanCopyArrayElems.reserve(Size); + } TaskgroupDescriptors.reserve(Size); ExprCaptures.reserve(Size); ExprPostUpdates.reserve(Size); @@ -13546,16 +14704,31 @@ struct ReductionData { RHSs.emplace_back(nullptr); ReductionOps.emplace_back(ReductionOp); TaskgroupDescriptors.emplace_back(nullptr); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.push_back(nullptr); + InscanCopyArrayTemps.push_back(nullptr); + InscanCopyArrayElems.push_back(nullptr); + } } /// Stores reduction data. void push(Expr *Item, Expr *Private, Expr *LHS, Expr *RHS, Expr *ReductionOp, - Expr *TaskgroupDescriptor) { + Expr *TaskgroupDescriptor, Expr *CopyOp, Expr *CopyArrayTemp, + Expr *CopyArrayElem) { Vars.emplace_back(Item); Privates.emplace_back(Private); LHSs.emplace_back(LHS); RHSs.emplace_back(RHS); ReductionOps.emplace_back(ReductionOp); TaskgroupDescriptors.emplace_back(TaskgroupDescriptor); + if (RedModifier == OMPC_REDUCTION_inscan) { + InscanCopyOps.push_back(CopyOp); + InscanCopyArrayTemps.push_back(CopyArrayTemp); + InscanCopyArrayElems.push_back(CopyArrayElem); + } else { + assert(CopyOp == nullptr && CopyArrayTemp == nullptr && + CopyArrayElem == nullptr && + "Copy operation must be used for inscan reductions only."); + } } }; } // namespace @@ -13567,7 +14740,7 @@ static bool checkOMPArraySectionConstantForReduction( if (Length == nullptr) { // For array sections of the form [1:] or [:], we would need to analyze // the lower bound... - if (OASE->getColonLoc().isValid()) + if (OASE->getColonLocFirst().isValid()) return false; // This is an array subscript which has implicit length 1! @@ -13593,7 +14766,7 @@ static bool checkOMPArraySectionConstantForReduction( if (Length == nullptr) { // For array sections of the form [1:] or [:], we would need to analyze // the lower bound... - if (OASE->getColonLoc().isValid()) + if (OASE->getColonLocFirst().isValid()) return false; // This is an array subscript which has implicit length 1! @@ -13948,11 +15121,11 @@ static bool actOnOMPReductionKindClause( if (isOpenMPTargetExecutionDirective(Stack->getCurrentDirective())) { S.Diag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; S.Diag(ELoc, diag::note_vla_unsupported); + continue; } else { S.targetDiag(ELoc, diag::err_omp_reduction_vla_unsupported) << !!OASE; S.targetDiag(ELoc, diag::note_vla_unsupported); } - continue; } // For arrays/array sections only: // Create pseudo array type for private copy. The size for this array will @@ -14007,9 +15180,9 @@ static bool actOnOMPReductionKindClause( if (auto *ComplexTy = OrigType->getAs<ComplexType>()) Type = ComplexTy->getElementType(); if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = - llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), - /*isIEEE=*/true); + llvm::APFloat InitValue = llvm::APFloat::getAllOnesValue( + Context.getFloatTypeSemantics(Type), + Context.getTypeSize(Type)); Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, Type, ELoc); } else if (Type->isScalarType()) { @@ -14157,6 +15330,53 @@ static bool actOnOMPReductionKindClause( continue; } + // Add copy operations for inscan reductions. + // LHS = RHS; + ExprResult CopyOpRes, TempArrayRes, TempArrayElem; + if (ClauseKind == OMPC_reduction && + RD.RedModifier == OMPC_REDUCTION_inscan) { + ExprResult RHS = S.DefaultLvalueConversion(RHSDRE); + CopyOpRes = S.BuildBinOp(Stack->getCurScope(), ELoc, BO_Assign, LHSDRE, + RHS.get()); + if (!CopyOpRes.isUsable()) + continue; + CopyOpRes = + S.ActOnFinishFullExpr(CopyOpRes.get(), /*DiscardedValue=*/true); + if (!CopyOpRes.isUsable()) + continue; + // For simd directive and simd-based directives in simd mode no need to + // construct temp array, need just a single temp element. + if (Stack->getCurrentDirective() == OMPD_simd || + (S.getLangOpts().OpenMPSimd && + isOpenMPSimdDirective(Stack->getCurrentDirective()))) { + VarDecl *TempArrayVD = + buildVarDecl(S, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + // Add a constructor to the temp decl. + S.ActOnUninitializedDecl(TempArrayVD); + TempArrayRes = buildDeclRefExpr(S, TempArrayVD, PrivateTy, ELoc); + } else { + // Build temp array for prefix sum. + auto *Dim = new (S.Context) + OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue); + QualType ArrayTy = + S.Context.getVariableArrayType(PrivateTy, Dim, ArrayType::Normal, + /*IndexTypeQuals=*/0, {ELoc, ELoc}); + VarDecl *TempArrayVD = + buildVarDecl(S, ELoc, ArrayTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + // Add a constructor to the temp decl. + S.ActOnUninitializedDecl(TempArrayVD); + TempArrayRes = buildDeclRefExpr(S, TempArrayVD, ArrayTy, ELoc); + TempArrayElem = + S.DefaultFunctionArrayLvalueConversion(TempArrayRes.get()); + auto *Idx = new (S.Context) + OpaqueValueExpr(ELoc, S.Context.getSizeType(), VK_RValue); + TempArrayElem = S.CreateBuiltinArraySubscriptExpr(TempArrayElem.get(), + ELoc, Idx, ELoc); + } + } + // OpenMP [2.15.4.6, Restrictions, p.2] // A list item that appears in an in_reduction clause of a task construct // must appear in a task_reduction clause of a construct associated with a @@ -14167,8 +15387,8 @@ static bool actOnOMPReductionKindClause( if (ClauseKind == OMPC_in_reduction) { SourceRange ParentSR; BinaryOperatorKind ParentBOK; - const Expr *ParentReductionOp; - Expr *ParentBOKTD, *ParentReductionOpTD; + const Expr *ParentReductionOp = nullptr; + Expr *ParentBOKTD = nullptr, *ParentReductionOpTD = nullptr; DSAStackTy::DSAVarData ParentBOKDSA = Stack->getTopMostTaskgroupReductionData(D, ParentSR, ParentBOK, ParentBOKTD); @@ -14177,13 +15397,9 @@ static bool actOnOMPReductionKindClause( D, ParentSR, ParentReductionOp, ParentReductionOpTD); bool IsParentBOK = ParentBOKDSA.DKind != OMPD_unknown; bool IsParentReductionOp = ParentReductionOpDSA.DKind != OMPD_unknown; - if (!IsParentBOK && !IsParentReductionOp) { - S.Diag(ELoc, diag::err_omp_in_reduction_not_task_reduction); - continue; - } if ((DeclareReductionRef.isUnset() && IsParentReductionOp) || - (DeclareReductionRef.isUsable() && IsParentBOK) || BOK != ParentBOK || - IsParentReductionOp) { + (DeclareReductionRef.isUsable() && IsParentBOK) || + (IsParentBOK && BOK != ParentBOK) || IsParentReductionOp) { bool EmitError = true; if (IsParentReductionOp && DeclareReductionRef.isUsable()) { llvm::FoldingSetNodeID RedId, ParentRedId; @@ -14206,7 +15422,6 @@ static bool actOnOMPReductionKindClause( } } TaskgroupDescriptor = IsParentBOK ? ParentBOKTD : ParentReductionOpTD; - assert(TaskgroupDescriptor && "Taskgroup descriptor must be defined."); } DeclRefExpr *Ref = nullptr; @@ -14245,8 +15460,17 @@ static bool actOnOMPReductionKindClause( } // All reduction items are still marked as reduction (to do not increase // code base size). - Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); - if (CurrDir == OMPD_taskgroup) { + unsigned Modifier = RD.RedModifier; + // Consider task_reductions as reductions with task modifier. Required for + // correct analysis of in_reduction clauses. + if (CurrDir == OMPD_taskgroup && ClauseKind == OMPC_task_reduction) + Modifier = OMPC_REDUCTION_task; + Stack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref, Modifier); + if (Modifier == OMPC_REDUCTION_task && + (CurrDir == OMPD_taskgroup || + ((isOpenMPParallelDirective(CurrDir) || + isOpenMPWorksharingDirective(CurrDir)) && + !isOpenMPSimdDirective(CurrDir)))) { if (DeclareReductionRef.isUsable()) Stack->addTaskgroupReductionData(D, ReductionIdRange, DeclareReductionRef.get()); @@ -14254,17 +15478,41 @@ static bool actOnOMPReductionKindClause( Stack->addTaskgroupReductionData(D, ReductionIdRange, BOK); } RD.push(VarsExpr, PrivateDRE, LHSDRE, RHSDRE, ReductionOp.get(), - TaskgroupDescriptor); + TaskgroupDescriptor, CopyOpRes.get(), TempArrayRes.get(), + TempArrayElem.get()); } return RD.Vars.empty(); } OMPClause *Sema::ActOnOpenMPReductionClause( - ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation ColonLoc, SourceLocation EndLoc, + ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, ArrayRef<Expr *> UnresolvedReductions) { - ReductionData RD(VarList.size()); + if (ModifierLoc.isValid() && Modifier == OMPC_REDUCTION_unknown) { + Diag(LParenLoc, diag::err_omp_unexpected_clause_value) + << getListOfPossibleValues(OMPC_reduction, /*First=*/0, + /*Last=*/OMPC_REDUCTION_unknown) + << getOpenMPClauseName(OMPC_reduction); + return nullptr; + } + // OpenMP 5.0, 2.19.5.4 reduction Clause, Restrictions + // A reduction clause with the inscan reduction-modifier may only appear on a + // worksharing-loop construct, a worksharing-loop SIMD construct, a simd + // construct, a parallel worksharing-loop construct or a parallel + // worksharing-loop SIMD construct. + if (Modifier == OMPC_REDUCTION_inscan && + (DSAStack->getCurrentDirective() != OMPD_for && + DSAStack->getCurrentDirective() != OMPD_for_simd && + DSAStack->getCurrentDirective() != OMPD_simd && + DSAStack->getCurrentDirective() != OMPD_parallel_for && + DSAStack->getCurrentDirective() != OMPD_parallel_for_simd)) { + Diag(ModifierLoc, diag::err_omp_wrong_inscan_reduction); + return nullptr; + } + + ReductionData RD(VarList.size(), Modifier); if (actOnOMPReductionKindClause(*this, DSAStack, OMPC_reduction, VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, ReductionId, @@ -14272,9 +15520,10 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return nullptr; return OMPReductionClause::Create( - Context, StartLoc, LParenLoc, ColonLoc, EndLoc, RD.Vars, - ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, - RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, + Context, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, Modifier, + RD.Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, + RD.Privates, RD.LHSs, RD.RHSs, RD.ReductionOps, RD.InscanCopyOps, + RD.InscanCopyArrayTemps, RD.InscanCopyArrayElems, buildPreInits(Context, RD.ExprCaptures), buildPostUpdate(*this, RD.ExprPostUpdates)); } @@ -14330,8 +15579,8 @@ bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, } bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, - OpenMPLinearClauseKind LinKind, - QualType Type) { + OpenMPLinearClauseKind LinKind, QualType Type, + bool IsDeclareSimd) { const auto *VD = dyn_cast_or_null<VarDecl>(D); // A variable must not have an incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type)) @@ -14347,8 +15596,10 @@ bool Sema::CheckOpenMPLinearDecl(const ValueDecl *D, SourceLocation ELoc, // OpenMP 5.0 [2.19.3, List Item Privatization, Restrictions] // A variable that is privatized must not have a const-qualified type // unless it is of class type with a mutable member. This restriction does - // not apply to the firstprivate clause. - if (rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc)) + // not apply to the firstprivate clause, nor to the linear clause on + // declarative directives (like declare simd). + if (!IsDeclareSimd && + rejectConstNotMutableType(*this, D, Type, OMPC_linear, ELoc)) return true; // A list item must be of integral or pointer type. @@ -14900,8 +16151,53 @@ OMPClause *Sema::ActOnOpenMPFlushClause(ArrayRef<Expr *> VarList, return OMPFlushClause::Create(Context, StartLoc, LParenLoc, EndLoc, VarList); } +/// Tries to find omp_depend_t. type. +static bool findOMPDependT(Sema &S, SourceLocation Loc, DSAStackTy *Stack, + bool Diagnose = true) { + QualType OMPDependT = Stack->getOMPDependT(); + if (!OMPDependT.isNull()) + return true; + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_depend_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + if (Diagnose) + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_depend_t"; + return false; + } + Stack->setOMPDependT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (!Depobj) + return nullptr; + + bool OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack); + + // OpenMP 5.0, 2.17.10.1 depobj Construct + // depobj is an lvalue expression of type omp_depend_t. + if (!Depobj->isTypeDependent() && !Depobj->isValueDependent() && + !Depobj->isInstantiationDependent() && + !Depobj->containsUnexpandedParameterPack() && + (OMPDependTFound && + !Context.typesAreCompatible(DSAStack->getOMPDependT(), Depobj->getType(), + /*CompareUnqualified=*/true))) { + Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue) + << 0 << Depobj->getType() << Depobj->getSourceRange(); + } + + if (!Depobj->isLValue()) { + Diag(Depobj->getExprLoc(), diag::err_omp_expected_omp_depend_t_lvalue) + << 1 << Depobj->getSourceRange(); + } + + return OMPDepobjClause::Create(Context, StartLoc, LParenLoc, EndLoc, Depobj); +} + OMPClause * -Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, +Sema::ActOnOpenMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, SourceLocation DepLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -14911,16 +16207,38 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, << "'source' or 'sink'" << getOpenMPClauseName(OMPC_depend); return nullptr; } - if (DSAStack->getCurrentDirective() != OMPD_ordered && + if ((DSAStack->getCurrentDirective() != OMPD_ordered || + DSAStack->getCurrentDirective() == OMPD_depobj) && (DepKind == OMPC_DEPEND_unknown || DepKind == OMPC_DEPEND_source || - DepKind == OMPC_DEPEND_sink)) { - unsigned Except[] = {OMPC_DEPEND_source, OMPC_DEPEND_sink}; + DepKind == OMPC_DEPEND_sink || + ((LangOpts.OpenMP < 50 || + DSAStack->getCurrentDirective() == OMPD_depobj) && + DepKind == OMPC_DEPEND_depobj))) { + SmallVector<unsigned, 3> Except; + Except.push_back(OMPC_DEPEND_source); + Except.push_back(OMPC_DEPEND_sink); + if (LangOpts.OpenMP < 50 || DSAStack->getCurrentDirective() == OMPD_depobj) + Except.push_back(OMPC_DEPEND_depobj); + std::string Expected = (LangOpts.OpenMP >= 50 && !DepModifier) + ? "depend modifier(iterator) or " + : ""; Diag(DepLoc, diag::err_omp_unexpected_clause_value) - << getListOfPossibleValues(OMPC_depend, /*First=*/0, - /*Last=*/OMPC_DEPEND_unknown, Except) + << Expected + getListOfPossibleValues(OMPC_depend, /*First=*/0, + /*Last=*/OMPC_DEPEND_unknown, + Except) << getOpenMPClauseName(OMPC_depend); return nullptr; } + if (DepModifier && + (DepKind == OMPC_DEPEND_source || DepKind == OMPC_DEPEND_sink)) { + Diag(DepModifier->getExprLoc(), + diag::err_omp_depend_sink_source_with_modifier); + return nullptr; + } + if (DepModifier && + !DepModifier->getType()->isSpecificBuiltinType(BuiltinType::OMPIterator)) + Diag(DepModifier->getExprLoc(), diag::err_omp_depend_modifier_not_iterator); + SmallVector<Expr *, 8> Vars; DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); @@ -15021,42 +16339,97 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, } OpsOffs.emplace_back(RHS, OOK); } else { - // OpenMP 5.0 [2.17.11, Restrictions] - // List items used in depend clauses cannot be zero-length array sections. - const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); - if (OASE) { - const Expr *Length = OASE->getLength(); - Expr::EvalResult Result; - if (Length && !Length->isValueDependent() && - Length->EvaluateAsInt(Result, Context) && - Result.Val.getInt().isNullValue()) { - Diag(ELoc, - diag::err_omp_depend_zero_length_array_section_not_allowed) - << SimpleExpr->getSourceRange(); + bool OMPDependTFound = LangOpts.OpenMP >= 50; + if (OMPDependTFound) + OMPDependTFound = findOMPDependT(*this, StartLoc, DSAStack, + DepKind == OMPC_DEPEND_depobj); + if (DepKind == OMPC_DEPEND_depobj) { + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the depobj dependence type + // must be expressions of the omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (OMPDependTFound && + !Context.hasSameUnqualifiedType(DSAStack->getOMPDependT(), + RefExpr->getType()))) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 0 << RefExpr->getType() << RefExpr->getSourceRange(); continue; } - } + if (!RefExpr->isLValue()) { + Diag(ELoc, diag::err_omp_expected_omp_depend_t_lvalue) + << 1 << RefExpr->getType() << RefExpr->getSourceRange(); + continue; + } + } else { + // OpenMP 5.0 [2.17.11, Restrictions] + // List items used in depend clauses cannot be zero-length array + // sections. + QualType ExprTy = RefExpr->getType().getNonReferenceType(); + const auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); + if (OASE) { + QualType BaseType = + OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); + if (const auto *ATy = BaseType->getAsArrayTypeUnsafe()) + ExprTy = ATy->getElementType(); + else + ExprTy = BaseType->getPointeeType(); + ExprTy = ExprTy.getNonReferenceType(); + const Expr *Length = OASE->getLength(); + Expr::EvalResult Result; + if (Length && !Length->isValueDependent() && + Length->EvaluateAsInt(Result, Context) && + Result.Val.getInt().isNullValue()) { + Diag(ELoc, + diag::err_omp_depend_zero_length_array_section_not_allowed) + << SimpleExpr->getSourceRange(); + continue; + } + } - auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - if (!RefExpr->IgnoreParenImpCasts()->isLValue() || - (ASE && - !ASE->getBase()->getType().getNonReferenceType()->isPointerType() && - !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); - continue; - } + // OpenMP 5.0, 2.17.11 depend Clause, Restrictions, C/C++ + // List items used in depend clauses with the in, out, inout or + // mutexinoutset dependence types cannot be expressions of the + // omp_depend_t type. + if (!RefExpr->isValueDependent() && !RefExpr->isTypeDependent() && + !RefExpr->isInstantiationDependent() && + !RefExpr->containsUnexpandedParameterPack() && + (OMPDependTFound && + DSAStack->getOMPDependT().getTypePtr() == ExprTy.getTypePtr())) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << 1 + << RefExpr->getSourceRange(); + continue; + } - ExprResult Res; - { - Sema::TentativeAnalysisScope Trap(*this); - Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, - RefExpr->IgnoreParenImpCasts()); - } - if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr)) { - Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) - << RefExpr->getSourceRange(); - continue; + auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); + if (!RefExpr->IgnoreParenImpCasts()->isLValue() || + (ASE && !ASE->getBase()->isTypeDependent() && + !ASE->getBase() + ->getType() + .getNonReferenceType() + ->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, + RefExpr->IgnoreParenImpCasts()); + } + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && + !isa<OMPArrayShapingExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << (LangOpts.OpenMP >= 50 ? 1 : 0) + << (LangOpts.OpenMP >= 50 ? 1 : 0) << RefExpr->getSourceRange(); + continue; + } } } Vars.push_back(RefExpr->IgnoreParenImpCasts()); @@ -15074,24 +16447,40 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, - DepKind, DepLoc, ColonLoc, Vars, - TotalDepCount.getZExtValue()); + DepModifier, DepKind, DepLoc, ColonLoc, + Vars, TotalDepCount.getZExtValue()); if ((DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) && DSAStack->isParentOrderedRegion()) DSAStack->addDoacrossDependClause(C, OpsOffs); return C; } -OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, +OMPClause *Sema::ActOnOpenMPDeviceClause(OpenMPDeviceClauseModifier Modifier, + Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { + assert((ModifierLoc.isInvalid() || LangOpts.OpenMP >= 50) && + "Unexpected device modifier in OpenMP < 50."); + + bool ErrorFound = false; + if (ModifierLoc.isValid() && Modifier == OMPC_DEVICE_unknown) { + std::string Values = + getListOfPossibleValues(OMPC_device, /*First=*/0, OMPC_DEVICE_unknown); + Diag(ModifierLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_device); + ErrorFound = true; + } + Expr *ValExpr = Device; Stmt *HelperValStmt = nullptr; // OpenMP [2.9.1, Restrictions] // The device expression must evaluate to a non-negative integer value. - if (!isNonNegativeIntegerValue(ValExpr, *this, OMPC_device, - /*StrictlyPositive=*/false)) + ErrorFound = !isNonNegativeIntegerValue(ValExpr, *this, OMPC_device, + /*StrictlyPositive=*/false) || + ErrorFound; + if (ErrorFound) return nullptr; OpenMPDirectiveKind DKind = DSAStack->getCurrentDirective(); @@ -15104,8 +16493,9 @@ OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, HelperValStmt = buildPreInits(Context, Captures); } - return new (Context) OMPDeviceClause(ValExpr, HelperValStmt, CaptureRegion, - StartLoc, LParenLoc, EndLoc); + return new (Context) + OMPDeviceClause(Modifier, ValExpr, HelperValStmt, CaptureRegion, StartLoc, + LParenLoc, ModifierLoc, EndLoc); } static bool checkTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, @@ -15133,7 +16523,8 @@ static bool checkArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, // If this is an array subscript, it refers to the whole size if the size of // the dimension is constant and equals 1. Also, an array section assumes the // format of an array subscript if no colon is used. - if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) { + if (isa<ArraySubscriptExpr>(E) || + (OASE && OASE->getColonLocFirst().isInvalid())) { if (const auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) return ATy->getSize().getSExtValue() != 1; // Size can't be evaluated statically. @@ -15189,7 +16580,8 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, // An array subscript always refer to a single element. Also, an array section // assumes the format of an array subscript if no colon is used. - if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) + if (isa<ArraySubscriptExpr>(E) || + (OASE && OASE->getColonLocFirst().isInvalid())) return false; assert(OASE && "Expecting array section if not an array subscript."); @@ -15214,256 +16606,338 @@ static bool checkArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, return ConstLength.getSExtValue() != 1; } -// Return the expression of the base of the mappable expression or null if it -// cannot be determined and do all the necessary checks to see if the expression -// is valid as a standalone mappable expression. In the process, record all the -// components of the expression. -static const Expr *checkMapClauseExpressionBase( - Sema &SemaRef, Expr *E, - OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, - OpenMPClauseKind CKind, bool NoDiagnose) { - SourceLocation ELoc = E->getExprLoc(); - SourceRange ERange = E->getSourceRange(); - - // The base of elements of list in a map clause have to be either: - // - a reference to variable or field. - // - a member expression. - // - an array expression. - // - // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the - // reference to 'r'. - // - // If we have: - // - // struct SS { - // Bla S; - // foo() { - // #pragma omp target map (S.Arr[:12]); - // } - // } - // - // We want to retrieve the member expression 'this->S'; +// The base of elements of list in a map clause have to be either: +// - a reference to variable or field. +// - a member expression. +// - an array expression. +// +// E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the +// reference to 'r'. +// +// If we have: +// +// struct SS { +// Bla S; +// foo() { +// #pragma omp target map (S.Arr[:12]); +// } +// } +// +// We want to retrieve the member expression 'this->S'; +// OpenMP 5.0 [2.19.7.1, map Clause, Restrictions, p.2] +// If a list item is an array section, it must specify contiguous storage. +// +// For this restriction it is sufficient that we make sure only references +// to variables or fields and array expressions, and that no array sections +// exist except in the rightmost expression (unless they cover the whole +// dimension of the array). E.g. these would be invalid: +// +// r.ArrS[3:5].Arr[6:7] +// +// r.ArrS[3:5].x +// +// but these would be valid: +// r.ArrS[3].Arr[6:7] +// +// r.ArrS[3].x +namespace { +class MapBaseChecker final : public StmtVisitor<MapBaseChecker, bool> { + Sema &SemaRef; + OpenMPClauseKind CKind = OMPC_unknown; + OMPClauseMappableExprCommon::MappableExprComponentList &Components; + bool NoDiagnose = false; const Expr *RelevantExpr = nullptr; - - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2] - // If a list item is an array section, it must specify contiguous storage. - // - // For this restriction it is sufficient that we make sure only references - // to variables or fields and array expressions, and that no array sections - // exist except in the rightmost expression (unless they cover the whole - // dimension of the array). E.g. these would be invalid: - // - // r.ArrS[3:5].Arr[6:7] - // - // r.ArrS[3:5].x - // - // but these would be valid: - // r.ArrS[3].Arr[6:7] - // - // r.ArrS[3].x - bool AllowUnitySizeArraySection = true; bool AllowWholeSizeArraySection = true; + SourceLocation ELoc; + SourceRange ERange; - while (!RelevantExpr) { - E = E->IgnoreParenImpCasts(); + void emitErrorMsg() { + // If nothing else worked, this is not a valid map clause expression. + if (SemaRef.getLangOpts().OpenMP < 50) { + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << ERange; + } else { + SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses) + << getOpenMPClauseName(CKind) << ERange; + } + } - if (auto *CurE = dyn_cast<DeclRefExpr>(E)) { - if (!isa<VarDecl>(CurE->getDecl())) - return nullptr; +public: + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + if (!isa<VarDecl>(DRE->getDecl())) { + emitErrorMsg(); + return false; + } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = DRE; + // Record the component. + Components.emplace_back(DRE, DRE->getDecl()); + return true; + } - RelevantExpr = CurE; + bool VisitMemberExpr(MemberExpr *ME) { + Expr *E = ME; + Expr *BaseE = ME->getBase()->IgnoreParenCasts(); - // If we got a reference to a declaration, we should not expect any array - // section before that. - AllowUnitySizeArraySection = false; - AllowWholeSizeArraySection = false; + if (isa<CXXThisExpr>(BaseE)) { + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + // We found a base expression: this->Val. + RelevantExpr = ME; + } else { + E = BaseE; + } - // Record the component. - CurComponents.emplace_back(CurE, CurE->getDecl()); - } else if (auto *CurE = dyn_cast<MemberExpr>(E)) { - Expr *BaseE = CurE->getBase()->IgnoreParenImpCasts(); + if (!isa<FieldDecl>(ME->getMemberDecl())) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) + << ME->getSourceRange(); + return false; + } + if (RelevantExpr) + return false; + return Visit(E); + } - if (isa<CXXThisExpr>(BaseE)) - // We found a base expression: this->Val. - RelevantExpr = CurE; - else - E = BaseE; + auto *FD = cast<FieldDecl>(ME->getMemberDecl()); - if (!isa<FieldDecl>(CurE->getMemberDecl())) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) - << CurE->getSourceRange(); - return nullptr; - } - if (RelevantExpr) - return nullptr; - continue; + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3] + // A bit-field cannot appear in a map clause. + // + if (FD->isBitField()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) + << ME->getSourceRange() << getOpenMPClauseName(CKind); + return false; } + if (RelevantExpr) + return false; + return Visit(E); + } - auto *FD = cast<FieldDecl>(CurE->getMemberDecl()); + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + QualType CurType = BaseE->getType().getNonReferenceType(); - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3] - // A bit-field cannot appear in a map clause. - // - if (FD->isBitField()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) - << CurE->getSourceRange() << getOpenMPClauseName(CKind); - return nullptr; - } - if (RelevantExpr) - return nullptr; - continue; + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2] + // A list item cannot be a variable that is a member of a structure with + // a union type. + // + if (CurType->isUnionType()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << ME->getSourceRange(); + return false; } + return RelevantExpr || Visit(E); + } - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] - // If the type of a list item is a reference to a type T then the type - // will be considered to be T for all purposes of this clause. - QualType CurType = BaseE->getType().getNonReferenceType(); + // If we got a member expression, we should not expect any array section + // before that: + // + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7] + // If a list item is an element of a structure, only the rightmost symbol + // of the variable reference can be an array section. + // + AllowUnitySizeArraySection = false; + AllowWholeSizeArraySection = false; - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2] - // A list item cannot be a variable that is a member of a structure with - // a union type. - // - if (CurType->isUnionType()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) - << CurE->getSourceRange(); - return nullptr; - } - continue; + // Record the component. + Components.emplace_back(ME, FD); + return RelevantExpr || Visit(E); + } + + bool VisitArraySubscriptExpr(ArraySubscriptExpr *AE) { + Expr *E = AE->getBase()->IgnoreParenImpCasts(); + + if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { + if (!NoDiagnose) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << AE->getSourceRange(); + return false; } + return RelevantExpr || Visit(E); + } - // If we got a member expression, we should not expect any array section - // before that: - // - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7] - // If a list item is an element of a structure, only the rightmost symbol - // of the variable reference can be an array section. - // - AllowUnitySizeArraySection = false; + // If we got an array subscript that express the whole dimension we + // can have any array expressions before. If it only expressing part of + // the dimension, we can only have unitary-size array expressions. + if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, AE, + E->getType())) AllowWholeSizeArraySection = false; - // Record the component. - CurComponents.emplace_back(CurE, FD); - } else if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { - E = CurE->getBase()->IgnoreParenImpCasts(); - - if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { - if (!NoDiagnose) { - SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) - << 0 << CurE->getSourceRange(); - return nullptr; - } - continue; + if (const auto *TE = dyn_cast<CXXThisExpr>(E->IgnoreParenCasts())) { + Expr::EvalResult Result; + if (!AE->getIdx()->isValueDependent() && + AE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext()) && + !Result.Val.getInt().isNullValue()) { + SemaRef.Diag(AE->getIdx()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(AE->getIdx()->getExprLoc(), + diag::note_omp_invalid_subscript_on_this_ptr_map); } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = TE; + } - // If we got an array subscript that express the whole dimension we - // can have any array expressions before. If it only expressing part of - // the dimension, we can only have unitary-size array expressions. - if (checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, - E->getType())) - AllowWholeSizeArraySection = false; + // Record the component - we don't have any declaration associated. + Components.emplace_back(AE, nullptr); - if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { - Expr::EvalResult Result; - if (CurE->getIdx()->EvaluateAsInt(Result, SemaRef.getASTContext())) { - if (!Result.Val.getInt().isNullValue()) { - SemaRef.Diag(CurE->getIdx()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getIdx()->getExprLoc(), - diag::note_omp_invalid_subscript_on_this_ptr_map); - } - } - RelevantExpr = TE; - } + return RelevantExpr || Visit(E); + } - // Record the component - we don't have any declaration associated. - CurComponents.emplace_back(CurE, nullptr); - } else if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { - assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); - E = CurE->getBase()->IgnoreParenImpCasts(); + bool VisitOMPArraySectionExpr(OMPArraySectionExpr *OASE) { + assert(!NoDiagnose && "Array sections cannot be implicitly mapped."); + Expr *E = OASE->getBase()->IgnoreParenImpCasts(); + QualType CurType = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); - QualType CurType = - OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + if (CurType->isReferenceType()) + CurType = CurType->getPointeeType(); - // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] - // If the type of a list item is a reference to a type T then the type - // will be considered to be T for all purposes of this clause. - if (CurType->isReferenceType()) - CurType = CurType->getPointeeType(); + bool IsPointer = CurType->isAnyPointerType(); - bool IsPointer = CurType->isAnyPointerType(); + if (!IsPointer && !CurType->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << OASE->getSourceRange(); + return false; + } - if (!IsPointer && !CurType->isArrayType()) { - SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) - << 0 << CurE->getSourceRange(); - return nullptr; - } + bool NotWhole = + checkArrayExpressionDoesNotReferToWholeSize(SemaRef, OASE, CurType); + bool NotUnity = + checkArrayExpressionDoesNotReferToUnitySize(SemaRef, OASE, CurType); - bool NotWhole = - checkArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); - bool NotUnity = - checkArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); + if (AllowWholeSizeArraySection) { + // Any array section is currently allowed. Allowing a whole size array + // section implies allowing a unity array section as well. + // + // If this array section refers to the whole dimension we can still + // accept other array sections before this one, except if the base is a + // pointer. Otherwise, only unitary sections are accepted. + if (NotWhole || IsPointer) + AllowWholeSizeArraySection = false; + } else if (AllowUnitySizeArraySection && NotUnity) { + // A unity or whole array section is not allowed and that is not + // compatible with the properties of the current array section. + SemaRef.Diag( + ELoc, diag::err_array_section_does_not_specify_contiguous_storage) + << OASE->getSourceRange(); + return false; + } - if (AllowWholeSizeArraySection) { - // Any array section is currently allowed. Allowing a whole size array - // section implies allowing a unity array section as well. - // - // If this array section refers to the whole dimension we can still - // accept other array sections before this one, except if the base is a - // pointer. Otherwise, only unitary sections are accepted. - if (NotWhole || IsPointer) - AllowWholeSizeArraySection = false; - } else if (AllowUnitySizeArraySection && NotUnity) { - // A unity or whole array section is not allowed and that is not - // compatible with the properties of the current array section. - SemaRef.Diag( - ELoc, diag::err_array_section_does_not_specify_contiguous_storage) - << CurE->getSourceRange(); - return nullptr; + if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { + Expr::EvalResult ResultR; + Expr::EvalResult ResultL; + if (!OASE->getLength()->isValueDependent() && + OASE->getLength()->EvaluateAsInt(ResultR, SemaRef.getASTContext()) && + !ResultR.Val.getInt().isOneValue()) { + SemaRef.Diag(OASE->getLength()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(OASE->getLength()->getExprLoc(), + diag::note_omp_invalid_length_on_this_ptr_mapping); } - - if (const auto *TE = dyn_cast<CXXThisExpr>(E)) { - Expr::EvalResult ResultR; - Expr::EvalResult ResultL; - if (CurE->getLength()->EvaluateAsInt(ResultR, - SemaRef.getASTContext())) { - if (!ResultR.Val.getInt().isOneValue()) { - SemaRef.Diag(CurE->getLength()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getLength()->getExprLoc(), - diag::note_omp_invalid_length_on_this_ptr_mapping); - } - } - if (CurE->getLowerBound() && CurE->getLowerBound()->EvaluateAsInt( - ResultL, SemaRef.getASTContext())) { - if (!ResultL.Val.getInt().isNullValue()) { - SemaRef.Diag(CurE->getLowerBound()->getExprLoc(), - diag::err_omp_invalid_map_this_expr); - SemaRef.Diag(CurE->getLowerBound()->getExprLoc(), - diag::note_omp_invalid_lower_bound_on_this_ptr_mapping); - } - } - RelevantExpr = TE; + if (OASE->getLowerBound() && !OASE->getLowerBound()->isValueDependent() && + OASE->getLowerBound()->EvaluateAsInt(ResultL, + SemaRef.getASTContext()) && + !ResultL.Val.getInt().isNullValue()) { + SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), + diag::err_omp_invalid_map_this_expr); + SemaRef.Diag(OASE->getLowerBound()->getExprLoc(), + diag::note_omp_invalid_lower_bound_on_this_ptr_mapping); } + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = TE; + } - // Record the component - we don't have any declaration associated. - CurComponents.emplace_back(CurE, nullptr); - } else { - if (!NoDiagnose) { - // If nothing else worked, this is not a valid map clause expression. - SemaRef.Diag( - ELoc, diag::err_omp_expected_named_var_member_or_array_expression) - << ERange; - } - return nullptr; + // Record the component - we don't have any declaration associated. + Components.emplace_back(OASE, nullptr); + return RelevantExpr || Visit(E); + } + bool VisitOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + Expr *Base = E->getBase(); + + // Record the component - we don't have any declaration associated. + Components.emplace_back(E, nullptr); + + return Visit(Base->IgnoreParenImpCasts()); + } + + bool VisitUnaryOperator(UnaryOperator *UO) { + if (SemaRef.getLangOpts().OpenMP < 50 || !UO->isLValue() || + UO->getOpcode() != UO_Deref) { + emitErrorMsg(); + return false; } + if (!RelevantExpr) { + // Record the component if haven't found base decl. + Components.emplace_back(UO, nullptr); + } + return RelevantExpr || Visit(UO->getSubExpr()->IgnoreParenImpCasts()); } + bool VisitBinaryOperator(BinaryOperator *BO) { + if (SemaRef.getLangOpts().OpenMP < 50 || !BO->getType()->isPointerType()) { + emitErrorMsg(); + return false; + } + + // Pointer arithmetic is the only thing we expect to happen here so after we + // make sure the binary operator is a pointer type, the we only thing need + // to to is to visit the subtree that has the same type as root (so that we + // know the other subtree is just an offset) + Expr *LE = BO->getLHS()->IgnoreParenImpCasts(); + Expr *RE = BO->getRHS()->IgnoreParenImpCasts(); + Components.emplace_back(BO, nullptr); + assert((LE->getType().getTypePtr() == BO->getType().getTypePtr() || + RE->getType().getTypePtr() == BO->getType().getTypePtr()) && + "Either LHS or RHS have base decl inside"); + if (BO->getType().getTypePtr() == LE->getType().getTypePtr()) + return RelevantExpr || Visit(LE); + return RelevantExpr || Visit(RE); + } + bool VisitCXXThisExpr(CXXThisExpr *CTE) { + assert(!RelevantExpr && "RelevantExpr is expected to be nullptr"); + RelevantExpr = CTE; + Components.emplace_back(CTE, nullptr); + return true; + } + bool VisitStmt(Stmt *) { + emitErrorMsg(); + return false; + } + const Expr *getFoundBase() const { + return RelevantExpr; + } + explicit MapBaseChecker( + Sema &SemaRef, OpenMPClauseKind CKind, + OMPClauseMappableExprCommon::MappableExprComponentList &Components, + bool NoDiagnose, SourceLocation &ELoc, SourceRange &ERange) + : SemaRef(SemaRef), CKind(CKind), Components(Components), + NoDiagnose(NoDiagnose), ELoc(ELoc), ERange(ERange) {} +}; +} // namespace - return RelevantExpr; +/// Return the expression of the base of the mappable expression or null if it +/// cannot be determined and do all the necessary checks to see if the expression +/// is valid as a standalone mappable expression. In the process, record all the +/// components of the expression. +static const Expr *checkMapClauseExpressionBase( + Sema &SemaRef, Expr *E, + OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, + OpenMPClauseKind CKind, bool NoDiagnose) { + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + MapBaseChecker Checker(SemaRef, CKind, CurComponents, NoDiagnose, ELoc, + ERange); + if (Checker.Visit(E->IgnoreParens())) + return Checker.getFoundBase(); + return nullptr; } // Return true if expression E associated with value VD has conflicts with other @@ -15520,9 +16994,11 @@ static bool checkMapConflicts( // variable in map clauses of the same construct. if (CurrentRegionOnly && (isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) || - isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) && + isa<OMPArraySectionExpr>(CI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(CI->getAssociatedExpression())) && (isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) || - isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) { + isa<OMPArraySectionExpr>(SI->getAssociatedExpression()) || + isa<OMPArrayShapingExpr>(SI->getAssociatedExpression()))) { SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), diag::err_omp_multiple_array_items_in_map_clause) << CI->getAssociatedExpression()->getSourceRange(); @@ -15554,6 +17030,9 @@ static bool checkMapConflicts( const Expr *E = OASE->getBase()->IgnoreParenImpCasts(); Type = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + } else if (const auto *OASE = dyn_cast<OMPArrayShapingExpr>( + SI->getAssociatedExpression())) { + Type = OASE->getBase()->getType()->getPointeeType(); } if (Type.isNull() || Type->isAnyPointerType() || checkArrayExpressionDoesNotReferToWholeSize( @@ -15916,10 +17395,15 @@ static void checkMappableExpressionList( Expr *SimpleExpr = RE->IgnoreParenCasts(); - if (!RE->IgnoreParenImpCasts()->isLValue()) { - SemaRef.Diag(ELoc, - diag::err_omp_expected_named_var_member_or_array_expression) - << RE->getSourceRange(); + if (!RE->isLValue()) { + if (SemaRef.getLangOpts().OpenMP < 50) { + SemaRef.Diag( + ELoc, diag::err_omp_expected_named_var_member_or_array_expression) + << RE->getSourceRange(); + } else { + SemaRef.Diag(ELoc, diag::err_omp_non_lvalue_in_map_or_motion_clauses) + << getOpenMPClauseName(CKind) << RE->getSourceRange(); + } continue; } @@ -16011,6 +17495,7 @@ static void checkMappableExpressionList( QualType Type; auto *ASE = dyn_cast<ArraySubscriptExpr>(VE->IgnoreParens()); auto *OASE = dyn_cast<OMPArraySectionExpr>(VE->IgnoreParens()); + auto *OAShE = dyn_cast<OMPArrayShapingExpr>(VE->IgnoreParens()); if (ASE) { Type = ASE->getType().getNonReferenceType(); } else if (OASE) { @@ -16021,6 +17506,8 @@ static void checkMappableExpressionList( else Type = BaseType->getPointeeType(); Type = Type.getNonReferenceType(); + } else if (OAShE) { + Type = OAShE->getBase()->getType()->getPointeeType(); } else { Type = VE->getType(); } @@ -16064,6 +17551,21 @@ static void checkMappableExpressionList( continue; } + // target, target data + // OpenMP 5.0 [2.12.2, Restrictions, p. 163] + // OpenMP 5.0 [2.12.5, Restrictions, p. 174] + // A map-type in a map clause must be to, from, tofrom or alloc + if ((DKind == OMPD_target_data || + isOpenMPTargetExecutionDirective(DKind)) && + !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_from || + MapType == OMPC_MAP_tofrom || MapType == OMPC_MAP_alloc)) { + SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) + << (IsMapTypeImplicit ? 1 : 0) + << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) + << getOpenMPDirectiveName(DKind); + continue; + } + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] // A list item cannot appear in both a map clause and a data-sharing // attribute clause on the same construct @@ -16124,7 +17626,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( OpenMPMapModifierKind Modifiers[] = {OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown, OMPC_MAP_MODIFIER_unknown}; - SourceLocation ModifiersLoc[OMPMapClause::NumberOfModifiers]; + SourceLocation ModifiersLoc[NumberOfOMPMapClauseModifiers]; // Process map-type-modifiers, flag errors for duplicate modifiers. unsigned Count = 0; @@ -16134,7 +17636,7 @@ OMPClause *Sema::ActOnOpenMPMapClause( Diag(MapTypeModifiersLoc[I], diag::err_omp_duplicate_map_type_modifier); continue; } - assert(Count < OMPMapClause::NumberOfModifiers && + assert(Count < NumberOfOMPMapClauseModifiers && "Modifiers exceed the allowed number of map type modifiers"); Modifiers[Count] = MapTypeModifiers[I]; ModifiersLoc[Count] = MapTypeModifiersLoc[I]; @@ -16678,6 +18180,69 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } +/// Tries to find omp_event_handle_t type. +static bool findOMPEventHandleT(Sema &S, SourceLocation Loc, + DSAStackTy *Stack) { + QualType OMPEventHandleT = Stack->getOMPEventHandleT(); + if (!OMPEventHandleT.isNull()) + return true; + IdentifierInfo *II = &S.PP.getIdentifierTable().get("omp_event_handle_t"); + ParsedType PT = S.getTypeName(*II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_event_handle_t"; + return false; + } + Stack->setOMPEventHandleT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + if (!Evt->isValueDependent() && !Evt->isTypeDependent() && + !Evt->isInstantiationDependent() && + !Evt->containsUnexpandedParameterPack()) { + if (!findOMPEventHandleT(*this, Evt->getExprLoc(), DSAStack)) + return nullptr; + // OpenMP 5.0, 2.10.1 task Construct. + // event-handle is a variable of the omp_event_handle_t type. + auto *Ref = dyn_cast<DeclRefExpr>(Evt->IgnoreParenImpCasts()); + if (!Ref) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 0 << Evt->getSourceRange(); + return nullptr; + } + auto *VD = dyn_cast_or_null<VarDecl>(Ref->getDecl()); + if (!VD) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 0 << Evt->getSourceRange(); + return nullptr; + } + if (!Context.hasSameUnqualifiedType(DSAStack->getOMPEventHandleT(), + VD->getType()) || + VD->getType().isConstant(Context)) { + Diag(Evt->getExprLoc(), diag::err_omp_var_expected) + << "omp_event_handle_t" << 1 << VD->getType() + << Evt->getSourceRange(); + return nullptr; + } + // OpenMP 5.0, 2.10.1 task Construct + // [detach clause]... The event-handle will be considered as if it was + // specified on a firstprivate clause. + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, /*FromParent=*/false); + if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_firstprivate && + DVar.RefExpr) { + Diag(Evt->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_firstprivate); + reportOriginalDsa(*this, DSAStack, VD, DVar); + return nullptr; + } + } + + return new (Context) OMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc); +} + OMPClause *Sema::ActOnOpenMPDistScheduleClause( OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, @@ -16758,7 +18323,8 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( } } else { bool isDefaultmapModifier = (M != OMPC_DEFAULTMAP_MODIFIER_unknown); - bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown); + bool isDefaultmapKind = (Kind != OMPC_DEFAULTMAP_unknown) || + (LangOpts.OpenMP >= 50 && KindLoc.isInvalid()); if (!isDefaultmapKind || !isDefaultmapModifier) { std::string ModifierValue = "'alloc', 'from', 'to', 'tofrom', " "'firstprivate', 'none', 'default'"; @@ -16786,7 +18352,14 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( return nullptr; } } - DSAStack->setDefaultDMAAttr(M, Kind, StartLoc); + if (Kind == OMPC_DEFAULTMAP_unknown) { + // Variable category is not specified - mark all categories. + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_aggregate, StartLoc); + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_scalar, StartLoc); + DSAStack->setDefaultDMAAttr(M, OMPC_DEFAULTMAP_pointer, StartLoc); + } else { + DSAStack->setDefaultDMAAttr(M, Kind, StartLoc); + } return new (Context) OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); @@ -16955,15 +18528,6 @@ void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D, Diag(FD->getLocation(), diag::note_defined_here) << FD; return; } - // Mark the function as must be emitted for the device. - Optional<OMPDeclareTargetDeclAttr::DevTypeTy> DevTy = - OMPDeclareTargetDeclAttr::getDeviceType(FD); - if (LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && - *DevTy != OMPDeclareTargetDeclAttr::DT_Host) - checkOpenMPDeviceFunction(IdLoc, FD, /*CheckForDelayedContext=*/false); - if (!LangOpts.OpenMPIsDevice && Res.hasValue() && IdLoc.isValid() && - *DevTy != OMPDeclareTargetDeclAttr::DT_NoHost) - checkOpenMPHostFunction(IdLoc, FD, /*CheckCaller=*/false); } if (auto *VD = dyn_cast<ValueDecl>(D)) { // Problem if any with var declared with incomplete type will be reported @@ -17109,6 +18673,58 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, MVLI.VarBaseDeclarations, MVLI.VarComponents); } +OMPClause *Sema::ActOnOpenMPUseDeviceAddrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs) { + MappableVarListInfo MVLI(VarList); + + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_device_addr clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { + // It will be analyzed later. + MVLI.ProcessedVarList.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + auto *VD = dyn_cast<VarDecl>(D); + + // If required, build a capture to implement the privatization initialized + // with the current list item value. + DeclRefExpr *Ref = nullptr; + if (!VD) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + MVLI.ProcessedVarList.push_back(VD ? RefExpr->IgnoreParens() : Ref); + + // We need to add a data sharing attribute for this variable to make sure it + // is correctly captured. A variable that shows up in a use_device_addr has + // similar properties of a first private variable. + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + + // Create a mappable component for the list item. List items in this clause + // only need a component. + MVLI.VarBaseDeclarations.push_back(D); + MVLI.VarComponents.emplace_back(); + Expr *Component = SimpleRefExpr; + if (VD && (isa<OMPArraySectionExpr>(RefExpr->IgnoreParenImpCasts()) || + isa<ArraySubscriptExpr>(RefExpr->IgnoreParenImpCasts()))) + Component = DefaultFunctionArrayLvalueConversion(SimpleRefExpr).get(); + MVLI.VarComponents.back().push_back( + OMPClauseMappableExprCommon::MappableComponent(Component, D)); + } + + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPUseDeviceAddrClause::Create(Context, Locs, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, const OMPVarListLocTy &Locs) { MappableVarListInfo MVLI(VarList); @@ -17248,6 +18864,8 @@ OMPClause *Sema::ActOnOpenMPAllocateClause( if (Vars.empty()) return nullptr; + if (Allocator) + DSAStack->addInnerAllocatorExpr(Allocator); return OMPAllocateClause::Create(Context, StartLoc, LParenLoc, Allocator, ColonLoc, EndLoc, Vars); } @@ -17290,3 +18908,266 @@ OMPClause *Sema::ActOnOpenMPNontemporalClause(ArrayRef<Expr *> VarList, return OMPNontemporalClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); } + +OMPClause *Sema::ActOnOpenMPInclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + const DSAStackTy::DSAVarData DVar = + DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + + if (DSAStack->getParentDirective() != OMPD_unknown) + DSAStack->markDeclAsUsedInScanDirective(D); + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPInclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +OMPClause *Sema::ActOnOpenMPExclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP nontemporal clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) + // It will be analyzed later. + Vars.push_back(RefExpr); + ValueDecl *D = Res.first; + if (!D) + continue; + + OpenMPDirectiveKind ParentDirective = DSAStack->getParentDirective(); + DSAStackTy::DSAVarData DVar; + if (ParentDirective != OMPD_unknown) + DVar = DSAStack->getTopDSA(D, /*FromParent=*/true); + // OpenMP 5.0, 2.9.6, scan Directive, Restrictions. + // A list item that appears in the inclusive or exclusive clause must appear + // in a reduction clause with the inscan modifier on the enclosing + // worksharing-loop, worksharing-loop SIMD, or simd construct. + if (ParentDirective == OMPD_unknown || DVar.CKind != OMPC_reduction || + DVar.Modifier != OMPC_REDUCTION_inscan) { + Diag(ELoc, diag::err_omp_inclusive_exclusive_not_reduction) + << RefExpr->getSourceRange(); + } else { + DSAStack->markDeclAsUsedInScanDirective(D); + } + Vars.push_back(RefExpr); + } + + if (Vars.empty()) + return nullptr; + + return OMPExclusiveClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars); +} + +/// Tries to find omp_alloctrait_t type. +static bool findOMPAlloctraitT(Sema &S, SourceLocation Loc, DSAStackTy *Stack) { + QualType OMPAlloctraitT = Stack->getOMPAlloctraitT(); + if (!OMPAlloctraitT.isNull()) + return true; + IdentifierInfo &II = S.PP.getIdentifierTable().get("omp_alloctrait_t"); + ParsedType PT = S.getTypeName(II, Loc, S.getCurScope()); + if (!PT.getAsOpaquePtr() || PT.get().isNull()) { + S.Diag(Loc, diag::err_omp_implied_type_not_found) << "omp_alloctrait_t"; + return false; + } + Stack->setOMPAlloctraitT(PT.get()); + return true; +} + +OMPClause *Sema::ActOnOpenMPUsesAllocatorClause( + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc, + ArrayRef<UsesAllocatorsData> Data) { + // OpenMP [2.12.5, target Construct] + // allocator is an identifier of omp_allocator_handle_t type. + if (!findOMPAllocatorHandleT(*this, StartLoc, DSAStack)) + return nullptr; + // OpenMP [2.12.5, target Construct] + // allocator-traits-array is an identifier of const omp_alloctrait_t * type. + if (llvm::any_of( + Data, + [](const UsesAllocatorsData &D) { return D.AllocatorTraits; }) && + !findOMPAlloctraitT(*this, StartLoc, DSAStack)) + return nullptr; + llvm::SmallSet<CanonicalDeclPtr<Decl>, 4> PredefinedAllocators; + for (int I = 0; I < OMPAllocateDeclAttr::OMPUserDefinedMemAlloc; ++I) { + auto AllocatorKind = static_cast<OMPAllocateDeclAttr::AllocatorTypeTy>(I); + StringRef Allocator = + OMPAllocateDeclAttr::ConvertAllocatorTypeTyToStr(AllocatorKind); + DeclarationName AllocatorName = &Context.Idents.get(Allocator); + PredefinedAllocators.insert(LookupSingleName( + TUScope, AllocatorName, StartLoc, Sema::LookupAnyName)); + } + + SmallVector<OMPUsesAllocatorsClause::Data, 4> NewData; + for (const UsesAllocatorsData &D : Data) { + Expr *AllocatorExpr = nullptr; + // Check allocator expression. + if (D.Allocator->isTypeDependent()) { + AllocatorExpr = D.Allocator; + } else { + // Traits were specified - need to assign new allocator to the specified + // allocator, so it must be an lvalue. + AllocatorExpr = D.Allocator->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(AllocatorExpr); + bool IsPredefinedAllocator = false; + if (DRE) + IsPredefinedAllocator = PredefinedAllocators.count(DRE->getDecl()); + if (!DRE || + !(Context.hasSameUnqualifiedType( + AllocatorExpr->getType(), DSAStack->getOMPAllocatorHandleT()) || + Context.typesAreCompatible(AllocatorExpr->getType(), + DSAStack->getOMPAllocatorHandleT(), + /*CompareUnqualified=*/true)) || + (!IsPredefinedAllocator && + (AllocatorExpr->getType().isConstant(Context) || + !AllocatorExpr->isLValue()))) { + Diag(D.Allocator->getExprLoc(), diag::err_omp_var_expected) + << "omp_allocator_handle_t" << (DRE ? 1 : 0) + << AllocatorExpr->getType() << D.Allocator->getSourceRange(); + continue; + } + // OpenMP [2.12.5, target Construct] + // Predefined allocators appearing in a uses_allocators clause cannot have + // traits specified. + if (IsPredefinedAllocator && D.AllocatorTraits) { + Diag(D.AllocatorTraits->getExprLoc(), + diag::err_omp_predefined_allocator_with_traits) + << D.AllocatorTraits->getSourceRange(); + Diag(D.Allocator->getExprLoc(), diag::note_omp_predefined_allocator) + << cast<NamedDecl>(DRE->getDecl())->getName() + << D.Allocator->getSourceRange(); + continue; + } + // OpenMP [2.12.5, target Construct] + // Non-predefined allocators appearing in a uses_allocators clause must + // have traits specified. + if (!IsPredefinedAllocator && !D.AllocatorTraits) { + Diag(D.Allocator->getExprLoc(), + diag::err_omp_nonpredefined_allocator_without_traits); + continue; + } + // No allocator traits - just convert it to rvalue. + if (!D.AllocatorTraits) + AllocatorExpr = DefaultLvalueConversion(AllocatorExpr).get(); + DSAStack->addUsesAllocatorsDecl( + DRE->getDecl(), + IsPredefinedAllocator + ? DSAStackTy::UsesAllocatorsDeclKind::PredefinedAllocator + : DSAStackTy::UsesAllocatorsDeclKind::UserDefinedAllocator); + } + Expr *AllocatorTraitsExpr = nullptr; + if (D.AllocatorTraits) { + if (D.AllocatorTraits->isTypeDependent()) { + AllocatorTraitsExpr = D.AllocatorTraits; + } else { + // OpenMP [2.12.5, target Construct] + // Arrays that contain allocator traits that appear in a uses_allocators + // clause must be constant arrays, have constant values and be defined + // in the same scope as the construct in which the clause appears. + AllocatorTraitsExpr = D.AllocatorTraits->IgnoreParenImpCasts(); + // Check that traits expr is a constant array. + QualType TraitTy; + if (const ArrayType *Ty = + AllocatorTraitsExpr->getType()->getAsArrayTypeUnsafe()) + if (const auto *ConstArrayTy = dyn_cast<ConstantArrayType>(Ty)) + TraitTy = ConstArrayTy->getElementType(); + if (TraitTy.isNull() || + !(Context.hasSameUnqualifiedType(TraitTy, + DSAStack->getOMPAlloctraitT()) || + Context.typesAreCompatible(TraitTy, DSAStack->getOMPAlloctraitT(), + /*CompareUnqualified=*/true))) { + Diag(D.AllocatorTraits->getExprLoc(), + diag::err_omp_expected_array_alloctraits) + << AllocatorTraitsExpr->getType(); + continue; + } + // Do not map by default allocator traits if it is a standalone + // variable. + if (auto *DRE = dyn_cast<DeclRefExpr>(AllocatorTraitsExpr)) + DSAStack->addUsesAllocatorsDecl( + DRE->getDecl(), + DSAStackTy::UsesAllocatorsDeclKind::AllocatorTrait); + } + } + OMPUsesAllocatorsClause::Data &NewD = NewData.emplace_back(); + NewD.Allocator = AllocatorExpr; + NewD.AllocatorTraits = AllocatorTraitsExpr; + NewD.LParenLoc = D.LParenLoc; + NewD.RParenLoc = D.RParenLoc; + } + return OMPUsesAllocatorsClause::Create(Context, StartLoc, LParenLoc, EndLoc, + NewData); +} + +OMPClause *Sema::ActOnOpenMPAffinityClause( + SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, ArrayRef<Expr *> Locators) { + SmallVector<Expr *, 8> Vars; + for (Expr *RefExpr : Locators) { + assert(RefExpr && "NULL expr in OpenMP shared clause."); + if (isa<DependentScopeDeclRefExpr>(RefExpr) || RefExpr->isTypeDependent()) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } + + SourceLocation ELoc = RefExpr->getExprLoc(); + Expr *SimpleExpr = RefExpr->IgnoreParenImpCasts(); + + if (!SimpleExpr->isLValue()) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << 1 << 0 << RefExpr->getSourceRange(); + continue; + } + + ExprResult Res; + { + Sema::TentativeAnalysisScope Trap(*this); + Res = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, SimpleExpr); + } + if (!Res.isUsable() && !isa<OMPArraySectionExpr>(SimpleExpr) && + !isa<OMPArrayShapingExpr>(SimpleExpr)) { + Diag(ELoc, diag::err_omp_expected_addressable_lvalue_or_array_item) + << 1 << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(SimpleExpr); + } + + return OMPAffinityClause::Create(Context, StartLoc, LParenLoc, ColonLoc, + EndLoc, Modifier, Vars); +} diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 0fd932fac970..8635397f4806 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -10,10 +10,10 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Overload.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DependenceFlags.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" @@ -21,9 +21,11 @@ #include "clang/Basic/Diagnostic.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/PartialDiagnostic.h" +#include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/Overload.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -38,6 +40,8 @@ using namespace clang; using namespace sema; +using AllowedExplicit = Sema::AllowedExplicit; + static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { return llvm::any_of(FD->parameters(), [](const ParmVarDecl *P) { return P->hasAttr<PassObjectSizeAttr>(); @@ -91,10 +95,9 @@ static OverloadingResult IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence& User, OverloadCandidateSet& Conversions, - bool AllowExplicit, + AllowedExplicit AllowExplicit, bool AllowObjCConversionOnExplicit); - static ImplicitConversionSequence::CompareKind CompareStandardConversionSequences(Sema &S, SourceLocation Loc, const StandardConversionSequence& SCS1, @@ -229,7 +232,6 @@ bool StandardConversionSequence::isPointerConversionToBool() const { getFromType()->isMemberPointerType() || getFromType()->isObjCObjectPointerType() || getFromType()->isBlockPointerType() || - getFromType()->isNullPtrType() || First == ICK_Array_To_Pointer || First == ICK_Function_To_Pointer)) return true; @@ -327,9 +329,8 @@ NarrowingKind StandardConversionSequence::getNarrowingKind( goto FloatingIntegralConversion; if (FromType->isIntegralOrUnscopedEnumerationType()) goto IntegralConversion; - // Boolean conversions can be from pointers and pointers to members - // [conv.bool], and those aren't considered narrowing conversions. - return NK_Not_Narrowing; + // -- from a pointer type or pointer-to-member type to bool, or + return NK_Type_Narrowing; // -- from a floating-point type to an integer type, or // @@ -1317,7 +1318,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, static ImplicitConversionSequence TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, + AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion, @@ -1420,7 +1421,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, static ImplicitConversionSequence TryImplicitConversion(Sema &S, Expr *From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, + AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion, @@ -1475,13 +1476,12 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType, ImplicitConversionSequence Sema::TryImplicitConversion(Expr *From, QualType ToType, bool SuppressUserConversions, - bool AllowExplicit, + AllowedExplicit AllowExplicit, bool InOverloadResolution, bool CStyle, bool AllowObjCWritebackConversion) { - return ::TryImplicitConversion(*this, From, ToType, - SuppressUserConversions, AllowExplicit, - InOverloadResolution, CStyle, + return ::TryImplicitConversion(*this, From, ToType, SuppressUserConversions, + AllowExplicit, InOverloadResolution, CStyle, AllowObjCWritebackConversion, /*AllowObjCConversionOnExplicit=*/false); } @@ -1514,10 +1514,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From->getType(), From); ICS = ::TryImplicitConversion(*this, From, ToType, /*SuppressUserConversions=*/false, - AllowExplicit, + AllowExplicit ? AllowedExplicit::All + : AllowedExplicit::None, /*InOverloadResolution=*/false, - /*CStyle=*/false, - AllowObjCWritebackConversion, + /*CStyle=*/false, AllowObjCWritebackConversion, /*AllowObjCConversionOnExplicit=*/false); return PerformImplicitConversion(From, ToType, ICS, Action); } @@ -1653,9 +1653,13 @@ static bool IsVectorConversion(Sema &S, QualType FromType, // 1)vector types are equivalent AltiVec and GCC vector types // 2)lax vector conversions are permitted and the vector types are of the // same size + // 3)the destination type does not have the ARM MVE strict-polymorphism + // attribute, which inhibits lax vector conversion for overload resolution + // only if (ToType->isVectorType() && FromType->isVectorType()) { if (S.Context.areCompatibleVectorTypes(FromType, ToType) || - S.isLaxVectorConversion(FromType, ToType)) { + (S.isLaxVectorConversion(FromType, ToType) && + !ToType->hasAttr(attr::ArmMveStrictPolymorphism))) { ICK = ICK_Vector_Conversion; return true; } @@ -1844,8 +1848,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, (FromType->isArithmeticType() || FromType->isAnyPointerType() || FromType->isBlockPointerType() || - FromType->isMemberPointerType() || - FromType->isNullPtrType())) { + FromType->isMemberPointerType())) { // Boolean conversions (C++ 4.12). SCS.Second = ICK_Boolean_Conversion; FromType = S.Context.BoolTy; @@ -1867,6 +1870,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // FIXME: disable conversions between long double and __float128 if // their representation is different until there is back end support // We of course allow this conversion if long double is really double. + + // Conversions between bfloat and other floats are not permitted. + if (FromType == S.Context.BFloat16Ty || ToType == S.Context.BFloat16Ty) + return false; if (&S.Context.getFloatTypeSemantics(FromType) != &S.Context.getFloatTypeSemantics(ToType)) { bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty && @@ -1885,6 +1892,10 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, ToType->isIntegralType(S.Context)) || (FromType->isIntegralOrUnscopedEnumerationType() && ToType->isRealFloatingType())) { + // Conversions between bfloat and int are not permitted. + if (FromType->isBFloat16Type() || ToType->isBFloat16Type()) + return false; + // Floating-integral conversions (C++ 4.9). SCS.Second = ICK_Floating_Integral; FromType = ToType.getUnqualifiedType(); @@ -3000,13 +3011,13 @@ bool Sema::CheckPointerConversion(Expr *From, QualType ToType, // We must have a derived-to-base conversion. Check an // ambiguous or inaccessible conversion. unsigned InaccessibleID = 0; - unsigned AmbigiousID = 0; + unsigned AmbiguousID = 0; if (Diagnose) { InaccessibleID = diag::err_upcast_to_inaccessible_base; - AmbigiousID = diag::err_ambiguous_derived_to_base_conv; + AmbiguousID = diag::err_ambiguous_derived_to_base_conv; } if (CheckDerivedToBaseConversion( - FromPointeeType, ToPointeeType, InaccessibleID, AmbigiousID, + FromPointeeType, ToPointeeType, InaccessibleID, AmbiguousID, From->getExprLoc(), From->getSourceRange(), DeclarationName(), &BasePath, IgnoreBaseAccess)) return true; @@ -3176,7 +3187,7 @@ static bool isNonTrivialObjCLifetimeConversion(Qualifiers FromQuals, /// FromType and \p ToType is permissible, given knowledge about whether every /// outer layer is const-qualified. static bool isQualificationConversionStep(QualType FromType, QualType ToType, - bool CStyle, + bool CStyle, bool IsTopLevel, bool &PreviousToQualsIncludeConst, bool &ObjCLifetimeConversion) { Qualifiers FromQuals = FromType.getQualifiers(); @@ -3213,11 +3224,15 @@ static bool isQualificationConversionStep(QualType FromType, QualType ToType, if (!CStyle && !ToQuals.compatiblyIncludes(FromQuals)) return false; - // For a C-style cast, just require the address spaces to overlap. - // FIXME: Does "superset" also imply the representation of a pointer is the - // same? We're assuming that it does here and in compatiblyIncludes. - if (CStyle && !ToQuals.isAddressSpaceSupersetOf(FromQuals) && - !FromQuals.isAddressSpaceSupersetOf(ToQuals)) + // If address spaces mismatch: + // - in top level it is only valid to convert to addr space that is a + // superset in all cases apart from C-style casts where we allow + // conversions between overlapping address spaces. + // - in non-top levels it is not a valid conversion. + if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() && + (!IsTopLevel || + !(ToQuals.isAddressSpaceSupersetOf(FromQuals) || + (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))) return false; // -- if the cv 1,j and cv 2,j are different, then const is in @@ -3258,9 +3273,9 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, bool PreviousToQualsIncludeConst = true; bool UnwrappedAnyPointer = false; while (Context.UnwrapSimilarTypes(FromType, ToType)) { - if (!isQualificationConversionStep(FromType, ToType, CStyle, - PreviousToQualsIncludeConst, - ObjCLifetimeConversion)) + if (!isQualificationConversionStep( + FromType, ToType, CStyle, !UnwrappedAnyPointer, + PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return false; UnwrappedAnyPointer = true; } @@ -3393,9 +3408,10 @@ static OverloadingResult IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence &User, OverloadCandidateSet &CandidateSet, - bool AllowExplicit, + AllowedExplicit AllowExplicit, bool AllowObjCConversionOnExplicit) { - assert(AllowExplicit || !AllowObjCConversionOnExplicit); + assert(AllowExplicit != AllowedExplicit::None || + !AllowObjCConversionOnExplicit); CandidateSet.clear(OverloadCandidateSet::CSK_InitByUserDefinedConversion); // Whether we will only visit constructors. @@ -3428,7 +3444,8 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (InitListExpr *InitList = dyn_cast<InitListExpr>(From)) { // But first, see if there is an init-list-constructor that will work. OverloadingResult Result = IsInitializerListConstructorConversion( - S, From, ToType, ToRecordDecl, User, CandidateSet, AllowExplicit); + S, From, ToType, ToRecordDecl, User, CandidateSet, + AllowExplicit == AllowedExplicit::All); if (Result != OR_No_Viable_Function) return Result; // Never mind. @@ -3467,14 +3484,16 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs), CandidateSet, SuppressUserConversions, - /*PartialOverloading*/ false, AllowExplicit); + /*PartialOverloading*/ false, + AllowExplicit == AllowedExplicit::All); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, llvm::makeArrayRef(Args, NumArgs), CandidateSet, SuppressUserConversions, - /*PartialOverloading*/ false, AllowExplicit); + /*PartialOverloading*/ false, + AllowExplicit == AllowedExplicit::All); } } } @@ -3507,11 +3526,12 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, if (ConvTemplate) S.AddTemplateConversionCandidate( ConvTemplate, FoundDecl, ActingContext, From, ToType, - CandidateSet, AllowObjCConversionOnExplicit, AllowExplicit); + CandidateSet, AllowObjCConversionOnExplicit, + AllowExplicit != AllowedExplicit::None); else - S.AddConversionCandidate( - Conv, FoundDecl, ActingContext, From, ToType, CandidateSet, - AllowObjCConversionOnExplicit, AllowExplicit); + S.AddConversionCandidate(Conv, FoundDecl, ActingContext, From, ToType, + CandidateSet, AllowObjCConversionOnExplicit, + AllowExplicit != AllowedExplicit::None); } } } @@ -3597,7 +3617,7 @@ Sema::DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType) { OverloadCandidateSet::CSK_Normal); OverloadingResult OvResult = IsUserDefinedConversion(*this, From, ToType, ICS.UserDefined, - CandidateSet, false, false); + CandidateSet, AllowedExplicit::None, false); if (!(OvResult == OR_Ambiguous || (OvResult == OR_No_Viable_Function && !CandidateSet.empty()))) @@ -4499,7 +4519,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, // If we find a qualifier mismatch, the types are not reference-compatible, // but are still be reference-related if they're similar. bool ObjCLifetimeConversion = false; - if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, + if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel, PreviousToQualsIncludeConst, ObjCLifetimeConversion)) return (ConvertedReferent || Context.hasSimilarType(T1, T2)) @@ -4689,7 +4709,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, Sema::ReferenceConversions::NestedQualification) ? ICK_Qualification : ICK_Identity; - ICS.Standard.FromTypePtr = T2.getAsOpaquePtr(); + ICS.Standard.setFromType(T2); ICS.Standard.setToType(0, T2); ICS.Standard.setToType(1, T1); ICS.Standard.setToType(2, T1); @@ -4858,7 +4878,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // cv-qualification is subsumed by the initialization itself // and does not constitute a conversion. ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions, - /*AllowExplicit=*/false, + AllowedExplicit::None, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, @@ -5027,7 +5047,7 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, if (ToType->isRecordType() && !ToType->isAggregateType()) { // This function can deal with initializer lists. return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions, - /*AllowExplicit=*/false, + AllowedExplicit::None, InOverloadResolution, /*CStyle=*/false, AllowObjCWritebackConversion, /*AllowObjCConversionOnExplicit=*/false); @@ -5179,7 +5199,7 @@ TryCopyInitialization(Sema &S, Expr *From, QualType ToType, return TryImplicitConversion(S, From, ToType, SuppressUserConversions, - /*AllowExplicit=*/false, + AllowedExplicit::None, InOverloadResolution, /*CStyle=*/false, AllowObjCWritebackConversion, @@ -5425,9 +5445,20 @@ Sema::PerformObjectArgumentInitialization(Expr *From, /// expression From to bool (C++0x [conv]p3). static ImplicitConversionSequence TryContextuallyConvertToBool(Sema &S, Expr *From) { + // C++ [dcl.init]/17.8: + // - Otherwise, if the initialization is direct-initialization, the source + // type is std::nullptr_t, and the destination type is bool, the initial + // value of the object being initialized is false. + if (From->getType()->isNullPtrType()) + return ImplicitConversionSequence::getNullptrToBool(From->getType(), + S.Context.BoolTy, + From->isGLValue()); + + // All other direct-initialization of bool is equivalent to an implicit + // conversion to bool in which explicit conversions are permitted. return TryImplicitConversion(S, From, S.Context.BoolTy, /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, + AllowedExplicit::Conversions, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, @@ -5699,7 +5730,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { = TryImplicitConversion(S, From, Ty, // FIXME: Are these flags correct? /*SuppressUserConversions=*/false, - /*AllowExplicit=*/true, + AllowedExplicit::Conversions, /*InOverloadResolution=*/false, /*CStyle=*/false, /*AllowObjCWritebackConversion=*/false, @@ -6291,9 +6322,9 @@ void Sema::AddOverloadCandidate( return; } - if (Expr *RequiresClause = Function->getTrailingRequiresClause()) { + if (Function->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Function, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6333,7 +6364,8 @@ void Sema::AddOverloadCandidate( } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Function, Args)) { + if (EnableIfAttr *FailedAttr = + CheckEnableIf(Function, CandidateSet.getLocation(), Args)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -6439,11 +6471,10 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, return nullptr; } -static bool -convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg, - ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap, - bool MissingImplicitThis, Expr *&ConvertedThis, - SmallVectorImpl<Expr *> &ConvertedArgs) { +static bool convertArgsForAvailabilityChecks( + Sema &S, FunctionDecl *Function, Expr *ThisArg, SourceLocation CallLoc, + ArrayRef<Expr *> Args, Sema::SFINAETrap &Trap, bool MissingImplicitThis, + Expr *&ConvertedThis, SmallVectorImpl<Expr *> &ConvertedArgs) { if (ThisArg) { CXXMethodDecl *Method = cast<CXXMethodDecl>(Function); assert(!isa<CXXConstructorDecl>(Method) && @@ -6488,17 +6519,9 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg, if (!Function->isVariadic() && Args.size() < Function->getNumParams()) { for (unsigned i = Args.size(), e = Function->getNumParams(); i != e; ++i) { ParmVarDecl *P = Function->getParamDecl(i); - Expr *DefArg = P->hasUninstantiatedDefaultArg() - ? P->getUninstantiatedDefaultArg() - : P->getDefaultArg(); - // This can only happen in code completion, i.e. when PartialOverloading - // is true. - if (!DefArg) + if (!P->hasDefaultArg()) return false; - ExprResult R = - S.PerformCopyInitialization(InitializedEntity::InitializeParameter( - S.Context, Function->getParamDecl(i)), - SourceLocation(), DefArg); + ExprResult R = S.BuildCXXDefaultArgExpr(CallLoc, Function, P); if (R.isInvalid()) return false; ConvertedArgs.push_back(R.get()); @@ -6510,7 +6533,9 @@ convertArgsForAvailabilityChecks(Sema &S, FunctionDecl *Function, Expr *ThisArg, return true; } -EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, +EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, + SourceLocation CallLoc, + ArrayRef<Expr *> Args, bool MissingImplicitThis) { auto EnableIfAttrs = Function->specific_attrs<EnableIfAttr>(); if (EnableIfAttrs.begin() == EnableIfAttrs.end()) @@ -6521,7 +6546,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, // FIXME: We should look into making enable_if late-parsed. Expr *DiscardedThis; if (!convertArgsForAvailabilityChecks( - *this, Function, /*ThisArg=*/nullptr, Args, Trap, + *this, Function, /*ThisArg=*/nullptr, CallLoc, Args, Trap, /*MissingImplicitThis=*/true, DiscardedThis, ConvertedArgs)) return *EnableIfAttrs.begin(); @@ -6808,9 +6833,9 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, return; } - if (Expr *RequiresClause = Method->getTrailingRequiresClause()) { + if (Method->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Method, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -6851,7 +6876,8 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Method, Args, true)) { + if (EnableIfAttr *FailedAttr = + CheckEnableIf(Method, CandidateSet.getLocation(), Args, true)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -7204,10 +7230,9 @@ void Sema::AddConversionCandidate( return; } - Expr *RequiresClause = Conversion->getTrailingRequiresClause(); - if (RequiresClause) { + if (Conversion->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (CheckConstraintSatisfaction(RequiresClause, Satisfaction) || + if (CheckFunctionConstraints(Conversion, Satisfaction) || !Satisfaction.IsSatisfied) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_constraints_not_satisfied; @@ -7305,7 +7330,8 @@ void Sema::AddConversionCandidate( "Can only end up with a standard conversion sequence or failure"); } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { + if (EnableIfAttr *FailedAttr = + CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -7475,7 +7501,8 @@ void Sema::AddSurrogateCandidate(CXXConversionDecl *Conversion, } } - if (EnableIfAttr *FailedAttr = CheckEnableIf(Conversion, None)) { + if (EnableIfAttr *FailedAttr = + CheckEnableIf(Conversion, CandidateSet.getLocation(), None)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_enable_if; Candidate.DeductionFailure.Data = FailedAttr; @@ -7665,6 +7692,10 @@ class BuiltinCandidateTypeSet { /// candidates. TypeSet VectorTypes; + /// The set of matrix types that will be used in the built-in + /// candidates. + TypeSet MatrixTypes; + /// A flag indicating non-record types are viable candidates bool HasNonRecordTypes; @@ -7722,9 +7753,11 @@ public: /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } - iterator vector_begin() { return VectorTypes.begin(); } - iterator vector_end() { return VectorTypes.end(); } + llvm::iterator_range<iterator> vector_types() { return VectorTypes; } + + llvm::iterator_range<iterator> matrix_types() { return MatrixTypes; } + bool containsMatrixType(QualType Ty) const { return MatrixTypes.count(Ty); } bool hasNonRecordTypes() { return HasNonRecordTypes; } bool hasArithmeticOrEnumeralTypes() { return HasArithmeticOrEnumeralTypes; } bool hasNullPtrType() const { return HasNullPtrType; } @@ -7899,6 +7932,11 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // extension. HasArithmeticOrEnumeralTypes = true; VectorTypes.insert(Ty); + } else if (Ty->isMatrixType()) { + // Similar to vector types, we treat vector types as arithmetic types in + // many contexts as an extension. + HasArithmeticOrEnumeralTypes = true; + MatrixTypes.insert(Ty); } else if (Ty->isNullPtrType()) { HasNullPtrType = true; } else if (AllowUserConversions && TyRec) { @@ -8127,6 +8165,13 @@ class BuiltinOperatorOverloadBuilder { } + /// Helper to add an overload candidate for a binary builtin with types \p L + /// and \p R. + void AddCandidate(QualType L, QualType R) { + QualType LandR[2] = {L, R}; + S.AddBuiltinCandidate(LandR, Args, CandidateSet); + } + public: BuiltinOperatorOverloadBuilder( Sema &S, ArrayRef<Expr *> Args, @@ -8254,13 +8299,8 @@ public: } // Extension: We also add these operators for vector types. - for (BuiltinCandidateTypeSet::iterator - Vec = CandidateTypes[0].vector_begin(), - VecEnd = CandidateTypes[0].vector_end(); - Vec != VecEnd; ++Vec) { - QualType VecTy = *Vec; + for (QualType VecTy : CandidateTypes[0].vector_types()) S.AddBuiltinCandidate(&VecTy, Args, CandidateSet); - } } // C++ [over.built]p8: @@ -8294,13 +8334,8 @@ public: } // Extension: We also add this operator for vector types. - for (BuiltinCandidateTypeSet::iterator - Vec = CandidateTypes[0].vector_begin(), - VecEnd = CandidateTypes[0].vector_end(); - Vec != VecEnd; ++Vec) { - QualType VecTy = *Vec; + for (QualType VecTy : CandidateTypes[0].vector_types()) S.AddBuiltinCandidate(&VecTy, Args, CandidateSet); - } } // C++ [over.match.oper]p16: @@ -8380,7 +8415,7 @@ public: // We interpret "same parameter-type-list" as applying to the // "synthesized candidate, with the order of the two parameters // reversed", not to the original function. - bool Reversed = C->RewriteKind & CRK_Reversed; + bool Reversed = C->isReversed(); QualType FirstParamType = C->Function->getParamDecl(Reversed ? 1 : 0) ->getType() .getUnqualifiedType(); @@ -8531,17 +8566,31 @@ public: // Extension: Add the binary operators ==, !=, <, <=, >=, >, *, /, and the // conditional operator for vector types. - for (BuiltinCandidateTypeSet::iterator - Vec1 = CandidateTypes[0].vector_begin(), - Vec1End = CandidateTypes[0].vector_end(); - Vec1 != Vec1End; ++Vec1) { - for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes[1].vector_begin(), - Vec2End = CandidateTypes[1].vector_end(); - Vec2 != Vec2End; ++Vec2) { - QualType LandR[2] = { *Vec1, *Vec2 }; + for (QualType Vec1Ty : CandidateTypes[0].vector_types()) + for (QualType Vec2Ty : CandidateTypes[1].vector_types()) { + QualType LandR[2] = {Vec1Ty, Vec2Ty}; S.AddBuiltinCandidate(LandR, Args, CandidateSet); } + } + + /// Add binary operator overloads for each candidate matrix type M1, M2: + /// * (M1, M1) -> M1 + /// * (M1, M1.getElementType()) -> M1 + /// * (M2.getElementType(), M2) -> M2 + /// * (M2, M2) -> M2 // Only if M2 is not part of CandidateTypes[0]. + void addMatrixBinaryArithmeticOverloads() { + if (!HasArithmeticOrEnumeralCandidateType) + return; + + for (QualType M1 : CandidateTypes[0].matrix_types()) { + AddCandidate(M1, cast<MatrixType>(M1)->getElementType()); + AddCandidate(M1, M1); + } + + for (QualType M2 : CandidateTypes[1].matrix_types()) { + AddCandidate(cast<MatrixType>(M2)->getElementType(), M2); + if (!CandidateTypes[0].containsMatrixType(M2)) + AddCandidate(M2, M2); } } @@ -8802,30 +8851,23 @@ public: } // Extension: Add the binary operators =, +=, -=, *=, /= for vector types. - for (BuiltinCandidateTypeSet::iterator - Vec1 = CandidateTypes[0].vector_begin(), - Vec1End = CandidateTypes[0].vector_end(); - Vec1 != Vec1End; ++Vec1) { - for (BuiltinCandidateTypeSet::iterator - Vec2 = CandidateTypes[1].vector_begin(), - Vec2End = CandidateTypes[1].vector_end(); - Vec2 != Vec2End; ++Vec2) { + for (QualType Vec1Ty : CandidateTypes[0].vector_types()) + for (QualType Vec2Ty : CandidateTypes[0].vector_types()) { QualType ParamTypes[2]; - ParamTypes[1] = *Vec2; + ParamTypes[1] = Vec2Ty; // Add this built-in operator as a candidate (VQ is empty). - ParamTypes[0] = S.Context.getLValueReferenceType(*Vec1); + ParamTypes[0] = S.Context.getLValueReferenceType(Vec1Ty); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/isEqualOp); // Add this built-in operator as a candidate (VQ is 'volatile'). if (VisibleTypeConversionsQuals.hasVolatile()) { - ParamTypes[0] = S.Context.getVolatileType(*Vec1); + ParamTypes[0] = S.Context.getVolatileType(Vec1Ty); ParamTypes[0] = S.Context.getLValueReferenceType(ParamTypes[0]); S.AddBuiltinCandidate(ParamTypes, Args, CandidateSet, /*IsAssignmentOperator=*/isEqualOp); } } - } } // C++ [over.built]p22: @@ -9118,14 +9160,17 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, } else { OpBuilder.addBinaryPlusOrMinusPointerOverloads(Op); OpBuilder.addGenericBinaryArithmeticOverloads(); + OpBuilder.addMatrixBinaryArithmeticOverloads(); } break; case OO_Star: // '*' is either unary or binary if (Args.size() == 1) OpBuilder.addUnaryStarPointerOverloads(); - else + else { OpBuilder.addGenericBinaryArithmeticOverloads(); + OpBuilder.addMatrixBinaryArithmeticOverloads(); + } break; case OO_Slash: @@ -9270,17 +9315,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, if (ExplicitTemplateArgs) continue; - AddOverloadCandidate(FD, FoundDecl, Args, CandidateSet, - /*SuppressUserConversions=*/false, PartialOverloading, - /*AllowExplicit*/ true, - /*AllowExplicitConversions*/ false, - ADLCallKind::UsesADL); + AddOverloadCandidate( + FD, FoundDecl, Args, CandidateSet, /*SuppressUserConversions=*/false, + PartialOverloading, /*AllowExplicit=*/true, + /*AllowExplicitConversions=*/false, ADLCallKind::UsesADL); + if (CandidateSet.getRewriteInfo().shouldAddReversed(Context, FD)) { + AddOverloadCandidate( + FD, FoundDecl, {Args[1], Args[0]}, CandidateSet, + /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit=*/true, /*AllowExplicitConversions=*/false, + ADLCallKind::UsesADL, None, OverloadCandidateParamOrder::Reversed); + } } else { + auto *FTD = cast<FunctionTemplateDecl>(*I); AddTemplateOverloadCandidate( - cast<FunctionTemplateDecl>(*I), FoundDecl, ExplicitTemplateArgs, Args, - CandidateSet, + FTD, FoundDecl, ExplicitTemplateArgs, Args, CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, - /*AllowExplicit*/true, ADLCallKind::UsesADL); + /*AllowExplicit=*/true, ADLCallKind::UsesADL); + if (CandidateSet.getRewriteInfo().shouldAddReversed( + Context, FTD->getTemplatedDecl())) { + AddTemplateOverloadCandidate( + FTD, FoundDecl, ExplicitTemplateArgs, {Args[1], Args[0]}, + CandidateSet, /*SuppressUserConversions=*/false, PartialOverloading, + /*AllowExplicit=*/true, ADLCallKind::UsesADL, + OverloadCandidateParamOrder::Reversed); + } } } } @@ -9338,16 +9397,22 @@ static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, return Comparison::Equal; } -static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1, - const OverloadCandidate &Cand2) { +static Comparison +isBetterMultiversionCandidate(const OverloadCandidate &Cand1, + const OverloadCandidate &Cand2) { if (!Cand1.Function || !Cand1.Function->isMultiVersion() || !Cand2.Function || !Cand2.Function->isMultiVersion()) - return false; + return Comparison::Equal; - // If Cand1 is invalid, it cannot be a better match, if Cand2 is invalid, this - // is obviously better. - if (Cand1.Function->isInvalidDecl()) return false; - if (Cand2.Function->isInvalidDecl()) return true; + // If both are invalid, they are equal. If one of them is invalid, the other + // is better. + if (Cand1.Function->isInvalidDecl()) { + if (Cand2.Function->isInvalidDecl()) + return Comparison::Equal; + return Comparison::Worse; + } + if (Cand2.Function->isInvalidDecl()) + return Comparison::Better; // If this is a cpu_dispatch/cpu_specific multiversion situation, prefer // cpu_dispatch, else arbitrarily based on the identifiers. @@ -9357,16 +9422,18 @@ static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1, const auto *Cand2CPUSpec = Cand2.Function->getAttr<CPUSpecificAttr>(); if (!Cand1CPUDisp && !Cand2CPUDisp && !Cand1CPUSpec && !Cand2CPUSpec) - return false; + return Comparison::Equal; if (Cand1CPUDisp && !Cand2CPUDisp) - return true; + return Comparison::Better; if (Cand2CPUDisp && !Cand1CPUDisp) - return false; + return Comparison::Worse; if (Cand1CPUSpec && Cand2CPUSpec) { if (Cand1CPUSpec->cpus_size() != Cand2CPUSpec->cpus_size()) - return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size(); + return Cand1CPUSpec->cpus_size() < Cand2CPUSpec->cpus_size() + ? Comparison::Better + : Comparison::Worse; std::pair<CPUSpecificAttr::cpus_iterator, CPUSpecificAttr::cpus_iterator> FirstDiff = std::mismatch( @@ -9379,11 +9446,56 @@ static bool isBetterMultiversionCandidate(const OverloadCandidate &Cand1, assert(FirstDiff.first != Cand1CPUSpec->cpus_end() && "Two different cpu-specific versions should not have the same " "identifier list, otherwise they'd be the same decl!"); - return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName(); + return (*FirstDiff.first)->getName() < (*FirstDiff.second)->getName() + ? Comparison::Better + : Comparison::Worse; } llvm_unreachable("No way to get here unless both had cpu_dispatch"); } +/// Compute the type of the implicit object parameter for the given function, +/// if any. Returns None if there is no implicit object parameter, and a null +/// QualType if there is a 'matches anything' implicit object parameter. +static Optional<QualType> getImplicitObjectParamType(ASTContext &Context, + const FunctionDecl *F) { + if (!isa<CXXMethodDecl>(F) || isa<CXXConstructorDecl>(F)) + return llvm::None; + + auto *M = cast<CXXMethodDecl>(F); + // Static member functions' object parameters match all types. + if (M->isStatic()) + return QualType(); + + QualType T = M->getThisObjectType(); + if (M->getRefQualifier() == RQ_RValue) + return Context.getRValueReferenceType(T); + return Context.getLValueReferenceType(T); +} + +static bool haveSameParameterTypes(ASTContext &Context, const FunctionDecl *F1, + const FunctionDecl *F2, unsigned NumParams) { + if (declaresSameEntity(F1, F2)) + return true; + + auto NextParam = [&](const FunctionDecl *F, unsigned &I, bool First) { + if (First) { + if (Optional<QualType> T = getImplicitObjectParamType(Context, F)) + return *T; + } + assert(I < F->getNumParams()); + return F->getParamDecl(I++)->getType(); + }; + + unsigned I1 = 0, I2 = 0; + for (unsigned I = 0; I != NumParams; ++I) { + QualType T1 = NextParam(F1, I1, I == 0); + QualType T2 = NextParam(F2, I2, I == 0); + if (!T1.isNull() && !T1.isNull() && !Context.hasSameUnqualifiedType(T1, T2)) + return false; + } + return true; +} + /// isBetterOverloadCandidate - Determines whether the first overload /// candidate is a better candidate than the second (C++ 13.3.3p1). bool clang::isBetterOverloadCandidate( @@ -9451,18 +9563,20 @@ bool clang::isBetterOverloadCandidate( break; case ImplicitConversionSequence::Worse: - if (Cand1.Function && Cand1.Function == Cand2.Function && - (Cand2.RewriteKind & CRK_Reversed) != 0) { + if (Cand1.Function && Cand2.Function && + Cand1.isReversed() != Cand2.isReversed() && + haveSameParameterTypes(S.Context, Cand1.Function, Cand2.Function, + NumArgs)) { // Work around large-scale breakage caused by considering reversed // forms of operator== in C++20: // - // When comparing a function against its reversed form, if we have a - // better conversion for one argument and a worse conversion for the - // other, we prefer the non-reversed form. + // When comparing a function against a reversed function with the same + // parameter types, if we have a better conversion for one argument and + // a worse conversion for the other, the implicit conversion sequences + // are treated as being equally good. // - // This prevents a conversion function from being considered ambiguous - // with its own reversed form in various where it's only incidentally - // heterogeneous. + // This prevents a comparison function from being considered ambiguous + // with a reversed form that is written in the same way. // // We diagnose this as an extension from CreateOverloadedBinOp. HasWorseConversion = true; @@ -9480,10 +9594,8 @@ bool clang::isBetterOverloadCandidate( // -- for some argument j, ICSj(F1) is a better conversion sequence than // ICSj(F2), or, if not that, - if (HasBetterConversion) + if (HasBetterConversion && !HasWorseConversion) return true; - if (HasWorseConversion) - return false; // -- the context is an initialization by user-defined conversion // (see 8.5, 13.3.1.5) and the standard conversion sequence @@ -9540,14 +9652,13 @@ bool clang::isBetterOverloadCandidate( // according to the partial ordering rules described in 14.5.5.2, or, // if not that, if (Cand1IsSpecialization && Cand2IsSpecialization) { - if (FunctionTemplateDecl *BetterTemplate - = S.getMoreSpecializedTemplate(Cand1.Function->getPrimaryTemplate(), - Cand2.Function->getPrimaryTemplate(), - Loc, - isa<CXXConversionDecl>(Cand1.Function)? TPOC_Conversion - : TPOC_Call, - Cand1.ExplicitCallArguments, - Cand2.ExplicitCallArguments)) + if (FunctionTemplateDecl *BetterTemplate = S.getMoreSpecializedTemplate( + Cand1.Function->getPrimaryTemplate(), + Cand2.Function->getPrimaryTemplate(), Loc, + isa<CXXConversionDecl>(Cand1.Function) ? TPOC_Conversion + : TPOC_Call, + Cand1.ExplicitCallArguments, Cand2.ExplicitCallArguments, + Cand1.isReversed() ^ Cand2.isReversed())) return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } @@ -9566,17 +9677,15 @@ bool clang::isBetterOverloadCandidate( if (RC1 && RC2) { bool AtLeastAsConstrained1, AtLeastAsConstrained2; if (S.IsAtLeastAsConstrained(Cand1.Function, {RC1}, Cand2.Function, - {RC2}, AtLeastAsConstrained1)) - return false; - if (!AtLeastAsConstrained1) - return false; - if (S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, + {RC2}, AtLeastAsConstrained1) || + S.IsAtLeastAsConstrained(Cand2.Function, {RC2}, Cand1.Function, {RC1}, AtLeastAsConstrained2)) return false; - if (!AtLeastAsConstrained2) - return true; - } else if (RC1 || RC2) + if (AtLeastAsConstrained1 != AtLeastAsConstrained2) + return AtLeastAsConstrained1; + } else if (RC1 || RC2) { return RC1 != nullptr; + } } } @@ -9646,7 +9755,8 @@ bool clang::isBetterOverloadCandidate( if (HasPS1 != HasPS2 && HasPS1) return true; - return isBetterMultiversionCandidate(Cand1, Cand2); + Comparison MV = isBetterMultiversionCandidate(Cand1, Cand2); + return MV == Comparison::Better; } /// Determine whether two declarations are "equivalent" for the purposes of @@ -9947,9 +10057,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } - if (const Expr *RC = FD->getTrailingRequiresClause()) { + if (FD->getTrailingRequiresClause()) { ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(RC, Satisfaction)) + if (S.CheckFunctionConstraints(FD, Satisfaction, Loc)) return false; if (!Satisfaction.IsSatisfied) { if (Complain) { @@ -10974,8 +11084,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, << (unsigned)FnKindPair.first << (unsigned)ocs_non_template << FnDesc /* Ignored */; ConstraintSatisfaction Satisfaction; - if (S.CheckConstraintSatisfaction(Fn->getTrailingRequiresClause(), - Satisfaction)) + if (S.CheckFunctionConstraints(Fn, Satisfaction)) break; S.DiagnoseUnsatisfiedConstraint(Satisfaction); } @@ -11275,7 +11384,7 @@ CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, unsigned ConvIdx = 0; unsigned ArgIdx = 0; ArrayRef<QualType> ParamTypes; - bool Reversed = Cand->RewriteKind & CRK_Reversed; + bool Reversed = Cand->isReversed(); if (Cand->IsSurrogate) { QualType ConvType @@ -12688,9 +12797,7 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, // base classes. CallExpr *CE = CallExpr::Create(Context, Fn, Args, Context.DependentTy, VK_RValue, RParenLoc); - CE->setTypeDependent(true); - CE->setValueDependent(true); - CE->setInstantiationDependent(true); + CE->markDependentForPostponedNameLookup(); *Result = CE; return true; } @@ -12703,6 +12810,42 @@ bool Sema::buildOverloadedCallSet(Scope *S, Expr *Fn, return false; } +// Guess at what the return type for an unresolvable overload should be. +static QualType chooseRecoveryType(OverloadCandidateSet &CS, + OverloadCandidateSet::iterator *Best) { + llvm::Optional<QualType> Result; + // Adjust Type after seeing a candidate. + auto ConsiderCandidate = [&](const OverloadCandidate &Candidate) { + if (!Candidate.Function) + return; + QualType T = Candidate.Function->getReturnType(); + if (T.isNull()) + return; + if (!Result) + Result = T; + else if (Result != T) + Result = QualType(); + }; + + // Look for an unambiguous type from a progressively larger subset. + // e.g. if types disagree, but all *viable* overloads return int, choose int. + // + // First, consider only the best candidate. + if (Best && *Best != CS.end()) + ConsiderCandidate(**Best); + // Next, consider only viable candidates. + if (!Result) + for (const auto &C : CS) + if (C.Viable) + ConsiderCandidate(C); + // Finally, consider all candidates. + if (!Result) + for (const auto &C : CS) + ConsiderCandidate(C); + + return Result.getValueOr(QualType()); +} + /// FinishOverloadedCallExpr - given an OverloadCandidateSet, builds and returns /// the completed call expression. If overload resolution fails, emits /// diagnostics and returns ExprError() @@ -12792,8 +12935,11 @@ static ExprResult FinishOverloadedCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, } } - // Overload resolution failed. - return ExprError(); + // Overload resolution failed, try to recover. + SmallVector<Expr *, 8> SubExprs = {Fn}; + SubExprs.append(Args.begin(), Args.end()); + return SemaRef.CreateRecoveryExpr(Fn->getBeginLoc(), RParenLoc, SubExprs, + chooseRecoveryType(*CandidateSet, Best)); } static void markUnaddressableCandidatesUnviable(Sema &S, @@ -12893,8 +13039,9 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, if (Input->isTypeDependent()) { if (Fns.empty()) - return new (Context) UnaryOperator(Input, Opc, Context.DependentTy, - VK_RValue, OK_Ordinary, OpLoc, false); + return UnaryOperator::Create(Context, Input, Opc, Context.DependentTy, + VK_RValue, OK_Ordinary, OpLoc, false, + CurFPFeatureOverrides()); CXXRecordDecl *NamingClass = nullptr; // lookup ignores member operators UnresolvedLookupExpr *Fn = UnresolvedLookupExpr::Create( @@ -12902,7 +13049,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, /*ADL*/ true, IsOverloaded(Fns), Fns.begin(), Fns.end()); return CXXOperatorCallExpr::Create(Context, Op, Fn, ArgsArray, Context.DependentTy, VK_RValue, OpLoc, - FPOptions()); + CurFPFeatureOverrides()); } // Build an empty overload set. @@ -12976,7 +13123,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, Args[0] = Input; CallExpr *TheCall = CXXOperatorCallExpr::Create( Context, Op, FnExpr.get(), ArgsArray, ResultTy, VK, OpLoc, - FPOptions(), Best->IsADLCandidate); + CurFPFeatureOverrides(), Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) return ExprError(); @@ -12984,8 +13131,7 @@ Sema::CreateOverloadedUnaryOp(SourceLocation OpLoc, UnaryOperatorKind Opc, if (CheckFunctionCall(FnDecl, TheCall, FnDecl->getType()->castAs<FunctionProtoType>())) return ExprError(); - - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), FnDecl); } else { // We matched a built-in operator. Convert the arguments, then // break out so that we will build the appropriate built-in @@ -13134,7 +13280,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, Expr *Args[2] = { LHS, RHS }; LHS=RHS=nullptr; // Please use only Args instead of LHS/RHS couple - if (!getLangOpts().CPlusPlus2a) + if (!getLangOpts().CPlusPlus20) AllowRewrittenCandidates = false; OverloadedOperatorKind Op = BinaryOperator::getOverloadedOperator(Opc); @@ -13146,14 +13292,13 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // If there are no functions to store, just build a dependent // BinaryOperator or CompoundAssignment. if (Opc <= BO_Assign || Opc > BO_OrAssign) - return new (Context) BinaryOperator( - Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, OK_Ordinary, - OpLoc, FPFeatures); - - return new (Context) CompoundAssignOperator( - Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, OK_Ordinary, - Context.DependentTy, Context.DependentTy, OpLoc, - FPFeatures); + return BinaryOperator::Create( + Context, Args[0], Args[1], Opc, Context.DependentTy, VK_RValue, + OK_Ordinary, OpLoc, CurFPFeatureOverrides()); + return CompoundAssignOperator::Create( + Context, Args[0], Args[1], Opc, Context.DependentTy, VK_LValue, + OK_Ordinary, OpLoc, CurFPFeatureOverrides(), Context.DependentTy, + Context.DependentTy); } // FIXME: save results of ADL from here? @@ -13166,7 +13311,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, /*ADL*/ PerformADL, IsOverloaded(Fns), Fns.begin(), Fns.end()); return CXXOperatorCallExpr::Create(Context, Op, Fn, Args, Context.DependentTy, VK_RValue, OpLoc, - FPFeatures); + CurFPFeatureOverrides()); } // Always do placeholder-like conversions on the RHS. @@ -13210,7 +13355,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // We found a built-in operator or an overloaded operator. FunctionDecl *FnDecl = Best->Function; - bool IsReversed = (Best->RewriteKind & CRK_Reversed); + bool IsReversed = Best->isReversed(); if (IsReversed) std::swap(Args[0], Args[1]); @@ -13227,36 +13372,56 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, // resolution for an operator@, its return type shall be cv bool if (Best->RewriteKind && ChosenOp == OO_EqualEqual && !FnDecl->getReturnType()->isBooleanType()) { - Diag(OpLoc, diag::err_ovl_rewrite_equalequal_not_bool) + bool IsExtension = + FnDecl->getReturnType()->isIntegralOrUnscopedEnumerationType(); + Diag(OpLoc, IsExtension ? diag::ext_ovl_rewrite_equalequal_not_bool + : diag::err_ovl_rewrite_equalequal_not_bool) << FnDecl->getReturnType() << BinaryOperator::getOpcodeStr(Opc) << Args[0]->getSourceRange() << Args[1]->getSourceRange(); Diag(FnDecl->getLocation(), diag::note_declared_at); - return ExprError(); + if (!IsExtension) + return ExprError(); } if (AllowRewrittenCandidates && !IsReversed && - CandidateSet.getRewriteInfo().shouldAddReversed(ChosenOp)) { - // We could have reversed this operator, but didn't. Check if the + CandidateSet.getRewriteInfo().isReversible()) { + // We could have reversed this operator, but didn't. Check if some // reversed form was a viable candidate, and if so, if it had a // better conversion for either parameter. If so, this call is // formally ambiguous, and allowing it is an extension. + llvm::SmallVector<FunctionDecl*, 4> AmbiguousWith; for (OverloadCandidate &Cand : CandidateSet) { - if (Cand.Viable && Cand.Function == FnDecl && - Cand.RewriteKind & CRK_Reversed) { + if (Cand.Viable && Cand.Function && Cand.isReversed() && + haveSameParameterTypes(Context, Cand.Function, FnDecl, 2)) { for (unsigned ArgIdx = 0; ArgIdx < 2; ++ArgIdx) { if (CompareImplicitConversionSequences( *this, OpLoc, Cand.Conversions[ArgIdx], Best->Conversions[ArgIdx]) == ImplicitConversionSequence::Better) { - Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed) - << BinaryOperator::getOpcodeStr(Opc) - << Args[0]->getType() << Args[1]->getType() - << Args[0]->getSourceRange() << Args[1]->getSourceRange(); - Diag(FnDecl->getLocation(), - diag::note_ovl_ambiguous_oper_binary_reversed_candidate); + AmbiguousWith.push_back(Cand.Function); + break; } } - break; + } + } + + if (!AmbiguousWith.empty()) { + bool AmbiguousWithSelf = + AmbiguousWith.size() == 1 && + declaresSameEntity(AmbiguousWith.front(), FnDecl); + Diag(OpLoc, diag::ext_ovl_ambiguous_oper_binary_reversed) + << BinaryOperator::getOpcodeStr(Opc) + << Args[0]->getType() << Args[1]->getType() << AmbiguousWithSelf + << Args[0]->getSourceRange() << Args[1]->getSourceRange(); + if (AmbiguousWithSelf) { + Diag(FnDecl->getLocation(), + diag::note_ovl_ambiguous_oper_binary_reversed_self); + } else { + Diag(FnDecl->getLocation(), + diag::note_ovl_ambiguous_oper_binary_selected_candidate); + for (auto *F : AmbiguousWith) + Diag(F->getLocation(), + diag::note_ovl_ambiguous_oper_binary_reversed_candidate); } } } @@ -13315,7 +13480,7 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( Context, ChosenOp, FnExpr.get(), Args, ResultTy, VK, OpLoc, - FPFeatures, Best->IsADLCandidate); + CurFPFeatureOverrides(), Best->IsADLCandidate); if (CheckCallReturnType(FnDecl->getReturnType(), OpLoc, TheCall, FnDecl)) @@ -13341,6 +13506,10 @@ ExprResult Sema::CreateOverloadedBinOp(SourceLocation OpLoc, if (R.isInvalid()) return ExprError(); + R = CheckForImmediateInvocation(R, FnDecl); + if (R.isInvalid()) + return ExprError(); + // For a rewritten candidate, we've already reversed the arguments // if needed. Perform the rest of the rewrite now. if ((Best->RewriteKind & CRK_DifferentOperator) || @@ -13580,10 +13749,10 @@ ExprResult Sema::BuildSynthesizedThreeWayComparison( // Build a PseudoObjectExpr to model the rewriting of an <=> operator, and to // bind the OpaqueValueExprs before they're (repeatedly) used. - Expr *SyntacticForm = new (Context) - BinaryOperator(OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), - Result.get()->getValueKind(), - Result.get()->getObjectKind(), OpLoc, FPFeatures); + Expr *SyntacticForm = BinaryOperator::Create( + Context, OrigLHS, OrigRHS, BO_Cmp, Result.get()->getType(), + Result.get()->getValueKind(), Result.get()->getObjectKind(), OpLoc, + CurFPFeatureOverrides()); Expr *SemanticForm[] = {LHS, RHS, Result.get()}; return PseudoObjectExpr::Create(Context, SyntacticForm, SemanticForm, 2); } @@ -13614,7 +13783,7 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, return CXXOperatorCallExpr::Create(Context, OO_Subscript, Fn, Args, Context.DependentTy, VK_RValue, RLoc, - FPOptions()); + CurFPFeatureOverrides()); } // Handle placeholders on both operands. @@ -13687,10 +13856,9 @@ Sema::CreateOverloadedArraySubscriptExpr(SourceLocation LLoc, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = - CXXOperatorCallExpr::Create(Context, OO_Subscript, FnExpr.get(), - Args, ResultTy, VK, RLoc, FPOptions()); - + CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Subscript, FnExpr.get(), Args, ResultTy, VK, RLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(FnDecl->getReturnType(), LLoc, TheCall, FnDecl)) return ExprError(); @@ -14000,7 +14168,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // resolution process, we still need to handle the enable_if attribute. Do // that here, so it will not hide previous -- and more relevant -- errors. if (auto *MemE = dyn_cast<MemberExpr>(NakedMemExpr)) { - if (const EnableIfAttr *Attr = CheckEnableIf(Method, Args, true)) { + if (const EnableIfAttr *Attr = + CheckEnableIf(Method, LParenLoc, Args, true)) { Diag(MemE->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << Method << Method->getSourceRange(); @@ -14039,7 +14208,8 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, MemExpr->getMemberLoc()); } - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), + TheCall->getMethodDecl()); } /// BuildCallToObjectOfClassType - Build a call to an object of class @@ -14310,9 +14480,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = - CXXOperatorCallExpr::Create(Context, OO_Call, NewFn.get(), MethodArgs, - ResultTy, VK, RParenLoc, FPOptions()); + CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( + Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, VK, RParenLoc, + CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; @@ -14320,7 +14490,7 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, if (CheckFunctionCall(Method, TheCall, Proto)) return true; - return MaybeBindToTemporary(TheCall); + return CheckForImmediateInvocation(MaybeBindToTemporary(TheCall), Method); } /// BuildOverloadedArrowExpr - Build a call to an overloaded @c operator-> @@ -14428,8 +14598,9 @@ Sema::BuildOverloadedArrowExpr(Scope *S, Expr *Base, SourceLocation OpLoc, QualType ResultTy = Method->getReturnType(); ExprValueKind VK = Expr::getValueKindForType(ResultTy); ResultTy = ResultTy.getNonLValueExprType(Context); - CXXOperatorCallExpr *TheCall = CXXOperatorCallExpr::Create( - Context, OO_Arrow, FnExpr.get(), Base, ResultTy, VK, OpLoc, FPOptions()); + CXXOperatorCallExpr *TheCall = + CXXOperatorCallExpr::Create(Context, OO_Arrow, FnExpr.get(), Base, + ResultTy, VK, OpLoc, CurFPFeatureOverrides()); if (CheckCallReturnType(Method->getReturnType(), OpLoc, TheCall, Method)) return ExprError(); @@ -14515,7 +14686,7 @@ ExprResult Sema::BuildLiteralOperatorCall(LookupResult &R, if (CheckFunctionCall(FD, UDL, nullptr)) return ExprError(); - return MaybeBindToTemporary(UDL); + return CheckForImmediateInvocation(MaybeBindToTemporary(UDL), FD); } /// Build a call to 'begin' or 'end' for a C++11 for-range statement. If the @@ -14676,9 +14847,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, if (Context.getTargetInfo().getCXXABI().isMicrosoft()) (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); - return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, - VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc(), false); + return UnaryOperator::Create( + Context, SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary, + UnOp->getOperatorLoc(), false, CurFPFeatureOverrides()); } } Expr *SubExpr = FixOverloadedFunctionReference(UnOp->getSubExpr(), @@ -14686,10 +14857,10 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, if (SubExpr == UnOp->getSubExpr()) return UnOp; - return new (Context) UnaryOperator(SubExpr, UO_AddrOf, - Context.getPointerType(SubExpr->getType()), - VK_RValue, OK_Ordinary, - UnOp->getOperatorLoc(), false); + return UnaryOperator::Create(Context, SubExpr, UO_AddrOf, + Context.getPointerType(SubExpr->getType()), + VK_RValue, OK_Ordinary, UnOp->getOperatorLoc(), + false, CurFPFeatureOverrides()); } if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { diff --git a/clang/lib/Sema/SemaPseudoObject.cpp b/clang/lib/Sema/SemaPseudoObject.cpp index 5587e0d24c7f..d17599a6ed14 100644 --- a/clang/lib/Sema/SemaPseudoObject.cpp +++ b/clang/lib/Sema/SemaPseudoObject.cpp @@ -127,12 +127,10 @@ namespace { if (UnaryOperator *uop = dyn_cast<UnaryOperator>(e)) { assert(uop->getOpcode() == UO_Extension); e = rebuild(uop->getSubExpr()); - return new (S.Context) UnaryOperator(e, uop->getOpcode(), - uop->getType(), - uop->getValueKind(), - uop->getObjectKind(), - uop->getOperatorLoc(), - uop->canOverflow()); + return UnaryOperator::Create( + S.Context, e, uop->getOpcode(), uop->getType(), uop->getValueKind(), + uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow(), + S.CurFPFeatureOverrides()); } if (GenericSelectionExpr *gse = dyn_cast<GenericSelectionExpr>(e)) { @@ -167,16 +165,11 @@ namespace { Expr *&rebuiltExpr = ce->isConditionTrue() ? LHS : RHS; rebuiltExpr = rebuild(rebuiltExpr); - return new (S.Context) ChooseExpr(ce->getBuiltinLoc(), - ce->getCond(), - LHS, RHS, - rebuiltExpr->getType(), - rebuiltExpr->getValueKind(), - rebuiltExpr->getObjectKind(), - ce->getRParenLoc(), - ce->isConditionTrue(), - rebuiltExpr->isTypeDependent(), - rebuiltExpr->isValueDependent()); + return new (S.Context) + ChooseExpr(ce->getBuiltinLoc(), ce->getCond(), LHS, RHS, + rebuiltExpr->getType(), rebuiltExpr->getValueKind(), + rebuiltExpr->getObjectKind(), ce->getRParenLoc(), + ce->isConditionTrue()); } llvm_unreachable("bad expression to rebuild!"); @@ -453,11 +446,11 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, ExprResult result; if (opcode == BO_Assign) { result = semanticRHS; - syntactic = new (S.Context) BinaryOperator(syntacticLHS, capturedRHS, - opcode, capturedRHS->getType(), - capturedRHS->getValueKind(), - OK_Ordinary, opcLoc, - FPOptions()); + syntactic = BinaryOperator::Create(S.Context, syntacticLHS, capturedRHS, + opcode, capturedRHS->getType(), + capturedRHS->getValueKind(), OK_Ordinary, + opcLoc, S.CurFPFeatureOverrides()); + } else { ExprResult opLHS = buildGet(); if (opLHS.isInvalid()) return ExprError(); @@ -468,14 +461,11 @@ PseudoOpBuilder::buildAssignmentOperation(Scope *Sc, SourceLocation opcLoc, result = S.BuildBinOp(Sc, opcLoc, nonCompound, opLHS.get(), semanticRHS); if (result.isInvalid()) return ExprError(); - syntactic = - new (S.Context) CompoundAssignOperator(syntacticLHS, capturedRHS, opcode, - result.get()->getType(), - result.get()->getValueKind(), - OK_Ordinary, - opLHS.get()->getType(), - result.get()->getType(), - opcLoc, FPOptions()); + syntactic = CompoundAssignOperator::Create( + S.Context, syntacticLHS, capturedRHS, opcode, result.get()->getType(), + result.get()->getValueKind(), OK_Ordinary, opcLoc, + S.CurFPFeatureOverrides(), opLHS.get()->getType(), + result.get()->getType()); } // The result of the assignment, if not void, is the value set into @@ -536,12 +526,14 @@ PseudoOpBuilder::buildIncDecOperation(Scope *Sc, SourceLocation opcLoc, (result.get()->isTypeDependent() || CanCaptureValue(result.get()))) setResultToLastSemantic(); - UnaryOperator *syntactic = new (S.Context) UnaryOperator( - syntacticOp, opcode, resultType, VK_LValue, OK_Ordinary, opcLoc, - !resultType->isDependentType() - ? S.Context.getTypeSize(resultType) >= - S.Context.getTypeSize(S.Context.IntTy) - : false); + UnaryOperator *syntactic = + UnaryOperator::Create(S.Context, syntacticOp, opcode, resultType, + VK_LValue, OK_Ordinary, opcLoc, + !resultType->isDependentType() + ? S.Context.getTypeSize(resultType) >= + S.Context.getTypeSize(S.Context.IntTy) + : false, + S.CurFPFeatureOverrides()); return complete(syntactic); } @@ -590,7 +582,7 @@ bool ObjCPropertyOpBuilder::isWeakProperty() const { QualType T; if (RefExpr->isExplicitProperty()) { const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); - if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) + if (Prop->getPropertyAttributes() & ObjCPropertyAttribute::kind_weak) return true; T = Prop->getType(); @@ -1561,8 +1553,9 @@ ExprResult Sema::checkPseudoObjectIncDec(Scope *Sc, SourceLocation opcLoc, UnaryOperatorKind opcode, Expr *op) { // Do nothing if the operand is dependent. if (op->isTypeDependent()) - return new (Context) UnaryOperator(op, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc, false); + return UnaryOperator::Create(Context, op, opcode, Context.DependentTy, + VK_RValue, OK_Ordinary, opcLoc, false, + CurFPFeatureOverrides()); assert(UnaryOperator::isIncrementDecrementOp(opcode)); Expr *opaqueRef = op->IgnoreParens(); @@ -1591,9 +1584,9 @@ ExprResult Sema::checkPseudoObjectAssignment(Scope *S, SourceLocation opcLoc, Expr *LHS, Expr *RHS) { // Do nothing if either argument is dependent. if (LHS->isTypeDependent() || RHS->isTypeDependent()) - return new (Context) BinaryOperator(LHS, RHS, opcode, Context.DependentTy, - VK_RValue, OK_Ordinary, opcLoc, - FPOptions()); + return BinaryOperator::Create(Context, LHS, RHS, opcode, + Context.DependentTy, VK_RValue, OK_Ordinary, + opcLoc, CurFPFeatureOverrides()); // Filter out non-overload placeholder types in the RHS. if (RHS->getType()->isNonOverloadPlaceholderType()) { @@ -1646,28 +1639,30 @@ Expr *Sema::recreateSyntacticForm(PseudoObjectExpr *E) { Expr *syntax = E->getSyntacticForm(); if (UnaryOperator *uop = dyn_cast<UnaryOperator>(syntax)) { Expr *op = stripOpaqueValuesFromPseudoObjectRef(*this, uop->getSubExpr()); - return new (Context) UnaryOperator( - op, uop->getOpcode(), uop->getType(), uop->getValueKind(), - uop->getObjectKind(), uop->getOperatorLoc(), uop->canOverflow()); + return UnaryOperator::Create(Context, op, uop->getOpcode(), uop->getType(), + uop->getValueKind(), uop->getObjectKind(), + uop->getOperatorLoc(), uop->canOverflow(), + CurFPFeatureOverrides()); } else if (CompoundAssignOperator *cop = dyn_cast<CompoundAssignOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, cop->getLHS()); Expr *rhs = cast<OpaqueValueExpr>(cop->getRHS())->getSourceExpr(); - return new (Context) CompoundAssignOperator(lhs, rhs, cop->getOpcode(), - cop->getType(), - cop->getValueKind(), - cop->getObjectKind(), - cop->getComputationLHSType(), - cop->getComputationResultType(), - cop->getOperatorLoc(), - FPOptions()); + return CompoundAssignOperator::Create( + Context, lhs, rhs, cop->getOpcode(), cop->getType(), + cop->getValueKind(), cop->getObjectKind(), cop->getOperatorLoc(), + CurFPFeatureOverrides(), cop->getComputationLHSType(), + cop->getComputationResultType()); + } else if (BinaryOperator *bop = dyn_cast<BinaryOperator>(syntax)) { Expr *lhs = stripOpaqueValuesFromPseudoObjectRef(*this, bop->getLHS()); Expr *rhs = cast<OpaqueValueExpr>(bop->getRHS())->getSourceExpr(); - return new (Context) BinaryOperator(lhs, rhs, bop->getOpcode(), - bop->getType(), bop->getValueKind(), - bop->getObjectKind(), - bop->getOperatorLoc(), FPOptions()); + return BinaryOperator::Create(Context, lhs, rhs, bop->getOpcode(), + bop->getType(), bop->getValueKind(), + bop->getObjectKind(), bop->getOperatorLoc(), + CurFPFeatureOverrides()); + + } else if (isa<CallExpr>(syntax)) { + return syntax; } else { assert(syntax->hasPlaceholderType(BuiltinType::PseudoObject)); return stripOpaqueValuesFromPseudoObjectRef(*this, syntax); diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp new file mode 100644 index 000000000000..db7603b42f7b --- /dev/null +++ b/clang/lib/Sema/SemaSYCL.cpp @@ -0,0 +1,49 @@ +//===- SemaSYCL.cpp - Semantic Analysis for SYCL constructs ---------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// This implements Semantic Analysis for SYCL constructs. +//===----------------------------------------------------------------------===// + +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" + +using namespace clang; + +// ----------------------------------------------------------------------------- +// SYCL device specific diagnostics implementation +// ----------------------------------------------------------------------------- + +Sema::DeviceDiagBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext()); + DeviceDiagBuilder::Kind DiagKind = [this, FD] { + if (!FD) + return DeviceDiagBuilder::K_Nop; + if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted) + return DeviceDiagBuilder::K_ImmediateWithCallStack; + return DeviceDiagBuilder::K_Deferred; + }(); + return DeviceDiagBuilder(DiagKind, Loc, DiagID, FD, *this); +} + +bool Sema::checkSYCLDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { + assert(getLangOpts().SYCLIsDevice && + "Should only be called during SYCL compilation"); + assert(Callee && "Callee may not be null."); + + // Errors in unevaluated context don't need to be generated, + // so we can safely skip them. + if (isUnevaluatedContext() || isConstantEvaluated()) + return true; + + DeviceDiagBuilder::Kind DiagKind = DeviceDiagBuilder::K_Nop; + + return DiagKind != DeviceDiagBuilder::K_Immediate && + DiagKind != DeviceDiagBuilder::K_ImmediateWithCallStack; +} diff --git a/clang/lib/Sema/SemaStmt.cpp b/clang/lib/Sema/SemaStmt.cpp index d6c3af9e84c8..73f3183c163f 100644 --- a/clang/lib/Sema/SemaStmt.cpp +++ b/clang/lib/Sema/SemaStmt.cpp @@ -334,6 +334,11 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } else if (const PseudoObjectExpr *POE = dyn_cast<PseudoObjectExpr>(E)) { const Expr *Source = POE->getSyntacticForm(); + // Handle the actually selected call of an OpenMP specialized call. + if (LangOpts.OpenMP && isa<CallExpr>(Source) && + POE->getNumSemanticExprs() == 1 && + isa<CallExpr>(POE->getSemanticExpr(0))) + return DiagnoseUnusedExprResult(POE->getSemanticExpr(0)); if (isa<ObjCSubscriptRefExpr>(Source)) DiagID = diag::warn_unused_container_subscript_expr; else @@ -365,7 +370,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } } - if (E->isGLValue() && E->getType().isVolatileQualified()) { + // Tell the user to assign it into a variable to force a volatile load if this + // isn't an array. + if (E->isGLValue() && E->getType().isVolatileQualified() && + !E->getType()->isArrayType()) { Diag(Loc, diag::warn_unused_volatile) << R1 << R2; return; } @@ -389,6 +397,11 @@ StmtResult Sema::ActOnCompoundStmt(SourceLocation L, SourceLocation R, ArrayRef<Stmt *> Elts, bool isStmtExpr) { const unsigned NumElts = Elts.size(); + // Mark the current function as usng floating point constrained intrinsics + if (getCurFPFeatures().isFPConstrained()) + if (FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) + F->setUsesFPIntrin(true); + // If we're in C89 mode, check that we don't have any decls after stmts. If // so, emit an extension diagnostic. if (!getLangOpts().C99 && !getLangOpts().CPlusPlus) { @@ -464,7 +477,9 @@ Sema::ActOnCaseExpr(SourceLocation CaseLoc, ExprResult Val) { return ER; }; - ExprResult Converted = CorrectDelayedTyposInExpr(Val, CheckAndFinish); + ExprResult Converted = CorrectDelayedTyposInExpr( + Val, /*InitDecl=*/nullptr, /*RecoverUncorrectedTypos=*/false, + CheckAndFinish); if (Converted.get() == Val.get()) Converted = CheckAndFinish(Val.get()); return Converted; @@ -730,11 +745,11 @@ StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, if (CondExpr && !CondExpr->isTypeDependent()) { // We have already converted the expression to an integral or enumeration - // type, when we parsed the switch condition. If we don't have an - // appropriate type now, enter the switch scope but remember that it's - // invalid. - assert(CondExpr->getType()->isIntegralOrEnumerationType() && - "invalid condition type"); + // type, when we parsed the switch condition. There are cases where we don't + // have an appropriate type, e.g. a typo-expr Cond was corrected to an + // inappropriate-type expr, we just return an error. + if (!CondExpr->getType()->isIntegralOrEnumerationType()) + return StmtError(); if (CondExpr->isKnownToHaveBooleanValue()) { // switch(bool_expr) {...} is often a programmer error, e.g. // switch(n && mask) { ... } // Doh - should be "n & mask". @@ -1313,8 +1328,9 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, } } -StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, - Stmt *Body) { +StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, + SourceLocation LParenLoc, ConditionResult Cond, + SourceLocation RParenLoc, Stmt *Body) { if (Cond.isInvalid()) return StmtError(); @@ -1329,7 +1345,7 @@ StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, getCurCompoundScope().setHasEmptyLoopBodies(); return WhileStmt::Create(Context, CondVal.first, CondVal.second, Body, - WhileLoc); + WhileLoc, LParenLoc, RParenLoc); } StmtResult @@ -1387,10 +1403,9 @@ namespace { Simple = false; } - // Any Stmt not whitelisted will cause the condition to be marked complex. - void VisitStmt(Stmt *S) { - Simple = false; - } + // Any Stmt not explicitly listed will cause the condition to be marked + // complex. + void VisitStmt(Stmt *S) { Simple = false; } void VisitBinaryOperator(BinaryOperator *E) { Visit(E->getLHS()); @@ -2114,18 +2129,22 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, return StmtError(); } + // This function is responsible for attaching an initializer to LoopVar. We + // must call ActOnInitializerError if we fail to do so. Decl *LoopVar = DS->getSingleDecl(); if (LoopVar->isInvalidDecl() || !Range || DiagnoseUnexpandedParameterPack(Range, UPPC_Expression)) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } // Build the coroutine state immediately and not later during template // instantiation if (!CoawaitLoc.isInvalid()) { - if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) + if (!ActOnCoroutineBodyStart(S, CoawaitLoc, "co_await")) { + ActOnInitializerError(LoopVar); return StmtError(); + } } // Build auto && __range = range-init @@ -2137,7 +2156,7 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, std::string("__range") + DepthStr); if (FinishForRangeVarDecl(*this, RangeVar, Range, RangeLoc, diag::err_for_range_deduction_failure)) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } @@ -2146,14 +2165,20 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, BuildDeclaratorGroup(MutableArrayRef<Decl *>((Decl **)&RangeVar, 1)); StmtResult RangeDecl = ActOnDeclStmt(RangeGroup, RangeLoc, RangeLoc); if (RangeDecl.isInvalid()) { - LoopVar->setInvalidDecl(); + ActOnInitializerError(LoopVar); return StmtError(); } - return BuildCXXForRangeStmt( + StmtResult R = BuildCXXForRangeStmt( ForLoc, CoawaitLoc, InitStmt, ColonLoc, RangeDecl.get(), /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr, /*Cond=*/nullptr, /*Inc=*/nullptr, DS, RParenLoc, Kind); + if (R.isInvalid()) { + ActOnInitializerError(LoopVar); + return StmtError(); + } + + return R; } /// Create the initialization, compare, and increment steps for @@ -2336,22 +2361,6 @@ static StmtResult RebuildForRangeWithDereference(Sema &SemaRef, Scope *S, AdjustedRange.get(), RParenLoc, Sema::BFRK_Rebuild); } -namespace { -/// RAII object to automatically invalidate a declaration if an error occurs. -struct InvalidateOnErrorScope { - InvalidateOnErrorScope(Sema &SemaRef, Decl *D, bool Enabled) - : Trap(SemaRef.Diags), D(D), Enabled(Enabled) {} - ~InvalidateOnErrorScope() { - if (Enabled && Trap.hasErrorOccurred()) - D->setInvalidDecl(); - } - - DiagnosticErrorTrap Trap; - Decl *D; - bool Enabled; -}; -} - /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, Stmt *InitStmt, @@ -2378,11 +2387,6 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, DeclStmt *LoopVarDS = cast<DeclStmt>(LoopVarDecl); VarDecl *LoopVar = cast<VarDecl>(LoopVarDS->getSingleDecl()); - // If we hit any errors, mark the loop variable as invalid if its type - // contains 'auto'. - InvalidateOnErrorScope Invalidate(*this, LoopVar, - LoopVar->getType()->isUndeducedType()); - StmtResult BeginDeclStmt = Begin; StmtResult EndDeclStmt = End; ExprResult NotEqExpr = Cond, IncrExpr = Inc; @@ -2664,7 +2668,8 @@ StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, // trying to determine whether this would be a valid range. if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) { AddInitializerToDecl(LoopVar, DerefExpr.get(), /*DirectInit=*/false); - if (LoopVar->isInvalidDecl()) + if (LoopVar->isInvalidDecl() || + (LoopVar->getInit() && LoopVar->getInit()->containsErrors())) NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); } } @@ -2741,22 +2746,24 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, E = E->IgnoreImpCasts(); } - bool ReturnsReference = false; + QualType ReferenceReturnType; if (isa<UnaryOperator>(E)) { - ReturnsReference = true; + ReferenceReturnType = SemaRef.Context.getLValueReferenceType(E->getType()); } else { const CXXOperatorCallExpr *Call = cast<CXXOperatorCallExpr>(E); const FunctionDecl *FD = Call->getDirectCallee(); QualType ReturnType = FD->getReturnType(); - ReturnsReference = ReturnType->isReferenceType(); + if (ReturnType->isReferenceType()) + ReferenceReturnType = ReturnType; } - if (ReturnsReference) { + if (!ReferenceReturnType.isNull()) { // Loop variable creates a temporary. Suggest either to go with // non-reference loop variable to indicate a copy is made, or - // the correct time to bind a const reference. - SemaRef.Diag(VD->getLocation(), diag::warn_for_range_const_reference_copy) - << VD << VariableType << E->getType(); + // the correct type to bind a const reference. + SemaRef.Diag(VD->getLocation(), + diag::warn_for_range_const_ref_binds_temp_built_from_ref) + << VD << VariableType << ReferenceReturnType; QualType NonReferenceType = VariableType.getNonReferenceType(); NonReferenceType.removeLocalConst(); QualType NewReferenceType = @@ -2769,7 +2776,7 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, // Suggest removing the reference from the loop variable. // If the type is a rvalue reference do not warn since that changes the // semantic of the code. - SemaRef.Diag(VD->getLocation(), diag::warn_for_range_variable_always_copy) + SemaRef.Diag(VD->getLocation(), diag::warn_for_range_ref_binds_ret_temp) << VD << RangeInitType; QualType NonReferenceType = VariableType.getNonReferenceType(); NonReferenceType.removeLocalConst(); @@ -2821,7 +2828,7 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, // Suggest changing from a const variable to a const reference variable // if doing so will prevent a copy. SemaRef.Diag(VD->getLocation(), diag::warn_for_range_copy) - << VD << VariableType << InitExpr->getType(); + << VD << VariableType; SemaRef.Diag(VD->getBeginLoc(), diag::note_use_reference_type) << SemaRef.Context.getLValueReferenceType(VariableType) << VD->getSourceRange() @@ -2838,9 +2845,13 @@ static void DiagnoseForRangeConstVariableCopies(Sema &SemaRef, /// Suggest "const foo &x" to prevent the copy. static void DiagnoseForRangeVariableCopies(Sema &SemaRef, const CXXForRangeStmt *ForStmt) { - if (SemaRef.Diags.isIgnored(diag::warn_for_range_const_reference_copy, - ForStmt->getBeginLoc()) && - SemaRef.Diags.isIgnored(diag::warn_for_range_variable_always_copy, + if (SemaRef.inTemplateInstantiation()) + return; + + if (SemaRef.Diags.isIgnored( + diag::warn_for_range_const_ref_binds_temp_built_from_ref, + ForStmt->getBeginLoc()) && + SemaRef.Diags.isIgnored(diag::warn_for_range_ref_binds_ret_temp, ForStmt->getBeginLoc()) && SemaRef.Diags.isIgnored(diag::warn_for_range_copy, ForStmt->getBeginLoc())) { @@ -2860,6 +2871,9 @@ static void DiagnoseForRangeVariableCopies(Sema &SemaRef, if (!InitExpr) return; + if (InitExpr->getExprLoc().isMacroID()) + return; + if (VariableType->isReferenceType()) { DiagnoseForRangeReferenceVariableCopies(SemaRef, VD, ForStmt->getRangeInit()->getType()); @@ -3286,6 +3300,7 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { assert(AT && "lost auto type from lambda return type"); if (DeduceFunctionTypeFromReturnExpr(FD, ReturnLoc, RetValExp, AT)) { FD->setInvalidDecl(); + // FIXME: preserve the ill-formed return expression. return StmtError(); } CurCap->ReturnType = FnRetType = FD->getReturnType(); @@ -3616,6 +3631,12 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (isa<CXXBoolLiteralExpr>(RetValExp)) Diag(ReturnLoc, diag::warn_main_returns_bool_literal) << RetValExp->getSourceRange(); + if (FD->hasAttr<CmseNSEntryAttr>() && RetValExp) { + if (const auto *RT = dyn_cast<RecordType>(FnRetType.getCanonicalType())) { + if (RT->getDecl()->isOrContainsUnion()) + Diag(RetValExp->getBeginLoc(), diag::warn_cmse_nonsecure_union) << 1; + } + } } else if (ObjCMethodDecl *MD = getCurMethodDecl()) { FnRetType = MD->getReturnType(); isObjCMethod = true; diff --git a/clang/lib/Sema/SemaStmtAsm.cpp b/clang/lib/Sema/SemaStmtAsm.cpp index 93faf2d151f9..10fa24682f9c 100644 --- a/clang/lib/Sema/SemaStmtAsm.cpp +++ b/clang/lib/Sema/SemaStmtAsm.cpp @@ -296,6 +296,14 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, checkExprMemoryConstraintCompat(*this, OutputExpr, Info, false)) return StmtError(); + // Disallow _ExtInt, since the backends tend to have difficulties with + // non-normal sizes. + if (OutputExpr->getType()->isExtIntType()) + return StmtError( + Diag(OutputExpr->getBeginLoc(), diag::err_asm_invalid_type) + << OutputExpr->getType() << 0 /*Input*/ + << OutputExpr->getSourceRange()); + OutputConstraintInfos.push_back(Info); // If this is dependent, just continue. @@ -420,6 +428,12 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, } } + if (InputExpr->getType()->isExtIntType()) + return StmtError( + Diag(InputExpr->getBeginLoc(), diag::err_asm_invalid_type) + << InputExpr->getType() << 1 /*Output*/ + << InputExpr->getSourceRange()); + InputConstraintInfos.push_back(Info); const Type *Ty = Exprs[i]->getType().getTypePtr(); @@ -478,10 +492,10 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, // Look for the correct constraint index. unsigned ConstraintIdx = Piece.getOperandNo(); + unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Labels are the last in the Exprs list. - if (NS->isAsmGoto() && ConstraintIdx >= NS->getNumInputs()) + if (NS->isAsmGoto() && ConstraintIdx >= NumOperands) continue; - unsigned NumOperands = NS->getNumOutputs() + NS->getNumInputs(); // Look for the (ConstraintIdx - NumOperands + 1)th constraint with // modifier '+'. if (ConstraintIdx >= NumOperands) { @@ -892,6 +906,15 @@ StmtResult Sema::ActOnMSAsmStmt(SourceLocation AsmLoc, SourceLocation LBraceLoc, SourceLocation EndLoc) { bool IsSimple = (NumOutputs != 0 || NumInputs != 0); setFunctionHasBranchProtectedScope(); + + for (uint64_t I = 0; I < NumOutputs + NumInputs; ++I) { + if (Exprs[I]->getType()->isExtIntType()) + return StmtError( + Diag(Exprs[I]->getBeginLoc(), diag::err_asm_invalid_type) + << Exprs[I]->getType() << (I < NumOutputs) + << Exprs[I]->getSourceRange()); + } + MSAsmStmt *NS = new (Context) MSAsmStmt(Context, AsmLoc, LBraceLoc, IsSimple, /*IsVolatile*/ true, AsmToks, NumOutputs, NumInputs, diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 3d91893b4065..e9d3c755eb23 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -10,6 +10,7 @@ // //===----------------------------------------------------------------------===// +#include "clang/AST/EvaluatedExprVisitor.h" #include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" @@ -170,6 +171,44 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const ParsedAttr &A, return LoopHintAttr::CreateImplicit(S.Context, Option, State, ValueExpr, A); } +namespace { +class CallExprFinder : public ConstEvaluatedExprVisitor<CallExprFinder> { + bool FoundCallExpr = false; + +public: + typedef ConstEvaluatedExprVisitor<CallExprFinder> Inherited; + + CallExprFinder(Sema &S, const Stmt *St) : Inherited(S.Context) { Visit(St); } + + bool foundCallExpr() { return FoundCallExpr; } + + void VisitCallExpr(const CallExpr *E) { FoundCallExpr = true; } + + void Visit(const Stmt *St) { + if (!St) + return; + ConstEvaluatedExprVisitor<CallExprFinder>::Visit(St); + } +}; +} // namespace + +static Attr *handleNoMergeAttr(Sema &S, Stmt *St, const ParsedAttr &A, + SourceRange Range) { + NoMergeAttr NMA(S.Context, A); + if (S.CheckAttrNoArgs(A)) + return nullptr; + + CallExprFinder CEF(S, St); + + if (!CEF.foundCallExpr()) { + S.Diag(St->getBeginLoc(), diag::warn_nomerge_attribute_ignored_in_stmt) + << NMA.getSpelling(); + return nullptr; + } + + return ::new (S.Context) NoMergeAttr(S.Context, A); +} + static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl<const Attr *> &Attrs) { @@ -335,6 +374,8 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, return handleOpenCLUnrollHint(S, St, A, Range); case ParsedAttr::AT_Suppress: return handleSuppressAttr(S, St, A, Range); + case ParsedAttr::AT_NoMerge: + return handleNoMergeAttr(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index 1184446796eb..c05ed0b14e3e 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -46,6 +46,47 @@ clang::getTemplateParamsRange(TemplateParameterList const * const *Ps, return SourceRange(Ps[0]->getTemplateLoc(), Ps[N-1]->getRAngleLoc()); } +unsigned Sema::getTemplateDepth(Scope *S) const { + unsigned Depth = 0; + + // Each template parameter scope represents one level of template parameter + // depth. + for (Scope *TempParamScope = S->getTemplateParamParent(); TempParamScope; + TempParamScope = TempParamScope->getParent()->getTemplateParamParent()) { + ++Depth; + } + + // Note that there are template parameters with the given depth. + auto ParamsAtDepth = [&](unsigned D) { Depth = std::max(Depth, D + 1); }; + + // Look for parameters of an enclosing generic lambda. We don't create a + // template parameter scope for these. + for (FunctionScopeInfo *FSI : getFunctionScopes()) { + if (auto *LSI = dyn_cast<LambdaScopeInfo>(FSI)) { + if (!LSI->TemplateParams.empty()) { + ParamsAtDepth(LSI->AutoTemplateParameterDepth); + break; + } + if (LSI->GLTemplateParameterList) { + ParamsAtDepth(LSI->GLTemplateParameterList->getDepth()); + break; + } + } + } + + // Look for parameters of an enclosing terse function template. We don't + // create a template parameter scope for these either. + for (const InventedTemplateParameterInfo &Info : + getInventedParameterInfos()) { + if (!Info.TemplateParams.empty()) { + ParamsAtDepth(Info.AutoTemplateParameterDepth); + break; + } + } + + return Depth; +} + /// \brief Determine whether the declaration found is acceptable as the name /// of a template and, if so, return that template declaration. Otherwise, /// returns null. @@ -132,7 +173,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, ParsedType ObjectTypePtr, bool EnteringContext, TemplateTy &TemplateResult, - bool &MemberOfUnknownSpecialization) { + bool &MemberOfUnknownSpecialization, + bool Disambiguation) { assert(getLangOpts().CPlusPlus && "No template names in C!"); DeclarationName TName; @@ -162,7 +204,8 @@ TemplateNameKind Sema::isTemplateName(Scope *S, LookupResult R(*this, TName, Name.getBeginLoc(), LookupOrdinaryName); if (LookupTemplateName(R, S, SS, ObjectType, EnteringContext, MemberOfUnknownSpecialization, SourceLocation(), - &AssumedTemplate)) + &AssumedTemplate, + /*AllowTypoCorrection=*/!Disambiguation)) return TNK_Non_template; if (AssumedTemplate != AssumedTemplateKind::None) { @@ -328,11 +371,15 @@ bool Sema::LookupTemplateName(LookupResult &Found, QualType ObjectType, bool EnteringContext, bool &MemberOfUnknownSpecialization, - SourceLocation TemplateKWLoc, - AssumedTemplateKind *ATK) { + RequiredTemplateKind RequiredTemplate, + AssumedTemplateKind *ATK, + bool AllowTypoCorrection) { if (ATK) *ATK = AssumedTemplateKind::None; + if (SS.isInvalid()) + return true; + Found.setTemplateNameLookup(true); // Determine where to perform name lookup @@ -342,7 +389,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, if (!ObjectType.isNull()) { // This nested-name-specifier occurs in a member access expression, e.g., // x->B::f, and we are looking into the type of the object. - assert(!SS.isSet() && "ObjectType and scope specifier cannot coexist"); + assert(SS.isEmpty() && "ObjectType and scope specifier cannot coexist"); LookupCtx = computeDeclContext(ObjectType); IsDependent = !LookupCtx && ObjectType->isDependentType(); assert((IsDependent || !ObjectType->isIncompleteType() || @@ -368,11 +415,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, Found.clear(); return false; } - } else if (SS.isSet()) { + } else if (SS.isNotEmpty()) { // This nested-name-specifier occurs after another nested-name-specifier, // so long into the context associated with the prior nested-name-specifier. LookupCtx = computeDeclContext(SS, EnteringContext); - IsDependent = !LookupCtx; + IsDependent = !LookupCtx && isDependentScopeSpecifier(SS); // The declaration context must be complete. if (LookupCtx && RequireCompleteDeclContext(SS, LookupCtx)) @@ -399,7 +446,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, IsDependent |= Found.wasNotFoundInCurrentInstantiation(); } - if (!SS.isSet() && (ObjectType.isNull() || Found.empty())) { + if (SS.isEmpty() && (ObjectType.isNull() || Found.empty())) { // C++ [basic.lookup.classref]p1: // In a class member access expression (5.2.5), if the . or -> token is // immediately followed by an identifier followed by a <, the @@ -426,7 +473,8 @@ bool Sema::LookupTemplateName(LookupResult &Found, if (Found.isAmbiguous()) return false; - if (ATK && !SS.isSet() && ObjectType.isNull() && TemplateKWLoc.isInvalid()) { + if (ATK && SS.isEmpty() && ObjectType.isNull() && + !RequiredTemplate.hasTemplateKeyword()) { // C++2a [temp.names]p2: // A name is also considered to refer to a template if it is an // unqualified-id followed by a < and name lookup finds either one or more @@ -436,7 +484,7 @@ bool Sema::LookupTemplateName(LookupResult &Found, // all language modes, and diagnose the empty lookup in ActOnCallExpr if we // successfully form a call to an undeclared template-id. bool AllFunctions = - getLangOpts().CPlusPlus2a && + getLangOpts().CPlusPlus20 && std::all_of(Found.begin(), Found.end(), [](NamedDecl *ND) { return isa<FunctionDecl>(ND->getUnderlyingDecl()); }); @@ -452,8 +500,9 @@ bool Sema::LookupTemplateName(LookupResult &Found, } } - if (Found.empty() && !IsDependent) { - // If we did not find any names, attempt to correct any typos. + if (Found.empty() && !IsDependent && AllowTypoCorrection) { + // If we did not find any names, and this is not a disambiguation, attempt + // to correct any typos. DeclarationName Name = Found.getLookupName(); Found.clear(); // Simple filter callback that, for keywords, only accepts the C++ *_cast @@ -497,9 +546,11 @@ bool Sema::LookupTemplateName(LookupResult &Found, // If a 'template' keyword was used, a lookup that finds only non-template // names is an error. - if (ExampleLookupResult && TemplateKWLoc.isValid()) { + if (ExampleLookupResult && RequiredTemplate) { Diag(Found.getNameLoc(), diag::err_template_kw_refers_to_non_template) - << Found.getLookupName() << SS.getRange(); + << Found.getLookupName() << SS.getRange() + << RequiredTemplate.hasTemplateKeyword() + << RequiredTemplate.getTemplateKeywordLoc(); Diag(ExampleLookupResult->getUnderlyingDecl()->getLocation(), diag::note_template_kw_refers_to_non_template) << Found.getLookupName(); @@ -1050,7 +1101,8 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } -bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, +bool Sema::ActOnTypeConstraint(const CXXScopeSpec &SS, + TemplateIdAnnotation *TypeConstr, TemplateTypeParmDecl *ConstrainedParameter, SourceLocation EllipsisLoc) { ConceptDecl *CD = @@ -1080,14 +1132,57 @@ bool Sema::ActOnTypeConstraint(TemplateIdAnnotation *TypeConstr, makeTemplateArgumentListInfo(*this, *TypeConstr); } return AttachTypeConstraint( - TypeConstr->SS.isSet() ? TypeConstr->SS.getWithLocInContext(Context) : - NestedNameSpecifierLoc(), + SS.isSet() ? SS.getWithLocInContext(Context) : NestedNameSpecifierLoc(), DeclarationNameInfo(DeclarationName(TypeConstr->Name), TypeConstr->TemplateNameLoc), CD, TypeConstr->LAngleLoc.isValid() ? &TemplateArgs : nullptr, ConstrainedParameter, EllipsisLoc); } +template<typename ArgumentLocAppender> +static ExprResult formImmediatelyDeclaredConstraint( + Sema &S, NestedNameSpecifierLoc NS, DeclarationNameInfo NameInfo, + ConceptDecl *NamedConcept, SourceLocation LAngleLoc, + SourceLocation RAngleLoc, QualType ConstrainedType, + SourceLocation ParamNameLoc, ArgumentLocAppender Appender, + SourceLocation EllipsisLoc) { + + TemplateArgumentListInfo ConstraintArgs; + ConstraintArgs.addArgument( + S.getTrivialTemplateArgumentLoc(TemplateArgument(ConstrainedType), + /*NTTPType=*/QualType(), ParamNameLoc)); + + ConstraintArgs.setRAngleLoc(RAngleLoc); + ConstraintArgs.setLAngleLoc(LAngleLoc); + Appender(ConstraintArgs); + + // C++2a [temp.param]p4: + // [...] This constraint-expression E is called the immediately-declared + // constraint of T. [...] + CXXScopeSpec SS; + SS.Adopt(NS); + ExprResult ImmediatelyDeclaredConstraint = S.CheckConceptTemplateId( + SS, /*TemplateKWLoc=*/SourceLocation(), NameInfo, + /*FoundDecl=*/NamedConcept, NamedConcept, &ConstraintArgs); + if (ImmediatelyDeclaredConstraint.isInvalid() || !EllipsisLoc.isValid()) + return ImmediatelyDeclaredConstraint; + + // C++2a [temp.param]p4: + // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). + // + // We have the following case: + // + // template<typename T> concept C1 = true; + // template<C1... T> struct s1; + // + // The constraint: (C1<T> && ...) + return S.BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), + ImmediatelyDeclaredConstraint.get(), BO_LAnd, + EllipsisLoc, /*RHS=*/nullptr, + /*RParenLoc=*/SourceLocation(), + /*NumExpansions=*/None); +} + /// Attach a type-constraint to a template parameter. /// \returns true if an error occured. This can happen if the /// immediately-declared constraint could not be formed (e.g. incorrect number @@ -1106,51 +1201,21 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, *TemplateArgs) : nullptr; QualType ParamAsArgument(ConstrainedParameter->getTypeForDecl(), 0); - TemplateArgumentListInfo ConstraintArgs; - ConstraintArgs.addArgument( - TemplateArgumentLoc( - TemplateArgument(ParamAsArgument), - TemplateArgumentLocInfo( - Context.getTrivialTypeSourceInfo(ParamAsArgument, - ConstrainedParameter->getLocation())))); - if (TemplateArgs) { - ConstraintArgs.setRAngleLoc(TemplateArgs->getRAngleLoc()); - ConstraintArgs.setLAngleLoc(TemplateArgs->getLAngleLoc()); - for (const TemplateArgumentLoc &ArgLoc : TemplateArgs->arguments()) - ConstraintArgs.addArgument(ArgLoc); - } - // C++2a [temp.param]p4: - // [...] This constraint-expression E is called the immediately-declared - // constraint of T. [...] - CXXScopeSpec SS; - SS.Adopt(NS); - ExprResult ImmediatelyDeclaredConstraint = CheckConceptTemplateId(SS, - /*TemplateKWLoc=*/SourceLocation(), NameInfo, /*FoundDecl=*/NamedConcept, - NamedConcept, &ConstraintArgs); + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, NS, NameInfo, NamedConcept, + TemplateArgs ? TemplateArgs->getLAngleLoc() : SourceLocation(), + TemplateArgs ? TemplateArgs->getRAngleLoc() : SourceLocation(), + ParamAsArgument, ConstrainedParameter->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + if (TemplateArgs) + for (const auto &ArgLoc : TemplateArgs->arguments()) + ConstraintArgs.addArgument(ArgLoc); + }, EllipsisLoc); if (ImmediatelyDeclaredConstraint.isInvalid()) return true; - if (ConstrainedParameter->isParameterPack()) { - // C++2a [temp.param]p4: - // [...] If T is not a pack, then E is E', otherwise E is (E' && ...). - // - // We have the following case: - // - // template<typename T> concept C1 = true; - // template<C1... T> struct s1; - // - // The constraint: (C1<T> && ...) - ImmediatelyDeclaredConstraint = - BuildCXXFoldExpr(/*LParenLoc=*/SourceLocation(), - ImmediatelyDeclaredConstraint.get(), BO_LAnd, - EllipsisLoc, /*RHS=*/nullptr, - /*RParenLoc=*/SourceLocation(), - /*NumExpansions=*/None).get(); - if (ImmediatelyDeclaredConstraint.isInvalid()) - return true; - } - ConstrainedParameter->setTypeConstraint(NS, NameInfo, /*FoundDecl=*/NamedConcept, NamedConcept, ArgsAsWritten, @@ -1158,6 +1223,38 @@ bool Sema::AttachTypeConstraint(NestedNameSpecifierLoc NS, return false; } +bool Sema::AttachTypeConstraint(AutoTypeLoc TL, NonTypeTemplateParmDecl *NTTP, + SourceLocation EllipsisLoc) { + if (NTTP->getType() != TL.getType() || + TL.getAutoKeyword() != AutoTypeKeyword::Auto) { + Diag(NTTP->getTypeSourceInfo()->getTypeLoc().getBeginLoc(), + diag::err_unsupported_placeholder_constraint) + << NTTP->getTypeSourceInfo()->getTypeLoc().getSourceRange(); + return true; + } + // FIXME: Concepts: This should be the type of the placeholder, but this is + // unclear in the wording right now. + DeclRefExpr *Ref = BuildDeclRefExpr(NTTP, NTTP->getType(), VK_RValue, + NTTP->getLocation()); + if (!Ref) + return true; + ExprResult ImmediatelyDeclaredConstraint = + formImmediatelyDeclaredConstraint( + *this, TL.getNestedNameSpecifierLoc(), TL.getConceptNameInfo(), + TL.getNamedConcept(), TL.getLAngleLoc(), TL.getRAngleLoc(), + BuildDecltypeType(Ref, NTTP->getLocation()), NTTP->getLocation(), + [&] (TemplateArgumentListInfo &ConstraintArgs) { + for (unsigned I = 0, C = TL.getNumArgs(); I != C; ++I) + ConstraintArgs.addArgument(TL.getArgLoc(I)); + }, EllipsisLoc); + if (ImmediatelyDeclaredConstraint.isInvalid() || + !ImmediatelyDeclaredConstraint.isUsable()) + return true; + + NTTP->setPlaceholderTypeConstraint(ImmediatelyDeclaredConstraint.get()); + return false; +} + /// Check that the type of a non-type template parameter is /// well-formed. /// @@ -1242,11 +1339,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, // Check that we have valid decl-specifiers specified. auto CheckValidDeclSpecifiers = [this, &D] { // C++ [temp.param] - // p1 + // p1 // template-parameter: // ... // parameter-declaration - // p2 + // p2 // ... A storage class shall not be specified in a template-parameter // declaration. // [dcl.typedef]p1: @@ -1319,6 +1416,11 @@ NamedDecl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, TInfo); Param->setAccess(AS_public); + if (AutoTypeLoc TL = TInfo->getTypeLoc().getContainedAutoTypeLoc()) + if (TL.isConstrained()) + if (AttachTypeConstraint(TL, Param, D.getEllipsisLoc())) + Invalid = true; + if (Invalid) Param->setInvalidDecl(); @@ -1844,16 +1946,46 @@ namespace { /// constructor to a deduction guide. class ExtractTypeForDeductionGuide : public TreeTransform<ExtractTypeForDeductionGuide> { + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs; + public: typedef TreeTransform<ExtractTypeForDeductionGuide> Base; - ExtractTypeForDeductionGuide(Sema &SemaRef) : Base(SemaRef) {} + ExtractTypeForDeductionGuide( + Sema &SemaRef, + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) + : Base(SemaRef), MaterializedTypedefs(MaterializedTypedefs) {} TypeSourceInfo *transform(TypeSourceInfo *TSI) { return TransformType(TSI); } QualType TransformTypedefType(TypeLocBuilder &TLB, TypedefTypeLoc TL) { - return TransformType( - TLB, - TL.getTypedefNameDecl()->getTypeSourceInfo()->getTypeLoc()); + ASTContext &Context = SemaRef.getASTContext(); + TypedefNameDecl *OrigDecl = TL.getTypedefNameDecl(); + TypeLocBuilder InnerTLB; + QualType Transformed = + TransformType(InnerTLB, OrigDecl->getTypeSourceInfo()->getTypeLoc()); + TypeSourceInfo *TSI = + TransformType(InnerTLB.getTypeSourceInfo(Context, Transformed)); + + TypedefNameDecl *Decl = nullptr; + + if (isa<TypeAliasDecl>(OrigDecl)) + Decl = TypeAliasDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + else { + assert(isa<TypedefDecl>(OrigDecl) && "Not a Type alias or typedef"); + Decl = TypedefDecl::Create( + Context, Context.getTranslationUnitDecl(), OrigDecl->getBeginLoc(), + OrigDecl->getLocation(), OrigDecl->getIdentifier(), TSI); + } + + MaterializedTypedefs.push_back(Decl); + + QualType TDTy = Context.getTypedefType(Decl); + TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(TDTy); + TypedefTL.setNameLoc(TL.getNameLoc()); + + return TDTy; } }; @@ -1905,6 +2037,7 @@ struct ConvertConstructorToDeductionGuideTransform { // a list of substituted template arguments as we go. for (NamedDecl *Param : *InnerParams) { MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); Args.addOuterTemplateArguments(SubstArgs); Args.addOuterRetainedLevel(); NamedDecl *NewParam = transformTemplateParameter(Param, Args); @@ -1924,6 +2057,7 @@ struct ConvertConstructorToDeductionGuideTransform { // substitute references to the old parameters into references to the // new ones. MultiLevelTemplateArgumentList Args; + Args.setKind(TemplateSubstitutionKind::Rewrite); if (FTD) { Args.addOuterTemplateArguments(SubstArgs); Args.addOuterRetainedLevel(); @@ -1938,14 +2072,16 @@ struct ConvertConstructorToDeductionGuideTransform { // new ones. TypeLocBuilder TLB; SmallVector<ParmVarDecl*, 8> Params; - QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args); + SmallVector<TypedefNameDecl *, 4> MaterializedTypedefs; + QualType NewType = transformFunctionProtoType(TLB, FPTL, Params, Args, + MaterializedTypedefs); if (NewType.isNull()) return nullptr; TypeSourceInfo *NewTInfo = TLB.getTypeSourceInfo(SemaRef.Context, NewType); return buildDeductionGuide(TemplateParams, CD->getExplicitSpecifier(), NewTInfo, CD->getBeginLoc(), CD->getLocation(), - CD->getEndLoc()); + CD->getEndLoc(), MaterializedTypedefs); } /// Build a deduction guide with the specified parameter types. @@ -1996,12 +2132,14 @@ private: if (const auto *TC = TTP->getTypeConstraint()) { TemplateArgumentListInfo TransformedArgs; const auto *ArgsAsWritten = TC->getTemplateArgsAsWritten(); - if (SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), + if (!ArgsAsWritten || + SemaRef.Subst(ArgsAsWritten->getTemplateArgs(), ArgsAsWritten->NumTemplateArgs, TransformedArgs, Args)) SemaRef.AttachTypeConstraint( TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &TransformedArgs, NewTTP, + TC->getNamedConcept(), ArgsAsWritten ? &TransformedArgs : nullptr, + NewTTP, NewTTP->isParameterPack() ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) ->getEllipsisLoc() @@ -2038,16 +2176,18 @@ private: return NewParam; } - QualType transformFunctionProtoType(TypeLocBuilder &TLB, - FunctionProtoTypeLoc TL, - SmallVectorImpl<ParmVarDecl*> &Params, - MultiLevelTemplateArgumentList &Args) { + QualType transformFunctionProtoType( + TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, + SmallVectorImpl<ParmVarDecl *> &Params, + MultiLevelTemplateArgumentList &Args, + SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { SmallVector<QualType, 4> ParamTypes; const FunctionProtoType *T = TL.getTypePtr(); // -- The types of the function parameters are those of the constructor. for (auto *OldParam : TL.getParams()) { - ParmVarDecl *NewParam = transformFunctionTypeParam(OldParam, Args); + ParmVarDecl *NewParam = + transformFunctionTypeParam(OldParam, Args, MaterializedTypedefs); if (!NewParam) return QualType(); ParamTypes.push_back(NewParam->getType()); @@ -2089,9 +2229,9 @@ private: return Result; } - ParmVarDecl * - transformFunctionTypeParam(ParmVarDecl *OldParam, - MultiLevelTemplateArgumentList &Args) { + ParmVarDecl *transformFunctionTypeParam( + ParmVarDecl *OldParam, MultiLevelTemplateArgumentList &Args, + llvm::SmallVectorImpl<TypedefNameDecl *> &MaterializedTypedefs) { TypeSourceInfo *OldDI = OldParam->getTypeSourceInfo(); TypeSourceInfo *NewDI; if (auto PackTL = OldDI->getTypeLoc().getAs<PackExpansionTypeLoc>()) { @@ -2114,15 +2254,22 @@ private: // members of the current instantiations with the definitions of those // typedefs, avoiding triggering instantiation of the deduced type during // deduction. - NewDI = ExtractTypeForDeductionGuide(SemaRef).transform(NewDI); + NewDI = ExtractTypeForDeductionGuide(SemaRef, MaterializedTypedefs) + .transform(NewDI); // Resolving a wording defect, we also inherit default arguments from the // constructor. ExprResult NewDefArg; if (OldParam->hasDefaultArg()) { - NewDefArg = SemaRef.SubstExpr(OldParam->getDefaultArg(), Args); - if (NewDefArg.isInvalid()) - return nullptr; + // We don't care what the value is (we won't use it); just create a + // placeholder to indicate there is a default argument. + QualType ParamTy = NewDI->getType(); + NewDefArg = new (SemaRef.Context) + OpaqueValueExpr(OldParam->getDefaultArg()->getBeginLoc(), + ParamTy.getNonLValueExprType(SemaRef.Context), + ParamTy->isLValueReferenceType() ? VK_LValue : + ParamTy->isRValueReferenceType() ? VK_XValue : + VK_RValue); } ParmVarDecl *NewParam = ParmVarDecl::Create(SemaRef.Context, DC, @@ -2139,10 +2286,11 @@ private: return NewParam; } - NamedDecl *buildDeductionGuide(TemplateParameterList *TemplateParams, - ExplicitSpecifier ES, TypeSourceInfo *TInfo, - SourceLocation LocStart, SourceLocation Loc, - SourceLocation LocEnd) { + FunctionTemplateDecl *buildDeductionGuide( + TemplateParameterList *TemplateParams, ExplicitSpecifier ES, + TypeSourceInfo *TInfo, SourceLocation LocStart, SourceLocation Loc, + SourceLocation LocEnd, + llvm::ArrayRef<TypedefNameDecl *> MaterializedTypedefs = {}) { DeclarationNameInfo Name(DeductionGuideName, Loc); ArrayRef<ParmVarDecl *> Params = TInfo->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(); @@ -2156,6 +2304,8 @@ private: for (auto *Param : Params) Param->setDeclContext(Guide); + for (auto *TD : MaterializedTypedefs) + TD->setDeclContext(Guide); auto *GuideTemplate = FunctionTemplateDecl::Create( SemaRef.Context, DC, Loc, DeductionGuideName, TemplateParams, Guide); @@ -2762,7 +2912,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( SourceLocation DeclStartLoc, SourceLocation DeclLoc, const CXXScopeSpec &SS, TemplateIdAnnotation *TemplateId, ArrayRef<TemplateParameterList *> ParamLists, bool IsFriend, - bool &IsMemberSpecialization, bool &Invalid) { + bool &IsMemberSpecialization, bool &Invalid, bool SuppressDiagnostic) { IsMemberSpecialization = false; Invalid = false; @@ -2870,8 +3020,9 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( auto CheckExplicitSpecialization = [&](SourceRange Range, bool Recovery) { if (SawNonEmptyTemplateParameterList) { - Diag(DeclLoc, diag::err_specialize_member_of_template) - << !Recovery << Range; + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_specialize_member_of_template) + << !Recovery << Range; Invalid = true; IsMemberSpecialization = false; return true; @@ -2892,9 +3043,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( else ExpectedTemplateLoc = DeclStartLoc; - Diag(DeclLoc, diag::err_template_spec_needs_header) - << Range - << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_header) + << Range + << FixItHint::CreateInsertion(ExpectedTemplateLoc, "template<> "); return false; }; @@ -2984,12 +3136,13 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() > 0) { // The header has template parameters when it shouldn't. Complain. - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - diag::err_template_param_list_matches_nontemplate) - << T - << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), - ParamLists[ParamIdx]->getRAngleLoc()) - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + diag::err_template_param_list_matches_nontemplate) + << T + << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), + ParamLists[ParamIdx]->getRAngleLoc()) + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; return nullptr; } @@ -3025,7 +3178,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ExpectedTemplateParams && !TemplateParameterListsAreEqual(ParamLists[ParamIdx], ExpectedTemplateParams, - true, TPL_TemplateMatch)) + !SuppressDiagnostic, TPL_TemplateMatch)) Invalid = true; if (!Invalid && @@ -3037,9 +3190,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( continue; } - Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) - << T - << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); + if (!SuppressDiagnostic) + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) + << T + << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); Invalid = true; continue; } @@ -3075,16 +3229,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( AllExplicitSpecHeaders = false; } - Diag(ParamLists[ParamIdx]->getTemplateLoc(), - AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers - : diag::err_template_spec_extra_headers) - << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), - ParamLists[ParamLists.size() - 2]->getRAngleLoc()); + if (!SuppressDiagnostic) + Diag(ParamLists[ParamIdx]->getTemplateLoc(), + AllExplicitSpecHeaders ? diag::warn_template_spec_extra_headers + : diag::err_template_spec_extra_headers) + << SourceRange(ParamLists[ParamIdx]->getTemplateLoc(), + ParamLists[ParamLists.size() - 2]->getRAngleLoc()); // If there was a specialization somewhere, such that 'template<>' is // not required, and there were any 'template<>' headers, note where the // specialization occurred. - if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) + if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader && + !SuppressDiagnostic) Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); @@ -3360,6 +3516,10 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, DTN->getIdentifier(), TemplateArgs); + if (Name.getAsAssumedTemplateName() && + resolveAssumedTemplateNameAsType(/*Scope*/nullptr, Name, TemplateLoc)) + return QualType(); + TemplateDecl *Template = Name.getAsTemplateDecl(); if (!Template || isa<FunctionTemplateDecl>(Template) || isa<VarTemplateDecl>(Template) || isa<ConceptDecl>(Template)) { @@ -3399,9 +3559,8 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; TemplateArgLists.addOuterTemplateArguments(&StackTemplateArgs); - unsigned Depth = AliasTemplate->getTemplateParameters()->getDepth(); - for (unsigned I = 0; I < Depth; ++I) - TemplateArgLists.addOuterTemplateArguments(None); + TemplateArgLists.addOuterRetainedLevels( + AliasTemplate->getTemplateParameters()->getDepth()); LocalInstantiationScope Scope(*this); InstantiatingTemplate Inst(*this, TemplateLoc, Template); @@ -3707,6 +3866,9 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, SourceLocation LAngleLoc, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { + if (SS.isInvalid()) + return TypeResult(true); + TemplateName Template = TemplateD.get(); // Translate the parser's template argument list in our AST format. @@ -4044,7 +4206,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( if (isSameAsPrimaryTemplate(VarTemplate->getTemplateParameters(), Converted) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -4510,21 +4672,28 @@ Sema::BuildQualifiedTemplateIdExpr(CXXScopeSpec &SS, return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*ADL*/ false, TemplateArgs); } -/// Form a dependent template name. +/// Form a template name from a name that is syntactically required to name a +/// template, either due to use of the 'template' keyword or because a name in +/// this syntactic context is assumed to name a template (C++ [temp.names]p2-4). +/// +/// This action forms a template name given the name of the template and its +/// optional scope specifier. This is used when the 'template' keyword is used +/// or when the parsing context unambiguously treats a following '<' as +/// introducing a template argument list. Note that this may produce a +/// non-dependent template name if we can perform the lookup now and identify +/// the named template. /// -/// This action forms a dependent template name given the template -/// name and its (presumably dependent) scope specifier. For -/// example, given "MetaFun::template apply", the scope specifier \p -/// SS will be "MetaFun::", \p TemplateKWLoc contains the location +/// For example, given "x.MetaFun::template apply", the scope specifier +/// \p SS will be "MetaFun::", \p TemplateKWLoc contains the location /// of the "template" keyword, and "apply" is the \p Name. -TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, - CXXScopeSpec &SS, - SourceLocation TemplateKWLoc, - const UnqualifiedId &Name, - ParsedType ObjectType, - bool EnteringContext, - TemplateTy &Result, - bool AllowInjectedClassName) { +TemplateNameKind Sema::ActOnTemplateName(Scope *S, + CXXScopeSpec &SS, + SourceLocation TemplateKWLoc, + const UnqualifiedId &Name, + ParsedType ObjectType, + bool EnteringContext, + TemplateTy &Result, + bool AllowInjectedClassName) { if (TemplateKWLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TemplateKWLoc, getLangOpts().CPlusPlus11 ? @@ -4532,95 +4701,115 @@ TemplateNameKind Sema::ActOnDependentTemplateName(Scope *S, diag::ext_template_outside_of_template) << FixItHint::CreateRemoval(TemplateKWLoc); + if (SS.isInvalid()) + return TNK_Non_template; + + // Figure out where isTemplateName is going to look. DeclContext *LookupCtx = nullptr; - if (SS.isSet()) + if (SS.isNotEmpty()) LookupCtx = computeDeclContext(SS, EnteringContext); - if (!LookupCtx && ObjectType) - LookupCtx = computeDeclContext(ObjectType.get()); - if (LookupCtx) { - // C++0x [temp.names]p5: - // If a name prefixed by the keyword template is not the name of - // a template, the program is ill-formed. [Note: the keyword - // template may not be applied to non-template members of class - // templates. -end note ] [ Note: as is the case with the - // typename prefix, the template prefix is allowed in cases - // where it is not strictly necessary; i.e., when the - // nested-name-specifier or the expression on the left of the -> - // or . is not dependent on a template-parameter, or the use - // does not appear in the scope of a template. -end note] - // - // Note: C++03 was more strict here, because it banned the use of - // the "template" keyword prior to a template-name that was not a - // dependent name. C++ DR468 relaxed this requirement (the - // "template" keyword is now permitted). We follow the C++0x - // rules, even in C++03 mode with a warning, retroactively applying the DR. - bool MemberOfUnknownSpecialization; - TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, - ObjectType, EnteringContext, Result, - MemberOfUnknownSpecialization); - if (TNK == TNK_Non_template && MemberOfUnknownSpecialization) { - // This is a dependent template. Handle it below. - } else if (TNK == TNK_Non_template) { - // Do the lookup again to determine if this is a "nothing found" case or - // a "not a template" case. FIXME: Refactor isTemplateName so we don't - // need to do this. - DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); - LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), - LookupOrdinaryName); - bool MOUS; - if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, - MOUS, TemplateKWLoc) && !R.isAmbiguous()) + else if (ObjectType) + LookupCtx = computeDeclContext(GetTypeFromParser(ObjectType)); + + // C++0x [temp.names]p5: + // If a name prefixed by the keyword template is not the name of + // a template, the program is ill-formed. [Note: the keyword + // template may not be applied to non-template members of class + // templates. -end note ] [ Note: as is the case with the + // typename prefix, the template prefix is allowed in cases + // where it is not strictly necessary; i.e., when the + // nested-name-specifier or the expression on the left of the -> + // or . is not dependent on a template-parameter, or the use + // does not appear in the scope of a template. -end note] + // + // Note: C++03 was more strict here, because it banned the use of + // the "template" keyword prior to a template-name that was not a + // dependent name. C++ DR468 relaxed this requirement (the + // "template" keyword is now permitted). We follow the C++0x + // rules, even in C++03 mode with a warning, retroactively applying the DR. + bool MemberOfUnknownSpecialization; + TemplateNameKind TNK = isTemplateName(S, SS, TemplateKWLoc.isValid(), Name, + ObjectType, EnteringContext, Result, + MemberOfUnknownSpecialization); + if (TNK != TNK_Non_template) { + // We resolved this to a (non-dependent) template name. Return it. + auto *LookupRD = dyn_cast_or_null<CXXRecordDecl>(LookupCtx); + if (!AllowInjectedClassName && SS.isNotEmpty() && LookupRD && + Name.getKind() == UnqualifiedIdKind::IK_Identifier && + Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) { + // C++14 [class.qual]p2: + // In a lookup in which function names are not ignored and the + // nested-name-specifier nominates a class C, if the name specified + // [...] is the injected-class-name of C, [...] the name is instead + // considered to name the constructor + // + // We don't get here if naming the constructor would be valid, so we + // just reject immediately and recover by treating the + // injected-class-name as naming the template. + Diag(Name.getBeginLoc(), + diag::ext_out_of_line_qualified_id_type_names_constructor) + << Name.Identifier + << 0 /*injected-class-name used as template name*/ + << TemplateKWLoc.isValid(); + } + return TNK; + } + + if (!MemberOfUnknownSpecialization) { + // Didn't find a template name, and the lookup wasn't dependent. + // Do the lookup again to determine if this is a "nothing found" case or + // a "not a template" case. FIXME: Refactor isTemplateName so we don't + // need to do this. + DeclarationNameInfo DNI = GetNameFromUnqualifiedId(Name); + LookupResult R(*this, DNI.getName(), Name.getBeginLoc(), + LookupOrdinaryName); + bool MOUS; + // Tell LookupTemplateName that we require a template so that it diagnoses + // cases where it finds a non-template. + RequiredTemplateKind RTK = TemplateKWLoc.isValid() + ? RequiredTemplateKind(TemplateKWLoc) + : TemplateNameIsRequired; + if (!LookupTemplateName(R, S, SS, ObjectType.get(), EnteringContext, MOUS, + RTK, nullptr, /*AllowTypoCorrection=*/false) && + !R.isAmbiguous()) { + if (LookupCtx) Diag(Name.getBeginLoc(), diag::err_no_member) << DNI.getName() << LookupCtx << SS.getRange(); - return TNK_Non_template; - } else { - // We found something; return it. - auto *LookupRD = dyn_cast<CXXRecordDecl>(LookupCtx); - if (!AllowInjectedClassName && SS.isSet() && LookupRD && - Name.getKind() == UnqualifiedIdKind::IK_Identifier && - Name.Identifier && LookupRD->getIdentifier() == Name.Identifier) { - // C++14 [class.qual]p2: - // In a lookup in which function names are not ignored and the - // nested-name-specifier nominates a class C, if the name specified - // [...] is the injected-class-name of C, [...] the name is instead - // considered to name the constructor - // - // We don't get here if naming the constructor would be valid, so we - // just reject immediately and recover by treating the - // injected-class-name as naming the template. - Diag(Name.getBeginLoc(), - diag::ext_out_of_line_qualified_id_type_names_constructor) - << Name.Identifier - << 0 /*injected-class-name used as template name*/ - << 1 /*'template' keyword was used*/; - } - return TNK; + else + Diag(Name.getBeginLoc(), diag::err_undeclared_use) + << DNI.getName() << SS.getRange(); } + return TNK_Non_template; } NestedNameSpecifier *Qualifier = SS.getScopeRep(); switch (Name.getKind()) { case UnqualifiedIdKind::IK_Identifier: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, - Name.Identifier)); + Result = TemplateTy::make( + Context.getDependentTemplateName(Qualifier, Name.Identifier)); return TNK_Dependent_template_name; case UnqualifiedIdKind::IK_OperatorFunctionId: - Result = TemplateTy::make(Context.getDependentTemplateName(Qualifier, - Name.OperatorFunctionId.Operator)); + Result = TemplateTy::make(Context.getDependentTemplateName( + Qualifier, Name.OperatorFunctionId.Operator)); return TNK_Function_template; case UnqualifiedIdKind::IK_LiteralOperatorId: - llvm_unreachable("literal operator id cannot have a dependent scope"); + // This is a kind of template name, but can never occur in a dependent + // scope (literal operators can only be declared at namespace scope). + break; default: break; } - Diag(Name.getBeginLoc(), diag::err_template_kw_refers_to_non_template) + // This name cannot possibly name a dependent template. Diagnose this now + // rather than building a dependent template name that can never be valid. + Diag(Name.getBeginLoc(), + diag::err_template_kw_refers_to_dependent_non_template) << GetNameFromUnqualifiedId(Name).getName() << Name.getSourceRange() - << TemplateKWLoc; + << TemplateKWLoc.isValid() << TemplateKWLoc; return TNK_Non_template; } @@ -4655,10 +4844,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, CXXScopeSpec SS; DeclarationNameInfo NameInfo; - if (DeclRefExpr *ArgExpr = dyn_cast<DeclRefExpr>(Arg.getAsExpr())) { - SS.Adopt(ArgExpr->getQualifierLoc()); - NameInfo = ArgExpr->getNameInfo(); - } else if (DependentScopeDeclRefExpr *ArgExpr = + if (DependentScopeDeclRefExpr *ArgExpr = dyn_cast<DependentScopeDeclRefExpr>(Arg.getAsExpr())) { SS.Adopt(ArgExpr->getQualifierLoc()); NameInfo = ArgExpr->getNameInfo(); @@ -4677,6 +4863,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, if (Result.getAsSingle<TypeDecl>() || Result.getResultKind() == LookupResult::NotFoundInCurrentInstantiation) { + assert(SS.getScopeRep() && "dependent scope expr must has a scope!"); // Suggest that the user add 'typename' before the NNS. SourceLocation Loc = AL.getSourceRange().getBegin(); Diag(Loc, getLangOpts().MSVCCompat @@ -5716,6 +5903,11 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentSizedExtVectorType( return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitDependentSizedMatrixType( + const DependentSizedMatrixType *T) { + return Visit(T->getElementType()); +} + bool UnnamedLocalNoLinkageFinder::VisitDependentAddressSpaceType( const DependentAddressSpaceType *T) { return Visit(T->getPointeeType()); @@ -5734,6 +5926,11 @@ bool UnnamedLocalNoLinkageFinder::VisitExtVectorType(const ExtVectorType* T) { return Visit(T->getElementType()); } +bool UnnamedLocalNoLinkageFinder::VisitConstantMatrixType( + const ConstantMatrixType *T) { + return Visit(T->getElementType()); +} + bool UnnamedLocalNoLinkageFinder::VisitFunctionProtoType( const FunctionProtoType* T) { for (const auto &A : T->param_types()) { @@ -5815,7 +6012,9 @@ bool UnnamedLocalNoLinkageFinder::VisitDependentNameType( bool UnnamedLocalNoLinkageFinder::VisitDependentTemplateSpecializationType( const DependentTemplateSpecializationType* T) { - return VisitNestedNameSpecifier(T->getQualifier()); + if (auto *Q = T->getQualifier()) + return VisitNestedNameSpecifier(Q); + return false; } bool UnnamedLocalNoLinkageFinder::VisitPackExpansionType( @@ -5845,6 +6044,15 @@ bool UnnamedLocalNoLinkageFinder::VisitPipeType(const PipeType* T) { return false; } +bool UnnamedLocalNoLinkageFinder::VisitExtIntType(const ExtIntType *T) { + return false; +} + +bool UnnamedLocalNoLinkageFinder::VisitDependentExtIntType( + const DependentExtIntType *T) { + return false; +} + bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { if (Tag->getDeclContext()->isFunctionOrMethod()) { S.Diag(SR.getBegin(), @@ -5869,6 +6077,7 @@ bool UnnamedLocalNoLinkageFinder::VisitTagDecl(const TagDecl *Tag) { bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( NestedNameSpecifier *NNS) { + assert(NNS); if (NNS->getPrefix() && VisitNestedNameSpecifier(NNS->getPrefix())) return true; @@ -6177,8 +6386,11 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, Arg = subst->getReplacement()->IgnoreImpCasts(); } - DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg); - ValueDecl *Entity = DRE ? DRE->getDecl() : nullptr; + ValueDecl *Entity = nullptr; + if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Arg)) + Entity = DRE->getDecl(); + else if (CXXUuidofExpr *CUE = dyn_cast<CXXUuidofExpr>(Arg)) + Entity = CUE->getGuidDecl(); // If our parameter has pointer type, check for a null template value. if (ParamType->isPointerType() || ParamType->isNullPtrType()) { @@ -6205,16 +6417,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return false; } - if (isa<CXXUuidofExpr>(Arg)) { - if (CheckTemplateArgumentIsCompatibleWithParameter(S, Param, ParamType, - ArgIn, Arg, ArgType)) - return true; - - Converted = TemplateArgument(ArgIn); - return false; - } - - if (!DRE) { + if (!Entity) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); S.Diag(Param->getLocation(), diag::note_template_param_here); @@ -6241,13 +6444,14 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, FunctionDecl *Func = dyn_cast<FunctionDecl>(Entity); VarDecl *Var = dyn_cast<VarDecl>(Entity); + MSGuidDecl *Guid = dyn_cast<MSGuidDecl>(Entity); // A non-type template argument must refer to an object or function. - if (!Func && !Var) { + if (!Func && !Var && !Guid) { // We found something, but we don't know specifically what it is. S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_object_or_func) << Arg->getSourceRange(); - S.Diag(DRE->getDecl()->getLocation(), diag::note_template_arg_refers_here); + S.Diag(Entity->getLocation(), diag::note_template_arg_refers_here); return true; } @@ -6268,30 +6472,7 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, return true; } - if (Func) { - // If the template parameter has pointer type, the function decays. - if (ParamType->isPointerType() && !AddressTaken) - ArgType = S.Context.getPointerType(Func->getType()); - else if (AddressTaken && ParamType->isReferenceType()) { - // If we originally had an address-of operator, but the - // parameter has reference type, complain and (if things look - // like they will work) drop the address-of operator. - if (!S.Context.hasSameUnqualifiedType(Func->getType(), - ParamType.getNonReferenceType())) { - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } - - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType - << FixItHint::CreateRemoval(AddrOpLoc); - S.Diag(Param->getLocation(), diag::note_template_param_here); - - ArgType = Func->getType(); - } - } else { + if (Var) { // A value of reference type is not an object. if (Var->getType()->isReferenceType()) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_reference_var) @@ -6307,50 +6488,53 @@ CheckTemplateArgumentAddressOfObjectOrFunction(Sema &S, S.Diag(Var->getLocation(), diag::note_template_arg_refers_here); return true; } + } - // If the template parameter has pointer type, we must have taken - // the address of this object. - if (ParamType->isReferenceType()) { - if (AddressTaken) { - // If we originally had an address-of operator, but the - // parameter has reference type, complain and (if things look - // like they will work) drop the address-of operator. - if (!S.Context.hasSameUnqualifiedType(Var->getType(), - ParamType.getNonReferenceType())) { - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } + if (AddressTaken && ParamType->isReferenceType()) { + // If we originally had an address-of operator, but the + // parameter has reference type, complain and (if things look + // like they will work) drop the address-of operator. + if (!S.Context.hasSameUnqualifiedType(Entity->getType(), + ParamType.getNonReferenceType())) { + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType; + S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; + } - S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) - << ParamType - << FixItHint::CreateRemoval(AddrOpLoc); - S.Diag(Param->getLocation(), diag::note_template_param_here); + S.Diag(AddrOpLoc, diag::err_template_arg_address_of_non_pointer) + << ParamType + << FixItHint::CreateRemoval(AddrOpLoc); + S.Diag(Param->getLocation(), diag::note_template_param_here); - ArgType = Var->getType(); - } - } else if (!AddressTaken && ParamType->isPointerType()) { - if (Var->getType()->isArrayType()) { - // Array-to-pointer decay. - ArgType = S.Context.getArrayDecayedType(Var->getType()); - } else { - // If the template parameter has pointer type but the address of - // this object was not taken, complain and (possibly) recover by - // taking the address of the entity. - ArgType = S.Context.getPointerType(Var->getType()); - if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { - S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) - << ParamType; - S.Diag(Param->getLocation(), diag::note_template_param_here); - return true; - } + ArgType = Entity->getType(); + } + // If the template parameter has pointer type, either we must have taken the + // address or the argument must decay to a pointer. + if (!AddressTaken && ParamType->isPointerType()) { + if (Func) { + // Function-to-pointer decay. + ArgType = S.Context.getPointerType(Func->getType()); + } else if (Entity->getType()->isArrayType()) { + // Array-to-pointer decay. + ArgType = S.Context.getArrayDecayedType(Entity->getType()); + } else { + // If the template parameter has pointer type but the address of + // this object was not taken, complain and (possibly) recover by + // taking the address of the entity. + ArgType = S.Context.getPointerType(Entity->getType()); + if (!S.Context.hasSameUnqualifiedType(ArgType, ParamType)) { S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) - << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&"); - + << ParamType; S.Diag(Param->getLocation(), diag::note_template_param_here); + return true; } + + S.Diag(Arg->getBeginLoc(), diag::err_template_arg_not_address_of) + << ParamType << FixItHint::CreateInsertion(Arg->getBeginLoc(), "&"); + + S.Diag(Param->getLocation(), diag::note_template_param_here); } } @@ -6530,7 +6714,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, DeductionArg = PE->getPattern(); if (DeduceAutoType( Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), - DeductionArg, ParamType, Depth) == DAR_Failed) { + DeductionArg, ParamType, Depth, + // We do not check constraints right now because the + // immediately-declared constraint of the auto type is also an + // associated constraint, and will be checked along with the other + // associated constraints after checking the template argument list. + /*IgnoreConstraints=*/true) == DAR_Failed) { Diag(Arg->getExprLoc(), diag::err_non_type_template_parm_type_deduction_failure) << Param->getDeclName() << Param->getType() << Arg->getType() @@ -6670,12 +6859,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // -- a predefined __func__ variable APValue::LValueBase Base = Value.getLValueBase(); auto *VD = const_cast<ValueDecl *>(Base.dyn_cast<const ValueDecl *>()); - if (Base && !VD) { - auto *E = Base.dyn_cast<const Expr *>(); - if (E && isa<CXXUuidofExpr>(E)) { - Converted = TemplateArgument(ArgResult.get()->IgnoreImpCasts()); - break; - } + if (Base && (!VD || isa<LifetimeExtendedTemporaryDecl>(VD))) { Diag(Arg->getBeginLoc(), diag::err_template_arg_not_decl_ref) << Arg->getSourceRange(); return ExprError(); @@ -6762,7 +6946,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, QualType IntegerType = ParamType; if (const EnumType *Enum = IntegerType->getAs<EnumType>()) IntegerType = Enum->getDecl()->getIntegerType(); - Value = Value.extOrTrunc(Context.getTypeSize(IntegerType)); + Value = Value.extOrTrunc(IntegerType->isExtIntType() + ? Context.getIntWidth(IntegerType) + : Context.getTypeSize(IntegerType)); Converted = TemplateArgument(Context, Value, Context.getCanonicalType(ParamType)); @@ -6856,7 +7042,9 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // Coerce the template argument's value to the value it will have // based on the template parameter's type. - unsigned AllowedBits = Context.getTypeSize(IntegerType); + unsigned AllowedBits = IntegerType->isExtIntType() + ? Context.getIntWidth(IntegerType) + : Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) Value = Value.extOrTrunc(AllowedBits); Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); @@ -7102,6 +7290,11 @@ bool Sema::CheckTemplateTemplateArgument(TemplateTemplateParmDecl *Param, // [temp.constr.order]. SmallVector<const Expr *, 3> ParamsAC, TemplateAC; Params->getAssociatedConstraints(ParamsAC); + // C++2a[temp.arg.template]p3 + // [...] In this comparison, if P is unconstrained, the constraints on A + // are not considered. + if (ParamsAC.empty()) + return false; Template->getAssociatedConstraints(TemplateAC); bool IsParamAtLeastAsConstrained; if (IsAtLeastAsConstrained(Param, ParamsAC, Template, TemplateAC, @@ -7872,13 +8065,11 @@ bool Sema::CheckTemplatePartialSpecializationArgs( DeclResult Sema::ActOnClassTemplateSpecialization( Scope *S, unsigned TagSpec, TagUseKind TUK, SourceLocation KWLoc, - SourceLocation ModulePrivateLoc, TemplateIdAnnotation &TemplateId, - const ParsedAttributesView &Attr, + SourceLocation ModulePrivateLoc, CXXScopeSpec &SS, + TemplateIdAnnotation &TemplateId, const ParsedAttributesView &Attr, MultiTemplateParamsArg TemplateParameterLists, SkipBodyInfo *SkipBody) { assert(TUK != TUK_Reference && "References are not specializations"); - CXXScopeSpec &SS = TemplateId.SS; - // NOTE: KWLoc is the location of the tag keyword. This will instead // store the location of the outermost template keyword in the declaration. SourceLocation TemplateKWLoc = TemplateParameterLists.size() > 0 @@ -8048,7 +8239,7 @@ DeclResult Sema::ActOnClassTemplateSpecialization( if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization()) && - (!Context.getLangOpts().ConceptsTS || + (!Context.getLangOpts().CPlusPlus20 || !TemplateParams->hasAssociatedConstraints())) { // C++ [temp.class.spec]p9b3: // @@ -8274,7 +8465,7 @@ Decl *Sema::ActOnConceptDefinition(Scope *S, ConceptDecl *NewDecl = ConceptDecl::Create(Context, DC, NameLoc, Name, TemplateParameterLists.front(), ConstraintExpr); - + if (NewDecl->hasAssociatedConstraints()) { // C++2a [temp.concept]p4: // A concept shall not have associated constraints. @@ -10012,24 +10203,12 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, << FixItHint::CreateRemoval(TypenameLoc); NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); + TypeSourceInfo *TSI = nullptr; QualType T = CheckTypenameType(TypenameLoc.isValid()? ETK_Typename : ETK_None, - TypenameLoc, QualifierLoc, II, IdLoc); + TypenameLoc, QualifierLoc, II, IdLoc, &TSI, + /*DeducedTSTContext=*/true); if (T.isNull()) return true; - - TypeSourceInfo *TSI = Context.CreateTypeSourceInfo(T); - if (isa<DependentNameType>(T)) { - DependentNameTypeLoc TL = TSI->getTypeLoc().castAs<DependentNameTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.setNameLoc(IdLoc); - } else { - ElaboratedTypeLoc TL = TSI->getTypeLoc().castAs<ElaboratedTypeLoc>(); - TL.setElaboratedKeywordLoc(TypenameLoc); - TL.setQualifierLoc(QualifierLoc); - TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IdLoc); - } - return CreateParsedType(T, TSI); } @@ -10166,6 +10345,35 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, return true; } +QualType +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, + SourceLocation KeywordLoc, + NestedNameSpecifierLoc QualifierLoc, + const IdentifierInfo &II, + SourceLocation IILoc, + TypeSourceInfo **TSI, + bool DeducedTSTContext) { + QualType T = CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, II, IILoc, + DeducedTSTContext); + if (T.isNull()) + return QualType(); + + *TSI = Context.CreateTypeSourceInfo(T); + if (isa<DependentNameType>(T)) { + DependentNameTypeLoc TL = + (*TSI)->getTypeLoc().castAs<DependentNameTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.setNameLoc(IILoc); + } else { + ElaboratedTypeLoc TL = (*TSI)->getTypeLoc().castAs<ElaboratedTypeLoc>(); + TL.setElaboratedKeywordLoc(KeywordLoc); + TL.setQualifierLoc(QualifierLoc); + TL.getNamedTypeLoc().castAs<TypeSpecTypeLoc>().setNameLoc(IILoc); + } + return T; +} + /// Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType @@ -10173,32 +10381,38 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, - SourceLocation IILoc) { + SourceLocation IILoc, bool DeducedTSTContext) { CXXScopeSpec SS; SS.Adopt(QualifierLoc); - DeclContext *Ctx = computeDeclContext(SS); - if (!Ctx) { - // If the nested-name-specifier is dependent and couldn't be - // resolved to a type, build a typename type. - assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), - &II); + DeclContext *Ctx = nullptr; + if (QualifierLoc) { + Ctx = computeDeclContext(SS); + if (!Ctx) { + // If the nested-name-specifier is dependent and couldn't be + // resolved to a type, build a typename type. + assert(QualifierLoc.getNestedNameSpecifier()->isDependent()); + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), + &II); + } + + // If the nested-name-specifier refers to the current instantiation, + // the "typename" keyword itself is superfluous. In C++03, the + // program is actually ill-formed. However, DR 382 (in C++0x CD1) + // allows such extraneous "typename" keywords, and we retroactively + // apply this DR to C++03 code with only a warning. In any case we continue. + + if (RequireCompleteDeclContext(SS, Ctx)) + return QualType(); } - // If the nested-name-specifier refers to the current instantiation, - // the "typename" keyword itself is superfluous. In C++03, the - // program is actually ill-formed. However, DR 382 (in C++0x CD1) - // allows such extraneous "typename" keywords, and we retroactively - // apply this DR to C++03 code with only a warning. In any case we continue. - - if (RequireCompleteDeclContext(SS, Ctx)) - return QualType(); - DeclarationName Name(&II); LookupResult Result(*this, Name, IILoc, LookupOrdinaryName); - LookupQualifiedName(Result, Ctx, SS); + if (Ctx) + LookupQualifiedName(Result, Ctx, SS); + else + LookupName(Result, CurScope); unsigned DiagID = 0; Decl *Referenced = nullptr; switch (Result.getResultKind()) { @@ -10207,7 +10421,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // a more specific diagnostic. SourceRange CondRange; Expr *Cond = nullptr; - if (isEnableIf(QualifierLoc, II, CondRange, Cond)) { + if (Ctx && isEnableIf(QualifierLoc, II, CondRange, Cond)) { // If we have a condition, narrow it down to the specific failed // condition. if (Cond) { @@ -10223,12 +10437,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, return QualType(); } - Diag(CondRange.getBegin(), diag::err_typename_nested_not_found_enable_if) + Diag(CondRange.getBegin(), + diag::err_typename_nested_not_found_enable_if) << Ctx << CondRange; return QualType(); } - DiagID = diag::err_typename_nested_not_found; + DiagID = Ctx ? diag::err_typename_nested_not_found + : diag::err_unknown_typename; break; } @@ -10294,6 +10510,19 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // is a placeholder for a deduced class type [...]. if (getLangOpts().CPlusPlus17) { if (auto *TD = getAsTypeTemplateDecl(Result.getFoundDecl())) { + if (!DeducedTSTContext) { + QualType T(QualifierLoc + ? QualifierLoc.getNestedNameSpecifier()->getAsType() + : nullptr, 0); + if (!T.isNull()) + Diag(IILoc, diag::err_dependent_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)) << T; + else + Diag(IILoc, diag::err_deduced_tst) + << (int)getTemplateNameKindForDiagnostics(TemplateName(TD)); + Diag(TD->getLocation(), diag::note_template_decl_here); + return QualType(); + } return Context.getElaboratedType( Keyword, QualifierLoc.getNestedNameSpecifier(), Context.getDeducedTemplateSpecializationType(TemplateName(TD), @@ -10301,12 +10530,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, } } - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = Result.getFoundDecl(); break; case LookupResult::FoundOverloaded: - DiagID = diag::err_typename_nested_not_type; + DiagID = Ctx ? diag::err_typename_nested_not_type + : diag::err_typename_not_type; Referenced = *Result.begin(); break; @@ -10318,9 +10549,14 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // type. Emit an appropriate diagnostic and return an error. SourceRange FullRange(KeywordLoc.isValid() ? KeywordLoc : SS.getBeginLoc(), IILoc); - Diag(IILoc, DiagID) << FullRange << Name << Ctx; + if (Ctx) + Diag(IILoc, DiagID) << FullRange << Name << Ctx; + else + Diag(IILoc, DiagID) << FullRange << Name; if (Referenced) - Diag(Referenced->getLocation(), diag::note_typename_refers_here) + Diag(Referenced->getLocation(), + Ctx ? diag::note_typename_member_refers_here + : diag::note_typename_refers_here) << Name; return QualType(); } @@ -10515,7 +10751,7 @@ Sema::getTemplateArgumentBindingsText(const TemplateParameterList *Params, } Out << ']'; - return Out.str(); + return std::string(Out.str()); } void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, diff --git a/clang/lib/Sema/SemaTemplateDeduction.cpp b/clang/lib/Sema/SemaTemplateDeduction.cpp index 1b9f1b2144d1..5392be57a3aa 100644 --- a/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -355,7 +355,7 @@ checkDeducedTemplateArguments(ASTContext &Context, TemplateArgument Merged = checkDeducedTemplateArguments( Context, DeducedTemplateArgument(*XA, X.wasDeducedFromArrayBound()), DeducedTemplateArgument(*YA, Y.wasDeducedFromArrayBound())); - if (Merged.isNull()) + if (Merged.isNull() && !(XA->isNull() && YA->isNull())) return DeducedTemplateArgument(); NewPack.push_back(Merged); } @@ -724,38 +724,49 @@ private: // Compute the set of template parameter indices that correspond to // parameter packs expanded by the pack expansion. llvm::SmallBitVector SawIndices(TemplateParams->size()); + llvm::SmallVector<TemplateArgument, 4> ExtraDeductions; auto AddPack = [&](unsigned Index) { if (SawIndices[Index]) return; SawIndices[Index] = true; addPack(Index); + + // Deducing a parameter pack that is a pack expansion also constrains the + // packs appearing in that parameter to have the same deduced arity. Also, + // in C++17 onwards, deducing a non-type template parameter deduces its + // type, so we need to collect the pending deduced values for those packs. + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>( + TemplateParams->getParam(Index))) { + if (!NTTP->isExpandedParameterPack()) + if (auto *Expansion = dyn_cast<PackExpansionType>(NTTP->getType())) + ExtraDeductions.push_back(Expansion->getPattern()); + } + // FIXME: Also collect the unexpanded packs in any type and template + // parameter packs that are pack expansions. }; - // First look for unexpanded packs in the pattern. - SmallVector<UnexpandedParameterPack, 2> Unexpanded; - S.collectUnexpandedParameterPacks(Pattern, Unexpanded); - for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { - unsigned Depth, Index; - std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); - if (Depth == Info.getDeducedDepth()) - AddPack(Index); - } + auto Collect = [&](TemplateArgument Pattern) { + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + S.collectUnexpandedParameterPacks(Pattern, Unexpanded); + for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { + unsigned Depth, Index; + std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); + if (Depth == Info.getDeducedDepth()) + AddPack(Index); + } + }; + + // Look for unexpanded packs in the pattern. + Collect(Pattern); assert(!Packs.empty() && "Pack expansion without unexpanded packs?"); unsigned NumNamedPacks = Packs.size(); - // We can also have deduced template parameters that do not actually - // appear in the pattern, but can be deduced by it (the type of a non-type - // template parameter pack, in particular). These won't have prevented us - // from partially expanding the pack. - llvm::SmallBitVector Used(TemplateParams->size()); - MarkUsedTemplateParameters(S.Context, Pattern, /*OnlyDeduced*/true, - Info.getDeducedDepth(), Used); - for (int Index = Used.find_first(); Index != -1; - Index = Used.find_next(Index)) - if (TemplateParams->getParam(Index)->isParameterPack()) - AddPack(Index); + // Also look for unexpanded packs that are indirectly deduced by deducing + // the sizes of the packs in this pattern. + while (!ExtraDeductions.empty()) + Collect(ExtraDeductions.pop_back_val()); return NumNamedPacks; } @@ -1505,6 +1516,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::ExtInt: if (TDF & TDF_SkipNonDependent) return Sema::TDK_Success; @@ -1808,7 +1820,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // If this is a base class, try to perform template argument // deduction from it. if (NextT != RecordT) { - TemplateDeductionInfo BaseInfo(Info.getLocation()); + TemplateDeductionInfo BaseInfo(TemplateDeductionInfo::ForBase, Info); Sema::TemplateDeductionResult BaseResult = DeduceTemplateArguments(S, TemplateParams, SpecParam, QualType(NextT, 0), BaseInfo, Deduced); @@ -2046,6 +2058,101 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // (clang extension) // + // T __attribute__((matrix_type(<integral constant>, + // <integral constant>))) + case Type::ConstantMatrix: { + const ConstantMatrixType *MatrixArg = dyn_cast<ConstantMatrixType>(Arg); + if (!MatrixArg) + return Sema::TDK_NonDeducedMismatch; + + const ConstantMatrixType *MatrixParam = cast<ConstantMatrixType>(Param); + // Check that the dimensions are the same + if (MatrixParam->getNumRows() != MatrixArg->getNumRows() || + MatrixParam->getNumColumns() != MatrixArg->getNumColumns()) { + return Sema::TDK_NonDeducedMismatch; + } + // Perform deduction on element types. + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, MatrixParam->getElementType(), + MatrixArg->getElementType(), Info, Deduced, TDF); + } + + case Type::DependentSizedMatrix: { + const MatrixType *MatrixArg = dyn_cast<MatrixType>(Arg); + if (!MatrixArg) + return Sema::TDK_NonDeducedMismatch; + + // Check the element type of the matrixes. + const DependentSizedMatrixType *MatrixParam = + cast<DependentSizedMatrixType>(Param); + if (Sema::TemplateDeductionResult Result = + DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, MatrixParam->getElementType(), + MatrixArg->getElementType(), Info, Deduced, TDF)) + return Result; + + // Try to deduce a matrix dimension. + auto DeduceMatrixArg = + [&S, &Info, &Deduced, &TemplateParams]( + Expr *ParamExpr, const MatrixType *Arg, + unsigned (ConstantMatrixType::*GetArgDimension)() const, + Expr *(DependentSizedMatrixType::*GetArgDimensionExpr)() const) { + const auto *ArgConstMatrix = dyn_cast<ConstantMatrixType>(Arg); + const auto *ArgDepMatrix = dyn_cast<DependentSizedMatrixType>(Arg); + if (!ParamExpr->isValueDependent()) { + llvm::APSInt ParamConst( + S.Context.getTypeSize(S.Context.getSizeType())); + if (!ParamExpr->isIntegerConstantExpr(ParamConst, S.Context)) + return Sema::TDK_NonDeducedMismatch; + + if (ArgConstMatrix) { + if ((ArgConstMatrix->*GetArgDimension)() == ParamConst) + return Sema::TDK_Success; + return Sema::TDK_NonDeducedMismatch; + } + + Expr *ArgExpr = (ArgDepMatrix->*GetArgDimensionExpr)(); + llvm::APSInt ArgConst( + S.Context.getTypeSize(S.Context.getSizeType())); + if (!ArgExpr->isValueDependent() && + ArgExpr->isIntegerConstantExpr(ArgConst, S.Context) && + ArgConst == ParamConst) + return Sema::TDK_Success; + return Sema::TDK_NonDeducedMismatch; + } + + NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, ParamExpr); + if (!NTTP) + return Sema::TDK_Success; + + if (ArgConstMatrix) { + llvm::APSInt ArgConst( + S.Context.getTypeSize(S.Context.getSizeType())); + ArgConst = (ArgConstMatrix->*GetArgDimension)(); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, ArgConst, S.Context.getSizeType(), + /*ArrayBound=*/true, Info, Deduced); + } + + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, (ArgDepMatrix->*GetArgDimensionExpr)(), + Info, Deduced); + }; + + auto Result = DeduceMatrixArg(MatrixParam->getRowExpr(), MatrixArg, + &ConstantMatrixType::getNumRows, + &DependentSizedMatrixType::getRowExpr); + if (Result) + return Result; + + return DeduceMatrixArg(MatrixParam->getColumnExpr(), MatrixArg, + &ConstantMatrixType::getNumColumns, + &DependentSizedMatrixType::getColumnExpr); + } + + // (clang extension) + // // T __attribute__(((address_space(N)))) case Type::DependentAddressSpace: { const DependentAddressSpaceType *AddressSpaceParam = @@ -2096,6 +2203,33 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_NonDeducedMismatch; } + case Type::DependentExtInt: { + const auto *IntParam = cast<DependentExtIntType>(Param); + + if (const auto *IntArg = dyn_cast<ExtIntType>(Arg)){ + if (IntParam->isUnsigned() != IntArg->isUnsigned()) + return Sema::TDK_NonDeducedMismatch; + + NonTypeTemplateParmDecl *NTTP = + getDeducedParameterFromExpr(Info, IntParam->getNumBitsExpr()); + if (!NTTP) + return Sema::TDK_Success; + + llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); + ArgSize = IntArg->getNumBits(); + + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, + S.Context.IntTy, true, Info, + Deduced); + } + + if (const auto *IntArg = dyn_cast<DependentExtIntType>(Arg)) { + if (IntParam->isUnsigned() != IntArg->isUnsigned()) + return Sema::TDK_NonDeducedMismatch; + return Sema::TDK_Success; + } + return Sema::TDK_NonDeducedMismatch; + } case Type::TypeOfExpr: case Type::TypeOf: @@ -2478,7 +2612,7 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; - TemplateName Template = Arg.getAsTemplate(); + TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = @@ -2504,27 +2638,10 @@ Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, } TemplateArgumentLoc -Sema::getIdentityTemplateArgumentLoc(Decl *TemplateParm, +Sema::getIdentityTemplateArgumentLoc(NamedDecl *TemplateParm, SourceLocation Location) { - if (auto *TTP = dyn_cast<TemplateTypeParmDecl>(TemplateParm)) - return getTrivialTemplateArgumentLoc( - TemplateArgument( - Context.getTemplateTypeParmType(TTP->getDepth(), TTP->getIndex(), - TTP->isParameterPack(), TTP)), - QualType(), Location.isValid() ? Location : TTP->getLocation()); - else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(TemplateParm)) - return getTrivialTemplateArgumentLoc(TemplateArgument(TemplateName(TTP)), - QualType(), - Location.isValid() ? Location : - TTP->getLocation()); - auto *NTTP = cast<NonTypeTemplateParmDecl>(TemplateParm); - CXXScopeSpec SS; - DeclarationNameInfo Info(NTTP->getDeclName(), - Location.isValid() ? Location : NTTP->getLocation()); - Expr *E = BuildDeclarationNameExpr(SS, Info, NTTP).get(); - return getTrivialTemplateArgumentLoc(TemplateArgument(E), NTTP->getType(), - Location.isValid() ? Location : - NTTP->getLocation()); + return getTrivialTemplateArgumentLoc( + Context.getInjectedTemplateArg(TemplateParm), QualType(), Location); } /// Convert the given deduced template argument and add it to the set of @@ -2754,8 +2871,8 @@ CheckDeducedArgumentConstraints(Sema& S, TemplateDeclT *Template, /// Complete template argument deduction for a partial specialization. template <typename T> -static typename std::enable_if<IsPartialSpecialization<T>::value, - Sema::TemplateDeductionResult>::type +static std::enable_if_t<IsPartialSpecialization<T>::value, + Sema::TemplateDeductionResult> FinishTemplateArgumentDeduction( Sema &S, T *Partial, bool IsPartialOrdering, const TemplateArgumentList &TemplateArgs, @@ -2924,8 +3041,13 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - return ::FinishTemplateArgumentDeduction( - *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info); + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = ::FinishTemplateArgumentDeduction(*this, Partial, + /*IsPartialOrdering=*/false, + TemplateArgs, Deduced, Info); + }); + return Result; } /// Perform template argument deduction to determine whether @@ -2965,8 +3087,13 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - return ::FinishTemplateArgumentDeduction( - *this, Partial, /*IsPartialOrdering=*/false, TemplateArgs, Deduced, Info); + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = ::FinishTemplateArgumentDeduction(*this, Partial, + /*IsPartialOrdering=*/false, + TemplateArgs, Deduced, Info); + }); + return Result; } /// Determine whether the given type T is a simple-template-id type. @@ -3446,13 +3573,16 @@ Sema::TemplateDeductionResult Sema::FinishTemplateArgumentDeduction( // ([temp.constr.decl]), those constraints are checked for satisfaction // ([temp.constr.constr]). If the constraints are not satisfied, type // deduction fails. - if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), - Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) - return TDK_MiscellaneousDeductionFailure; + if (!PartialOverloading || + (Builder.size() == FunctionTemplate->getTemplateParameters()->size())) { + if (CheckInstantiatedFunctionTemplateConstraints(Info.getLocation(), + Specialization, Builder, Info.AssociatedConstraintsSatisfaction)) + return TDK_MiscellaneousDeductionFailure; - if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - return TDK_ConstraintsNotSatisfied; + if (!Info.AssociatedConstraintsSatisfaction.IsSatisfied) { + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); + return TDK_ConstraintsNotSatisfied; + } } if (OriginalCallArgs) { @@ -3912,13 +4042,12 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( SmallVector<QualType, 8> ParamTypes; unsigned NumExplicitlySpecified = 0; if (ExplicitTemplateArgs) { - TemplateDeductionResult Result = - SubstituteExplicitTemplateArguments(FunctionTemplate, - *ExplicitTemplateArgs, - Deduced, - ParamTypes, - nullptr, - Info); + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = SubstituteExplicitTemplateArguments( + FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, nullptr, + Info); + }); if (Result) return Result; @@ -4020,12 +4149,16 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // that is needed when the accessibility of template arguments is checked. DeclContext *CallingCtx = CurContext; - return FinishTemplateArgumentDeduction( - FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, - &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() { - ContextRAII SavedContext(*this, CallingCtx); - return CheckNonDependent(ParamTypesForArgChecking); - }); + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = FinishTemplateArgumentDeduction( + FunctionTemplate, Deduced, NumExplicitlySpecified, Specialization, Info, + &OriginalCallArgs, PartialOverloading, [&, CallingCtx]() { + ContextRAII SavedContext(*this, CallingCtx); + return CheckNonDependent(ParamTypesForArgChecking); + }); + }); + return Result; } QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, @@ -4111,11 +4244,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( unsigned NumExplicitlySpecified = 0; SmallVector<QualType, 4> ParamTypes; if (ExplicitTemplateArgs) { - if (TemplateDeductionResult Result - = SubstituteExplicitTemplateArguments(FunctionTemplate, - *ExplicitTemplateArgs, - Deduced, ParamTypes, - &FunctionType, Info)) + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = SubstituteExplicitTemplateArguments( + FunctionTemplate, *ExplicitTemplateArgs, Deduced, ParamTypes, + &FunctionType, Info); + }); + if (Result) return Result; NumExplicitlySpecified = Deduced.size(); @@ -4157,10 +4292,13 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( return Result; } - if (TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, - NumExplicitlySpecified, - Specialization, Info)) + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = FinishTemplateArgumentDeduction(FunctionTemplate, Deduced, + NumExplicitlySpecified, + Specialization, Info); + }); + if (Result) return Result; // If the function has a deduced return type, deduce it now, so we can check @@ -4317,9 +4455,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, LocalInstantiationScope InstScope(*this); // Finish template argument deduction. FunctionDecl *ConversionSpecialized = nullptr; - TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, - ConversionSpecialized, Info); + TemplateDeductionResult Result; + runWithSufficientStackSpace(Info.getLocation(), [&] { + Result = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + ConversionSpecialized, Info); + }); Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized); return Result; } @@ -4404,9 +4544,10 @@ namespace { QualType Result = SemaRef.Context.getAutoType( Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull(), - ReplacementIsPack); + ReplacementIsPack, TL.getTypePtr()->getTypeConstraintConcept(), + TL.getTypePtr()->getTypeConstraintArguments()); auto NewTL = TLB.push<AutoTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); + NewTL.copy(TL); return Result; } @@ -4441,9 +4582,10 @@ namespace { Sema::DeduceAutoResult Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth) { + Optional<unsigned> DependentDeductionDepth, + bool IgnoreConstraints) { return DeduceAutoType(Type->getTypeLoc(), Init, Result, - DependentDeductionDepth); + DependentDeductionDepth, IgnoreConstraints); } /// Attempt to produce an informative diagostic explaining why auto deduction @@ -4471,6 +4613,49 @@ static bool diagnoseAutoDeductionFailure(Sema &S, } } +static Sema::DeduceAutoResult +CheckDeducedPlaceholderConstraints(Sema &S, const AutoType &Type, + AutoTypeLoc TypeLoc, QualType Deduced) { + ConstraintSatisfaction Satisfaction; + ConceptDecl *Concept = Type.getTypeConstraintConcept(); + TemplateArgumentListInfo TemplateArgs(TypeLoc.getLAngleLoc(), + TypeLoc.getRAngleLoc()); + TemplateArgs.addArgument( + TemplateArgumentLoc(TemplateArgument(Deduced), + S.Context.getTrivialTypeSourceInfo( + Deduced, TypeLoc.getNameLoc()))); + for (unsigned I = 0, C = TypeLoc.getNumArgs(); I != C; ++I) + TemplateArgs.addArgument(TypeLoc.getArgLoc(I)); + + llvm::SmallVector<TemplateArgument, 4> Converted; + if (S.CheckTemplateArgumentList(Concept, SourceLocation(), TemplateArgs, + /*PartialTemplateArgs=*/false, Converted)) + return Sema::DAR_FailedAlreadyDiagnosed; + if (S.CheckConstraintSatisfaction(Concept, {Concept->getConstraintExpr()}, + Converted, TypeLoc.getLocalSourceRange(), + Satisfaction)) + return Sema::DAR_FailedAlreadyDiagnosed; + if (!Satisfaction.IsSatisfied) { + std::string Buf; + llvm::raw_string_ostream OS(Buf); + OS << "'" << Concept->getName(); + if (TypeLoc.hasExplicitTemplateArgs()) { + OS << "<"; + for (const auto &Arg : Type.getTypeConstraintArguments()) + Arg.print(S.getPrintingPolicy(), OS); + OS << ">"; + } + OS << "'"; + OS.flush(); + S.Diag(TypeLoc.getConceptNameLoc(), + diag::err_placeholder_constraints_not_satisfied) + << Deduced << Buf << TypeLoc.getLocalSourceRange(); + S.DiagnoseUnsatisfiedConstraint(Satisfaction); + return Sema::DAR_FailedAlreadyDiagnosed; + } + return Sema::DAR_Succeeded; +} + /// Deduce the type for an auto type-specifier (C++11 [dcl.spec.auto]p6) /// /// Note that this is done even if the initializer is dependent. (This is @@ -4485,9 +4670,14 @@ static bool diagnoseAutoDeductionFailure(Sema &S, /// dependent cases. This is necessary for template partial ordering with /// 'auto' template parameters. The value specified is the template /// parameter depth at which we should perform 'auto' deduction. +/// \param IgnoreConstraints Set if we should not fail if the deduced type does +/// not satisfy the type-constraint in the auto type. Sema::DeduceAutoResult Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, - Optional<unsigned> DependentDeductionDepth) { + Optional<unsigned> DependentDeductionDepth, + bool IgnoreConstraints) { + if (Init->containsErrors()) + return DAR_FailedAlreadyDiagnosed; if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) @@ -4528,6 +4718,14 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; // FIXME: Support a non-canonical deduced type for 'auto'. Deduced = Context.getCanonicalType(Deduced); + if (AT->isConstrained() && !IgnoreConstraints) { + auto ConstraintsResult = + CheckDeducedPlaceholderConstraints(*this, *AT, + Type.getContainedAutoTypeLoc(), + Deduced); + if (ConstraintsResult != DAR_Succeeded) + return ConstraintsResult; + } Result = SubstituteDeducedTypeTransform(*this, Deduced).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; @@ -4635,6 +4833,17 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, return DAR_FailedAlreadyDiagnosed; } + if (const auto *AT = Type.getType()->getAs<AutoType>()) { + if (AT->isConstrained() && !IgnoreConstraints) { + auto ConstraintsResult = + CheckDeducedPlaceholderConstraints(*this, *AT, + Type.getContainedAutoTypeLoc(), + DeducedType); + if (ConstraintsResult != DAR_Succeeded) + return ConstraintsResult; + } + } + Result = SubstituteDeducedTypeTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) return DAR_FailedAlreadyDiagnosed; @@ -4787,7 +4996,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S, FunctionTemplateDecl *FT1, FunctionTemplateDecl *FT2, TemplatePartialOrderingContext TPOC, - unsigned NumCallArguments1) { + unsigned NumCallArguments1, + bool Reversed) { + assert(!Reversed || TPOC == TPOC_Call); + FunctionDecl *FD1 = FT1->getTemplatedDecl(); FunctionDecl *FD2 = FT2->getTemplatedDecl(); const FunctionProtoType *Proto1 = FD1->getType()->getAs<FunctionProtoType>(); @@ -4836,6 +5048,12 @@ static bool isAtLeastAsSpecializedAs(Sema &S, } else if (!Method1 && Method2 && !Method2->isStatic()) { // Compare 'this' from Method2 against first parameter from Method1. AddImplicitObjectParameterType(S.Context, Method2, Args2); + } else if (Method1 && Method2 && Reversed) { + // Compare 'this' from Method1 against second parameter from Method2 + // and 'this' from Method2 against second parameter from Method1. + AddImplicitObjectParameterType(S.Context, Method1, Args1); + AddImplicitObjectParameterType(S.Context, Method2, Args2); + ++NumComparedArguments; } Args1.insert(Args1.end(), Proto1->param_type_begin(), @@ -4850,6 +5068,8 @@ static bool isAtLeastAsSpecializedAs(Sema &S, Args1.resize(NumComparedArguments); if (Args2.size() > NumComparedArguments) Args2.resize(NumComparedArguments); + if (Reversed) + std::reverse(Args2.begin(), Args2.end()); if (DeduceTemplateArguments(S, TemplateParams, Args2.data(), Args2.size(), Args1.data(), Args1.size(), Info, Deduced, TDF_None, /*PartialOrdering=*/true)) @@ -4968,6 +5188,10 @@ static bool isVariadicFunctionTemplate(FunctionTemplateDecl *FunTmpl) { /// \param NumCallArguments2 The number of arguments in the call to FT2, used /// only when \c TPOC is \c TPOC_Call. /// +/// \param Reversed If \c true, exactly one of FT1 and FT2 is an overload +/// candidate with a reversed parameter order. In this case, the corresponding +/// P/A pairs between FT1 and FT2 are reversed. +/// /// \returns the more specialized function template. If neither /// template is more specialized, returns NULL. FunctionTemplateDecl * @@ -4976,7 +5200,8 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, SourceLocation Loc, TemplatePartialOrderingContext TPOC, unsigned NumCallArguments1, - unsigned NumCallArguments2) { + unsigned NumCallArguments2, + bool Reversed) { auto JudgeByConstraints = [&] () -> FunctionTemplateDecl * { llvm::SmallVector<const Expr *, 3> AC1, AC2; @@ -4993,9 +5218,9 @@ Sema::getMoreSpecializedTemplate(FunctionTemplateDecl *FT1, }; bool Better1 = isAtLeastAsSpecializedAs(*this, Loc, FT1, FT2, TPOC, - NumCallArguments1); + NumCallArguments1, Reversed); bool Better2 = isAtLeastAsSpecializedAs(*this, Loc, FT2, FT1, TPOC, - NumCallArguments2); + NumCallArguments2, Reversed); if (Better1 != Better2) // We have a clear winner return Better1 ? FT1 : FT2; @@ -5174,14 +5399,15 @@ static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs, Info); auto *TST1 = T1->castAs<TemplateSpecializationType>(); - if (FinishTemplateArgumentDeduction( - S, P2, /*IsPartialOrdering=*/true, - TemplateArgumentList(TemplateArgumentList::OnStack, - TST1->template_arguments()), - Deduced, Info)) - return false; - - return true; + bool AtLeastAsSpecialized; + S.runWithSufficientStackSpace(Info.getLocation(), [&] { + AtLeastAsSpecialized = !FinishTemplateArgumentDeduction( + S, P2, /*IsPartialOrdering=*/true, + TemplateArgumentList(TemplateArgumentList::OnStack, + TST1->template_arguments()), + Deduced, Info); + }); + return AtLeastAsSpecialized; } /// Returns the more specialized class template partial specialization @@ -5616,6 +5842,24 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, break; } + case Type::ConstantMatrix: { + const ConstantMatrixType *MatType = cast<ConstantMatrixType>(T); + MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced, + Depth, Used); + break; + } + + case Type::DependentSizedMatrix: { + const DependentSizedMatrixType *MatType = cast<DependentSizedMatrixType>(T); + MarkUsedTemplateParameters(Ctx, MatType->getElementType(), OnlyDeduced, + Depth, Used); + MarkUsedTemplateParameters(Ctx, MatType->getRowExpr(), OnlyDeduced, Depth, + Used); + MarkUsedTemplateParameters(Ctx, MatType->getColumnExpr(), OnlyDeduced, + Depth, Used); + break; + } + case Type::FunctionProto: { const FunctionProtoType *Proto = cast<FunctionProtoType>(T); MarkUsedTemplateParameters(Ctx, Proto->getReturnType(), OnlyDeduced, Depth, @@ -5771,6 +6015,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, cast<DeducedType>(T)->getDeducedType(), OnlyDeduced, Depth, Used); break; + case Type::DependentExtInt: + MarkUsedTemplateParameters(Ctx, + cast<DependentExtIntType>(T)->getNumBitsExpr(), + OnlyDeduced, Depth, Used); + break; // None of these types have any template parameters in them. case Type::Builtin: @@ -5783,6 +6032,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::ObjCObjectPointer: case Type::UnresolvedUsing: case Type::Pipe: + case Type::ExtInt: #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) #define DEPENDENT_TYPE(Class, Base) diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index af41e231134d..11e03c517d01 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -9,7 +9,6 @@ // //===----------------------------------------------------------------------===/ -#include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -18,11 +17,15 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/AST/PrettyDeclStackTrace.h" +#include "clang/AST/TypeVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/Stack.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaConcept.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" @@ -199,8 +202,10 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case DeducedTemplateArgumentSubstitution: case PriorTemplateArgumentSubstitution: case ConstraintsCheck: + case NestedRequirementConstraintsCheck: return true; + case RequirementInstantiation: case DefaultTemplateArgumentChecking: case DeclaringSpecialMember: case DeclaringImplicitEqualityComparison: @@ -210,6 +215,8 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case ParameterMappingSubstitution: case ConstraintNormalization: case RewritingOperatorAsSpaceship: + case InitializingStructuredBinding: + case MarkingClassDllexported: return false; // This function should never be called when Kind's value is Memoization. @@ -247,7 +254,7 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Inst.InstantiationRange = InstantiationRange; SemaRef.pushCodeSynthesisContext(Inst); - AlreadyInstantiating = + AlreadyInstantiating = !Inst.Entity ? false : !SemaRef.InstantiatingSpecializations .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) .second; @@ -366,6 +373,26 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::Requirement *Req, sema::TemplateDeductionInfo &DeductionInfo, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::RequirementInstantiation, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/None, &DeductionInfo) {} + + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, + concepts::NestedRequirement *Req, ConstraintsCheck, + SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, CodeSynthesisContext::NestedRequirementConstraintsCheck, + PointOfInstantiation, InstantiationRange, /*Entity=*/nullptr, + /*Template=*/nullptr, /*TemplateArgs=*/None) {} + + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, ConstraintsCheck, NamedDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) : InstantiatingTemplate( @@ -446,8 +473,9 @@ void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { if (!AlreadyInstantiating) { auto &Active = SemaRef.CodeSynthesisContexts.back(); - SemaRef.InstantiatingSpecializations.erase( - std::make_pair(Active.Entity, Active.Kind)); + if (Active.Entity) + SemaRef.InstantiatingSpecializations.erase( + std::make_pair(Active.Entity, Active.Kind)); } atTemplateEnd(SemaRef.TemplateInstCallbacks, SemaRef, @@ -684,6 +712,18 @@ void Sema::PrintInstantiationStack() { << Active->InstantiationRange; break; + case CodeSynthesisContext::RequirementInstantiation: + Diags.Report(Active->PointOfInstantiation, + diag::note_template_requirement_instantiation_here) + << Active->InstantiationRange; + break; + + case CodeSynthesisContext::NestedRequirementConstraintsCheck: + Diags.Report(Active->PointOfInstantiation, + diag::note_nested_requirement_here) + << Active->InstantiationRange; + break; + case CodeSynthesisContext::DeclaringSpecialMember: Diags.Report(Active->PointOfInstantiation, diag::note_in_declaration_of_implicit_special_member) @@ -722,26 +762,47 @@ void Sema::PrintInstantiationStack() { diag::note_rewriting_operator_as_spaceship); break; + case CodeSynthesisContext::InitializingStructuredBinding: + Diags.Report(Active->PointOfInstantiation, + diag::note_in_binding_decl_init) + << cast<BindingDecl>(Active->Entity); + break; + + case CodeSynthesisContext::MarkingClassDllexported: + Diags.Report(Active->PointOfInstantiation, + diag::note_due_to_dllexported_class) + << cast<CXXRecordDecl>(Active->Entity) << !getLangOpts().CPlusPlus11; + break; + case CodeSynthesisContext::Memoization: break; - + case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; + if (!Active->Entity) { + Diags.Report(Active->PointOfInstantiation, + diag::note_nested_requirement_here) + << Active->InstantiationRange; + break; + } if (isa<ConceptDecl>(Active->Entity)) DiagID = diag::note_concept_specialization_here; else if (isa<TemplateDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_template_id_here; else if (isa<VarTemplatePartialSpecializationDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_var_spec_id_here; - else { - assert(isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)); + else if (isa<ClassTemplatePartialSpecializationDecl>(Active->Entity)) DiagID = diag::note_checking_constraints_for_class_spec_id_here; + else { + assert(isa<FunctionDecl>(Active->Entity)); + DiagID = diag::note_checking_constraints_for_function_here; } SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); cast<NamedDecl>(Active->Entity)->printName(OS); - printTemplateArgumentList(OS, Active->template_arguments(), - getPrintingPolicy()); + if (!isa<FunctionDecl>(Active->Entity)) + printTemplateArgumentList(OS, Active->template_arguments(), + getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, DiagID) << OS.str() << Active->InstantiationRange; break; @@ -788,6 +849,7 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ConstraintsCheck: case CodeSynthesisContext::ParameterMappingSubstitution: case CodeSynthesisContext::ConstraintNormalization: + case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return None; @@ -802,9 +864,10 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: case CodeSynthesisContext::ConstraintSubstitution: - // We're either substituting explicitly-specified template arguments - // or deduced template arguments or a constraint expression, so SFINAE - // applies. + case CodeSynthesisContext::RequirementInstantiation: + // We're either substituting explicitly-specified template arguments, + // deduced template arguments, a constraint expression or a requirement + // in a requires expression, so SFINAE applies. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; @@ -812,6 +875,8 @@ Optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const { case CodeSynthesisContext::DeclaringImplicitEqualityComparison: case CodeSynthesisContext::DefiningSynthesizedFunction: case CodeSynthesisContext::RewritingOperatorAsSpaceship: + case CodeSynthesisContext::InitializingStructuredBinding: + case CodeSynthesisContext::MarkingClassDllexported: // This happens in a context unrelated to template instantiation, so // there is no SFINAE. return None; @@ -874,6 +939,10 @@ namespace { this->Entity = Entity; } + unsigned TransformTemplateDepth(unsigned Depth) { + return TemplateArgs.getNewDepth(Depth); + } + bool TryExpandParameterPacks(SourceLocation EllipsisLoc, SourceRange PatternRange, ArrayRef<UnexpandedParameterPack> Unexpanded, @@ -1010,6 +1079,8 @@ namespace { NonTypeTemplateParmDecl *D); ExprResult TransformSubstNonTypeTemplateParmPackExpr( SubstNonTypeTemplateParmPackExpr *E); + ExprResult TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E); /// Rebuild a DeclRefExpr for a VarDecl reference. ExprResult RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc); @@ -1056,6 +1127,41 @@ namespace { return TreeTransform<TemplateInstantiator>::TransformLambdaExpr(E); } + ExprResult TransformRequiresExpr(RequiresExpr *E) { + LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); + return TreeTransform<TemplateInstantiator>::TransformRequiresExpr(E); + } + + bool TransformRequiresExprRequirements( + ArrayRef<concepts::Requirement *> Reqs, + SmallVectorImpl<concepts::Requirement *> &Transformed) { + bool SatisfactionDetermined = false; + for (concepts::Requirement *Req : Reqs) { + concepts::Requirement *TransReq = nullptr; + if (!SatisfactionDetermined) { + if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) + TransReq = TransformTypeRequirement(TypeReq); + else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) + TransReq = TransformExprRequirement(ExprReq); + else + TransReq = TransformNestedRequirement( + cast<concepts::NestedRequirement>(Req)); + if (!TransReq) + return true; + if (!TransReq->isDependent() && !TransReq->isSatisfied()) + // [expr.prim.req]p6 + // [...] The substitution and semantic constraint checking + // proceeds in lexical order and stops when a condition that + // determines the result of the requires-expression is + // encountered. [..] + SatisfactionDetermined = true; + } else + TransReq = Req; + Transformed.push_back(TransReq); + } + return false; + } + TemplateParameterList *TransformTemplateParameterList( TemplateParameterList *OrigTPL) { if (!OrigTPL || !OrigTPL->size()) return OrigTPL; @@ -1065,6 +1171,14 @@ namespace { /* DeclContext *Owner */ Owner, TemplateArgs); return DeclInstantiator.SubstTemplateParams(OrigTPL); } + + concepts::TypeRequirement * + TransformTypeRequirement(concepts::TypeRequirement *Req); + concepts::ExprRequirement * + TransformExprRequirement(concepts::ExprRequirement *Req); + concepts::NestedRequirement * + TransformNestedRequirement(concepts::NestedRequirement *Req); + private: ExprResult transformNonTypeTemplateParmRef(NonTypeTemplateParmDecl *parm, SourceLocation loc, @@ -1248,6 +1362,19 @@ TemplateName TemplateInstantiator::TransformTemplateName( TemplateArgument Arg = TemplateArgs(TTP->getDepth(), TTP->getPosition()); + if (TemplateArgs.isRewrite()) { + // We're rewriting the template parameter as a reference to another + // template parameter. + if (Arg.getKind() == TemplateArgument::Pack) { + assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() && + "unexpected pack arguments in template rewrite"); + Arg = Arg.pack_begin()->getPackExpansionPattern(); + } + assert(Arg.getKind() == TemplateArgument::Template && + "unexpected nontype template argument kind in template rewrite"); + return Arg.getAsTemplate(); + } + if (TTP->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1287,11 +1414,47 @@ TemplateName TemplateInstantiator::TransformTemplateName( AllowInjectedClassName); } +static ExprResult TransformUniqueStableName(TemplateInstantiator &TI, + PredefinedExpr *E) { + if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType) { + TypeSourceInfo *Info = + TI.getDerived().TransformType(E->getTypeSourceInfo()); + + if (!Info) + return ExprError(); + + if (!TI.getDerived().AlwaysRebuild() && Info == E->getTypeSourceInfo()) + return E; + + return TI.getSema().BuildUniqueStableName(E->getLocation(), Info); + } + + if (E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) { + EnterExpressionEvaluationContext Unevaluated( + TI.getSema(), Sema::ExpressionEvaluationContext::Unevaluated); + ExprResult SubExpr = TI.getDerived().TransformExpr(E->getExpr()); + + if (SubExpr.isInvalid()) + return ExprError(); + + if (!TI.getDerived().AlwaysRebuild() && SubExpr.get() == E->getExpr()) + return E; + + return TI.getSema().BuildUniqueStableName(E->getLocation(), SubExpr.get()); + } + + llvm_unreachable("Only valid for UniqueStableNameType/Expr"); +} + ExprResult TemplateInstantiator::TransformPredefinedExpr(PredefinedExpr *E) { if (!E->isTypeDependent()) return E; + if (E->getIdentKind() == PredefinedExpr::UniqueStableNameType || + E->getIdentKind() == PredefinedExpr::UniqueStableNameExpr) + return TransformUniqueStableName(*this, E); + return getSema().BuildPredefinedExpr(E->getLocation(), E->getIdentKind()); } @@ -1308,19 +1471,18 @@ TemplateInstantiator::TransformTemplateParmRefExpr(DeclRefExpr *E, TemplateArgument Arg = TemplateArgs(NTTP->getDepth(), NTTP->getPosition()); - if (TemplateArgs.getNumLevels() != TemplateArgs.getNumSubstitutedLevels()) { - // We're performing a partial substitution, so the substituted argument - // could be dependent. As a result we can't create a SubstNonType*Expr - // node now, since that represents a fully-substituted argument. - // FIXME: We should have some AST representation for this. + if (TemplateArgs.isRewrite()) { + // We're rewriting the template parameter as a reference to another + // template parameter. if (Arg.getKind() == TemplateArgument::Pack) { - // FIXME: This won't work for alias templates. assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() && - "unexpected pack arguments in partial substitution"); + "unexpected pack arguments in template rewrite"); Arg = Arg.pack_begin()->getPackExpansionPattern(); } assert(Arg.getKind() == TemplateArgument::Expression && - "unexpected nontype template argument kind in partial substitution"); + "unexpected nontype template argument kind in template rewrite"); + // FIXME: This can lead to the same subexpression appearing multiple times + // in a complete expression. return Arg.getAsExpr(); } @@ -1445,6 +1607,44 @@ TemplateInstantiator::TransformSubstNonTypeTemplateParmPackExpr( Arg); } +ExprResult +TemplateInstantiator::TransformSubstNonTypeTemplateParmExpr( + SubstNonTypeTemplateParmExpr *E) { + ExprResult SubstReplacement = TransformExpr(E->getReplacement()); + if (SubstReplacement.isInvalid()) + return true; + QualType SubstType = TransformType(E->getType()); + if (SubstType.isNull()) + return true; + // The type may have been previously dependent and not now, which means we + // might have to implicit cast the argument to the new type, for example: + // template<auto T, decltype(T) U> + // concept C = sizeof(U) == 4; + // void foo() requires C<2, 'a'> { } + // When normalizing foo(), we first form the normalized constraints of C: + // AtomicExpr(sizeof(U) == 4, + // U=SubstNonTypeTemplateParmExpr(Param=U, + // Expr=DeclRef(U), + // Type=decltype(T))) + // Then we substitute T = 2, U = 'a' into the parameter mapping, and need to + // produce: + // AtomicExpr(sizeof(U) == 4, + // U=SubstNonTypeTemplateParmExpr(Param=U, + // Expr=ImpCast( + // decltype(2), + // SubstNTTPE(Param=U, Expr='a', + // Type=char)), + // Type=decltype(2))) + // The call to CheckTemplateArgument here produces the ImpCast. + TemplateArgument Converted; + if (SemaRef.CheckTemplateArgument(E->getParameter(), SubstType, + SubstReplacement.get(), + Converted).isInvalid()) + return true; + return transformNonTypeTemplateParmRef(E->getParameter(), + E->getExprLoc(), Converted); +} + ExprResult TemplateInstantiator::RebuildVarDeclRefExpr(VarDecl *PD, SourceLocation Loc) { DeclarationNameInfo NameInfo(PD->getDeclName(), Loc); @@ -1594,6 +1794,24 @@ TemplateInstantiator::TransformTemplateTypeParmType(TypeLocBuilder &TLB, TemplateArgument Arg = TemplateArgs(T->getDepth(), T->getIndex()); + if (TemplateArgs.isRewrite()) { + // We're rewriting the template parameter as a reference to another + // template parameter. + if (Arg.getKind() == TemplateArgument::Pack) { + assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion() && + "unexpected pack arguments in template rewrite"); + Arg = Arg.pack_begin()->getPackExpansionPattern(); + } + assert(Arg.getKind() == TemplateArgument::Type && + "unexpected nontype template argument kind in template rewrite"); + QualType NewT = Arg.getAsType(); + assert(isa<TemplateTypeParmType>(NewT) && + "type parm not rewritten to type parm"); + auto NewTL = TLB.push<TemplateTypeParmTypeLoc>(NewT); + NewTL.setNameLoc(TL.getNameLoc()); + return NewT; + } + if (T->isParameterPack()) { assert(Arg.getKind() == TemplateArgument::Pack && "Missing argument pack"); @@ -1669,6 +1887,163 @@ TemplateInstantiator::TransformSubstTemplateTypeParmPackType( return Result; } +template<typename EntityPrinter> +static concepts::Requirement::SubstitutionDiagnostic * +createSubstDiag(Sema &S, TemplateDeductionInfo &Info, EntityPrinter Printer) { + SmallString<128> Message; + SourceLocation ErrorLoc; + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt PDA(SourceLocation(), + PartialDiagnostic::NullDiagnostic{}); + Info.takeSFINAEDiagnostic(PDA); + PDA.second.EmitToString(S.getDiagnostics(), Message); + ErrorLoc = PDA.first; + } else { + ErrorLoc = Info.getLocation(); + } + char *MessageBuf = new (S.Context) char[Message.size()]; + std::copy(Message.begin(), Message.end(), MessageBuf); + SmallString<128> Entity; + llvm::raw_svector_ostream OS(Entity); + Printer(OS); + char *EntityBuf = new (S.Context) char[Entity.size()]; + std::copy(Entity.begin(), Entity.end(), EntityBuf); + return new (S.Context) concepts::Requirement::SubstitutionDiagnostic{ + StringRef(EntityBuf, Entity.size()), ErrorLoc, + StringRef(MessageBuf, Message.size())}; +} + +concepts::TypeRequirement * +TemplateInstantiator::TransformTypeRequirement(concepts::TypeRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + if (Req->isSubstitutionFailure()) { + if (AlwaysRebuild()) + return RebuildTypeRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + + Sema::SFINAETrap Trap(SemaRef); + TemplateDeductionInfo Info(Req->getType()->getTypeLoc().getBeginLoc()); + Sema::InstantiatingTemplate TypeInst(SemaRef, + Req->getType()->getTypeLoc().getBeginLoc(), Req, Info, + Req->getType()->getTypeLoc().getSourceRange()); + if (TypeInst.isInvalid()) + return nullptr; + TypeSourceInfo *TransType = TransformType(Req->getType()); + if (!TransType || Trap.hasErrorOccurred()) + return RebuildTypeRequirement(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getType()->getType().print(OS, SemaRef.getPrintingPolicy()); + })); + return RebuildTypeRequirement(TransType); +} + +concepts::ExprRequirement * +TemplateInstantiator::TransformExprRequirement(concepts::ExprRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + + Sema::SFINAETrap Trap(SemaRef); + TemplateDeductionInfo Info(Req->getExpr()->getBeginLoc()); + + llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> + TransExpr; + if (Req->isExprSubstitutionFailure()) + TransExpr = Req->getExprSubstitutionDiagnostic(); + else { + Sema::InstantiatingTemplate ExprInst(SemaRef, Req->getExpr()->getBeginLoc(), + Req, Info, + Req->getExpr()->getSourceRange()); + if (ExprInst.isInvalid()) + return nullptr; + ExprResult TransExprRes = TransformExpr(Req->getExpr()); + if (TransExprRes.isInvalid() || Trap.hasErrorOccurred()) + TransExpr = createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + }); + else + TransExpr = TransExprRes.get(); + } + + llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; + const auto &RetReq = Req->getReturnTypeRequirement(); + if (RetReq.isEmpty()) + TransRetReq.emplace(); + else if (RetReq.isSubstitutionFailure()) + TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); + else if (RetReq.isTypeConstraint()) { + TemplateParameterList *OrigTPL = + RetReq.getTypeConstraintTemplateParameterList(); + Sema::InstantiatingTemplate TPLInst(SemaRef, OrigTPL->getTemplateLoc(), + Req, Info, OrigTPL->getSourceRange()); + if (TPLInst.isInvalid()) + return nullptr; + TemplateParameterList *TPL = + TransformTemplateParameterList(OrigTPL); + if (!TPL) + TransRetReq.emplace(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + RetReq.getTypeConstraint()->getImmediatelyDeclaredConstraint() + ->printPretty(OS, nullptr, SemaRef.getPrintingPolicy()); + })); + else { + TPLInst.Clear(); + TransRetReq.emplace(TPL); + } + } + assert(TransRetReq.hasValue() && + "All code paths leading here must set TransRetReq"); + if (Expr *E = TransExpr.dyn_cast<Expr *>()) + return RebuildExprRequirement(E, Req->isSimple(), Req->getNoexceptLoc(), + std::move(*TransRetReq)); + return RebuildExprRequirement( + TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(), + Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +concepts::NestedRequirement * +TemplateInstantiator::TransformNestedRequirement( + concepts::NestedRequirement *Req) { + if (!Req->isDependent() && !AlwaysRebuild()) + return Req; + if (Req->isSubstitutionFailure()) { + if (AlwaysRebuild()) + return RebuildNestedRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + Sema::InstantiatingTemplate ReqInst(SemaRef, + Req->getConstraintExpr()->getBeginLoc(), Req, + Sema::InstantiatingTemplate::ConstraintsCheck{}, + Req->getConstraintExpr()->getSourceRange()); + + ExprResult TransConstraint; + TemplateDeductionInfo Info(Req->getConstraintExpr()->getBeginLoc()); + { + EnterExpressionEvaluationContext ContextRAII( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + Sema::SFINAETrap Trap(SemaRef); + Sema::InstantiatingTemplate ConstrInst(SemaRef, + Req->getConstraintExpr()->getBeginLoc(), Req, Info, + Req->getConstraintExpr()->getSourceRange()); + if (ConstrInst.isInvalid()) + return nullptr; + TransConstraint = TransformExpr(Req->getConstraintExpr()); + if (TransConstraint.isInvalid() || Trap.hasErrorOccurred()) + return RebuildNestedRequirement(createSubstDiag(SemaRef, Info, + [&] (llvm::raw_ostream& OS) { + Req->getConstraintExpr()->printPretty(OS, nullptr, + SemaRef.getPrintingPolicy()); + })); + } + return RebuildNestedRequirement(TransConstraint.get()); +} + + /// Perform substitution on the type T with a given set of template /// arguments. /// @@ -1858,6 +2233,94 @@ void Sema::SubstExceptionSpec(FunctionDecl *New, const FunctionProtoType *Proto, UpdateExceptionSpec(New, ESI); } +namespace { + + struct GetContainedInventedTypeParmVisitor : + public TypeVisitor<GetContainedInventedTypeParmVisitor, + TemplateTypeParmDecl *> { + using TypeVisitor<GetContainedInventedTypeParmVisitor, + TemplateTypeParmDecl *>::Visit; + + TemplateTypeParmDecl *Visit(QualType T) { + if (T.isNull()) + return nullptr; + return Visit(T.getTypePtr()); + } + // The deduced type itself. + TemplateTypeParmDecl *VisitTemplateTypeParmType( + const TemplateTypeParmType *T) { + if (!T->getDecl() || !T->getDecl()->isImplicit()) + return nullptr; + return T->getDecl(); + } + + // Only these types can contain 'auto' types, and subsequently be replaced + // by references to invented parameters. + + TemplateTypeParmDecl *VisitElaboratedType(const ElaboratedType *T) { + return Visit(T->getNamedType()); + } + + TemplateTypeParmDecl *VisitPointerType(const PointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitBlockPointerType(const BlockPointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitReferenceType(const ReferenceType *T) { + return Visit(T->getPointeeTypeAsWritten()); + } + + TemplateTypeParmDecl *VisitMemberPointerType(const MemberPointerType *T) { + return Visit(T->getPointeeType()); + } + + TemplateTypeParmDecl *VisitArrayType(const ArrayType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitDependentSizedExtVectorType( + const DependentSizedExtVectorType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitVectorType(const VectorType *T) { + return Visit(T->getElementType()); + } + + TemplateTypeParmDecl *VisitFunctionProtoType(const FunctionProtoType *T) { + return VisitFunctionType(T); + } + + TemplateTypeParmDecl *VisitFunctionType(const FunctionType *T) { + return Visit(T->getReturnType()); + } + + TemplateTypeParmDecl *VisitParenType(const ParenType *T) { + return Visit(T->getInnerType()); + } + + TemplateTypeParmDecl *VisitAttributedType(const AttributedType *T) { + return Visit(T->getModifiedType()); + } + + TemplateTypeParmDecl *VisitMacroQualifiedType(const MacroQualifiedType *T) { + return Visit(T->getUnderlyingType()); + } + + TemplateTypeParmDecl *VisitAdjustedType(const AdjustedType *T) { + return Visit(T->getOriginalType()); + } + + TemplateTypeParmDecl *VisitPackExpansionType(const PackExpansionType *T) { + return Visit(T->getPattern()); + } + }; + +} // namespace + ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, const MultiLevelTemplateArgumentList &TemplateArgs, int indexAdjustment, @@ -1905,6 +2368,46 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, return nullptr; } + // In abbreviated templates, TemplateTypeParmDecls with possible + // TypeConstraints are created when the parameter list is originally parsed. + // The TypeConstraints can therefore reference other functions parameters in + // the abbreviated function template, which is why we must instantiate them + // here, when the instantiated versions of those referenced parameters are in + // scope. + if (TemplateTypeParmDecl *TTP = + GetContainedInventedTypeParmVisitor().Visit(OldDI->getType())) { + if (const TypeConstraint *TC = TTP->getTypeConstraint()) { + auto *Inst = cast_or_null<TemplateTypeParmDecl>( + FindInstantiatedDecl(TTP->getLocation(), TTP, TemplateArgs)); + // We will first get here when instantiating the abbreviated function + // template's described function, but we might also get here later. + // Make sure we do not instantiate the TypeConstraint more than once. + if (Inst && !Inst->getTypeConstraint()) { + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, InstArgs, TemplateArgs)) + return nullptr; + } + if (AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + TTP->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) + return nullptr; + } + } + } + ParmVarDecl *NewParm = CheckParameter(Context.getTranslationUnitDecl(), OldParm->getInnerLocStart(), OldParm->getLocation(), @@ -1923,7 +2426,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, UnparsedDefaultArgInstantiations[OldParm].push_back(NewParm); } else if (Expr *Arg = OldParm->getDefaultArg()) { FunctionDecl *OwningFunc = cast<FunctionDecl>(OldParm->getDeclContext()); - if (OwningFunc->isLexicallyWithinFunctionOrMethod()) { + if (OwningFunc->isInLocalScopeForInstantiation()) { // Instantiate default arguments for methods of local classes (DR1484) // and non-defining declarations. Sema::ContextRAII SavedContext(*this, OwningFunc); @@ -1932,7 +2435,12 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, if (NewArg.isUsable()) { // It would be nice if we still had this. SourceLocation EqualLoc = NewArg.get()->getBeginLoc(); - SetParamDefaultArgument(NewParm, NewArg.get(), EqualLoc); + ExprResult Result = + ConvertParamDefaultArgument(NewParm, NewArg.get(), EqualLoc); + if (Result.isInvalid()) + return nullptr; + + SetParamDefaultArgument(NewParm, Result.getAs<Expr>(), EqualLoc); } } else { // FIXME: if we non-lazily instantiated non-dependent default args for @@ -3101,6 +3609,12 @@ LocalInstantiationScope::findInstantiationOf(const Decl *D) { if (isa<EnumDecl>(D)) return nullptr; + // Materialized typedefs/type alias for implicit deduction guides may require + // instantiation. + if (isa<TypedefNameDecl>(D) && + isa<CXXDeductionGuideDecl>(D->getDeclContext())) + return nullptr; + // If we didn't find the decl, then we either have a sema bug, or we have a // forward reference to a label declaration. Return null to indicate that // we have an uninstantiated label. @@ -3152,6 +3666,13 @@ void LocalInstantiationScope::MakeInstantiatedLocalArgPack(const Decl *D) { ArgumentPacks.push_back(Pack); } +bool LocalInstantiationScope::isLocalPackExpansion(const Decl *D) { + for (DeclArgumentPack *Pack : ArgumentPacks) + if (std::find(Pack->begin(), Pack->end(), D) != Pack->end()) + return true; + return false; +} + void LocalInstantiationScope::SetPartiallySubstitutedPack(NamedDecl *Pack, const TemplateArgument *ExplicitArgs, unsigned NumExplicitArgs) { diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 64500d0a26d5..2efb7acb9724 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -8,7 +8,7 @@ // This file implements C++ template instantiation for declarations. // //===----------------------------------------------------------------------===/ -#include "clang/Sema/SemaInternal.h" + #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" @@ -19,8 +19,11 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/AST/TypeLoc.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Basic/TargetInfo.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateInstCallback.h" #include "llvm/Support/TimeProfiler.h" @@ -393,50 +396,39 @@ static void instantiateOMPDeclareVariantAttr( VariantFuncRef = Subst(E); } + // Copy the template version of the OMPTraitInfo and run substitute on all + // score and condition expressiosn. + OMPTraitInfo &TI = S.getASTContext().getNewOMPTraitInfo(); + TI = *Attr.getTraitInfos(); + + // Try to substitute template parameters in score and condition expressions. + auto SubstScoreOrConditionExpr = [&S, Subst](Expr *&E, bool) { + if (E) { + EnterExpressionEvaluationContext Unevaluated( + S, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult ER = Subst(E); + if (ER.isUsable()) + E = ER.get(); + else + return true; + } + return false; + }; + if (TI.anyScoreOrCondition(SubstScoreOrConditionExpr)) + return; + // Check function/variant ref. Optional<std::pair<FunctionDecl *, Expr *>> DeclVarData = - S.checkOpenMPDeclareVariantFunction( - S.ConvertDeclToDeclGroup(New), VariantFuncRef.get(), Attr.getRange()); + S.checkOpenMPDeclareVariantFunction(S.ConvertDeclToDeclGroup(New), + VariantFuncRef.get(), TI, + Attr.getRange()); + if (!DeclVarData) return; - SmallVector<Sema::OMPCtxSelectorData, 4> Data; - for (unsigned I = 0, E = Attr.scores_size(); I < E; ++I) { - ExprResult Score; - if (Expr *E = *std::next(Attr.scores_begin(), I)) - Score = Subst(E); - // Instantiate the attribute. - auto CtxSet = static_cast<OpenMPContextSelectorSetKind>( - *std::next(Attr.ctxSelectorSets_begin(), I)); - auto Ctx = static_cast<OpenMPContextSelectorKind>( - *std::next(Attr.ctxSelectors_begin(), I)); - switch (CtxSet) { - case OMP_CTX_SET_implementation: - switch (Ctx) { - case OMP_CTX_vendor: - Data.emplace_back(CtxSet, Ctx, Score, Attr.implVendors()); - break; - case OMP_CTX_kind: - case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); - } - break; - case OMP_CTX_SET_device: - switch (Ctx) { - case OMP_CTX_kind: - Data.emplace_back(CtxSet, Ctx, Score, Attr.deviceKinds()); - break; - case OMP_CTX_vendor: - case OMP_CTX_unknown: - llvm_unreachable("Unexpected context selector kind."); - } - break; - case OMP_CTX_SET_unknown: - llvm_unreachable("Unexpected context selector set kind."); - } - } + S.ActOnOpenMPDeclareVariantDirective(DeclVarData.getValue().first, - DeclVarData.getValue().second, - Attr.getRange(), Data); + DeclVarData.getValue().second, TI, + Attr.getRange()); } static void instantiateDependentAMDGPUFlatWorkGroupSizeAttr( @@ -706,6 +698,10 @@ TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) { llvm_unreachable("extern \"C\" context cannot be instantiated"); } +Decl *TemplateDeclInstantiator::VisitMSGuidDecl(MSGuidDecl *D) { + llvm_unreachable("GUID declaration cannot be instantiated"); +} + Decl * TemplateDeclInstantiator::VisitLabelDecl(LabelDecl *D) { LabelDecl *Inst = LabelDecl::Create(SemaRef.Context, Owner, D->getLocation(), @@ -1837,6 +1833,23 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( return nullptr; QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); + if (TemplateParams && TemplateParams->size()) { + auto *LastParam = + dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back()); + if (LastParam && LastParam->isImplicit() && + LastParam->hasTypeConstraint()) { + // In abbreviated templates, the type-constraints of invented template + // type parameters are instantiated with the function type, invalidating + // the TemplateParameterList which relied on the template type parameter + // not having a type constraint. Recreate the TemplateParameterList with + // the updated parameter list. + TemplateParams = TemplateParameterList::Create( + SemaRef.Context, TemplateParams->getTemplateLoc(), + TemplateParams->getLAngleLoc(), TemplateParams->asArray(), + TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause()); + } + } + NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, @@ -1848,6 +1861,8 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -1896,6 +1911,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( D->hasWrittenPrototype(), D->getConstexprKind(), TrailingRequiresClause); Function->setRangeEnd(D->getSourceRange().getEnd()); + Function->setUsesFPIntrin(D->usesFPIntrin()); } if (D->isInlined()) @@ -2029,7 +2045,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl( // Look only into the namespace where the friend would be declared to // find a previous declaration. This is the innermost enclosing namespace, // as described in ActOnFriendFunctionDecl. - SemaRef.LookupQualifiedName(Previous, DC); + SemaRef.LookupQualifiedName(Previous, DC->getRedeclContext()); // In C++, the previous declaration we find might be a tag type // (class or enum). In this case, the new declaration will hide the @@ -2175,6 +2191,23 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( return nullptr; QualType T = adjustFunctionTypeForInstantiation(SemaRef.Context, D, TInfo); + if (TemplateParams && TemplateParams->size()) { + auto *LastParam = + dyn_cast<TemplateTypeParmDecl>(TemplateParams->asArray().back()); + if (LastParam && LastParam->isImplicit() && + LastParam->hasTypeConstraint()) { + // In abbreviated templates, the type-constraints of invented template + // type parameters are instantiated with the function type, invalidating + // the TemplateParameterList which relied on the template type parameter + // not having a type constraint. Recreate the TemplateParameterList with + // the updated parameter list. + TemplateParams = TemplateParameterList::Create( + SemaRef.Context, TemplateParams->getTemplateLoc(), + TemplateParams->getLAngleLoc(), TemplateParams->asArray(), + TemplateParams->getRAngleLoc(), TemplateParams->getRequiresClause()); + } + } + NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); if (QualifierLoc) { QualifierLoc = SemaRef.SubstNestedNameSpecifierLoc(QualifierLoc, @@ -2186,6 +2219,11 @@ Decl *TemplateDeclInstantiator::VisitCXXMethodDecl( // FIXME: Concepts: Do not substitute into constraint expressions Expr *TrailingRequiresClause = D->getTrailingRequiresClause(); if (TrailingRequiresClause) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(Owner); + Sema::CXXThisScopeRAII ThisScope(SemaRef, ThisContext, + D->getMethodQualifiers(), ThisContext); ExprResult SubstRC = SemaRef.SubstExpr(TrailingRequiresClause, TemplateArgs); if (SubstRC.isInvalid()) @@ -2518,28 +2556,34 @@ Decl *TemplateDeclInstantiator::VisitTemplateTypeParmDecl( Inst->setAccess(AS_public); Inst->setImplicit(D->isImplicit()); if (auto *TC = D->getTypeConstraint()) { - // TODO: Concepts: do not instantiate the constraint (delayed constraint - // substitution) - const ASTTemplateArgumentListInfo *TemplArgInfo - = TC->getTemplateArgsAsWritten(); - TemplateArgumentListInfo InstArgs; - - if (TemplArgInfo) { - InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); - InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); - if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), - TemplArgInfo->NumTemplateArgs, - InstArgs, TemplateArgs)) + if (!D->isImplicit()) { + // Invented template parameter type constraints will be instantiated with + // the corresponding auto-typed parameter as it might reference other + // parameters. + + // TODO: Concepts: do not instantiate the constraint (delayed constraint + // substitution) + const ASTTemplateArgumentListInfo *TemplArgInfo + = TC->getTemplateArgsAsWritten(); + TemplateArgumentListInfo InstArgs; + + if (TemplArgInfo) { + InstArgs.setLAngleLoc(TemplArgInfo->LAngleLoc); + InstArgs.setRAngleLoc(TemplArgInfo->RAngleLoc); + if (SemaRef.Subst(TemplArgInfo->getTemplateArgs(), + TemplArgInfo->NumTemplateArgs, + InstArgs, TemplateArgs)) + return nullptr; + } + if (SemaRef.AttachTypeConstraint( + TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), + TC->getNamedConcept(), &InstArgs, Inst, + D->isParameterPack() + ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) + ->getEllipsisLoc() + : SourceLocation())) return nullptr; } - if (SemaRef.AttachTypeConstraint( - TC->getNestedNameSpecifierLoc(), TC->getConceptNameInfo(), - TC->getNamedConcept(), &InstArgs, Inst, - D->isParameterPack() - ? cast<CXXFoldExpr>(TC->getImmediatelyDeclaredConstraint()) - ->getEllipsisLoc() - : SourceLocation())) - return nullptr; } if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { TypeSourceInfo *InstantiatedDefaultArg = @@ -2685,6 +2729,16 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( D->getDepth() - TemplateArgs.getNumSubstitutedLevels(), D->getPosition(), D->getIdentifier(), T, D->isParameterPack(), DI); + if (AutoTypeLoc AutoLoc = DI->getTypeLoc().getContainedAutoTypeLoc()) + if (AutoLoc.isConstrained()) + if (SemaRef.AttachTypeConstraint( + AutoLoc, Param, + IsExpandedParameterPack + ? DI->getTypeLoc().getAs<PackExpansionTypeLoc>() + .getEllipsisLoc() + : SourceLocation())) + Invalid = true; + Param->setAccess(AS_public); Param->setImplicit(D->isImplicit()); if (Invalid) @@ -3571,6 +3625,9 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( if (InsertPos) VarTemplate->AddSpecialization(Var, InsertPos); + if (SemaRef.getLangOpts().OpenCL) + SemaRef.deduceOpenCLAddressSpace(Var); + // Substitute the nested name specifier, if any. if (SubstQualifier(D, Var)) return nullptr; @@ -3600,6 +3657,12 @@ Decl *TemplateDeclInstantiator::VisitConceptDecl(ConceptDecl *D) { llvm_unreachable("Concept definitions cannot reside inside a template"); } +Decl * +TemplateDeclInstantiator::VisitRequiresExprBodyDecl(RequiresExprBodyDecl *D) { + return RequiresExprBodyDecl::Create(SemaRef.Context, D->getDeclContext(), + D->getBeginLoc()); +} + Decl *TemplateDeclInstantiator::VisitDecl(Decl *D) { llvm_unreachable("Unexpected decl"); } @@ -3659,6 +3722,8 @@ FunctionDecl *Sema::SubstSpaceshipAsEqualEqual(CXXRecordDecl *RD, // access and function-definition and in the same class scope as the // three-way comparison operator function MultiLevelTemplateArgumentList NoTemplateArgs; + NoTemplateArgs.setKind(TemplateSubstitutionKind::Rewrite); + NoTemplateArgs.addOuterRetainedLevels(RD->getTemplateDepth()); TemplateDeclInstantiator Instantiator(*this, RD, NoTemplateArgs); Decl *R; if (auto *MD = dyn_cast<CXXMethodDecl>(Spaceship)) { @@ -3713,6 +3778,8 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { // checking satisfaction. Expr *InstRequiresClause = nullptr; if (Expr *E = L->getRequiresClause()) { + EnterExpressionEvaluationContext ConstantEvaluated( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); ExprResult Res = SemaRef.SubstExpr(E, TemplateArgs); if (Res.isInvalid() || !Res.isUsable()) { return nullptr; @@ -4163,6 +4230,94 @@ static bool addInstantiatedParametersToScope(Sema &S, FunctionDecl *Function, return false; } +bool Sema::InstantiateDefaultArgument(SourceLocation CallLoc, FunctionDecl *FD, + ParmVarDecl *Param) { + assert(Param->hasUninstantiatedDefaultArg()); + Expr *UninstExpr = Param->getUninstantiatedDefaultArg(); + + EnterExpressionEvaluationContext EvalContext( + *this, ExpressionEvaluationContext::PotentiallyEvaluated, Param); + + // Instantiate the expression. + // + // FIXME: Pass in a correct Pattern argument, otherwise + // getTemplateInstantiationArgs uses the lexical context of FD, e.g. + // + // template<typename T> + // struct A { + // static int FooImpl(); + // + // template<typename Tp> + // // bug: default argument A<T>::FooImpl() is evaluated with 2-level + // // template argument list [[T], [Tp]], should be [[Tp]]. + // friend A<Tp> Foo(int a); + // }; + // + // template<typename T> + // A<T> Foo(int a = A<T>::FooImpl()); + MultiLevelTemplateArgumentList TemplateArgs + = getTemplateInstantiationArgs(FD, nullptr, /*RelativeToPrimary=*/true); + + InstantiatingTemplate Inst(*this, CallLoc, Param, + TemplateArgs.getInnermost()); + if (Inst.isInvalid()) + return true; + if (Inst.isAlreadyInstantiating()) { + Diag(Param->getBeginLoc(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return true; + } + + ExprResult Result; + { + // C++ [dcl.fct.default]p5: + // The names in the [default argument] expression are bound, and + // the semantic constraints are checked, at the point where the + // default argument expression appears. + ContextRAII SavedContext(*this, FD); + LocalInstantiationScope Local(*this); + + FunctionDecl *Pattern = FD->getTemplateInstantiationPattern( + /*ForDefinition*/ false); + if (addInstantiatedParametersToScope(*this, FD, Pattern, Local, + TemplateArgs)) + return true; + + runWithSufficientStackSpace(CallLoc, [&] { + Result = SubstInitializer(UninstExpr, TemplateArgs, + /*DirectInit*/false); + }); + } + if (Result.isInvalid()) + return true; + + // Check the expression as an initializer for the parameter. + InitializedEntity Entity + = InitializedEntity::InitializeParameter(Context, Param); + InitializationKind Kind = InitializationKind::CreateCopy( + Param->getLocation(), + /*FIXME:EqualLoc*/ UninstExpr->getBeginLoc()); + Expr *ResultE = Result.getAs<Expr>(); + + InitializationSequence InitSeq(*this, Entity, Kind, ResultE); + Result = InitSeq.Perform(*this, Entity, Kind, ResultE); + if (Result.isInvalid()) + return true; + + Result = + ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart(), + /*DiscardedValue*/ false); + if (Result.isInvalid()) + return true; + + // Remember the instantiated default argument. + Param->setDefaultArg(Result.getAs<Expr>()); + if (ASTMutationListener *L = getASTMutationListener()) + L->DefaultArgumentInstantiated(Param); + + return false; +} + void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, FunctionDecl *Decl) { const FunctionProtoType *Proto = Decl->getType()->castAs<FunctionProtoType>(); @@ -4193,6 +4348,10 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, MultiLevelTemplateArgumentList TemplateArgs = getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); + // FIXME: We can't use getTemplateInstantiationPattern(false) in general + // here, because for a non-defining friend declaration in a class template, + // we don't store enough information to map back to the friend declaration in + // the template. FunctionDecl *Template = Proto->getExceptionSpecTemplate(); if (addInstantiatedParametersToScope(*this, Decl, Template, Scope, TemplateArgs)) { @@ -4224,24 +4383,29 @@ bool Sema::CheckInstantiatedFunctionTemplateConstraints( Sema::ContextRAII savedContext(*this, Decl); LocalInstantiationScope Scope(*this); - MultiLevelTemplateArgumentList MLTAL = - getTemplateInstantiationArgs(Decl, nullptr, /*RelativeToPrimary*/true); - // If this is not an explicit specialization - we need to get the instantiated // version of the template arguments and add them to scope for the // substitution. if (Decl->isTemplateInstantiation()) { InstantiatingTemplate Inst(*this, Decl->getPointOfInstantiation(), InstantiatingTemplate::ConstraintsCheck{}, Decl->getPrimaryTemplate(), - MLTAL.getInnermost(), SourceRange()); + TemplateArgs, SourceRange()); if (Inst.isInvalid()) return true; - if (addInstantiatedParametersToScope(*this, Decl, - Decl->getTemplateInstantiationPattern(), - Scope, MLTAL)) + MultiLevelTemplateArgumentList MLTAL( + *Decl->getTemplateSpecializationArgs()); + if (addInstantiatedParametersToScope( + *this, Decl, Decl->getPrimaryTemplate()->getTemplatedDecl(), + Scope, MLTAL)) return true; } - + Qualifiers ThisQuals; + CXXRecordDecl *Record = nullptr; + if (auto *Method = dyn_cast<CXXMethodDecl>(Decl)) { + ThisQuals = Method->getMethodQualifiers(); + Record = Method->getParent(); + } + CXXThisScopeRAII ThisScope(*this, Record, ThisQuals, Record != nullptr); return CheckConstraintSatisfaction(Template, TemplateAC, TemplateArgs, PointOfInstantiation, Satisfaction); } @@ -4297,7 +4461,7 @@ TemplateDeclInstantiator::InitFunctionInstantiation(FunctionDecl *New, EPI.ExceptionSpec.Type != EST_None && EPI.ExceptionSpec.Type != EST_DynamicNone && EPI.ExceptionSpec.Type != EST_BasicNoexcept && - !Tmpl->isLexicallyWithinFunctionOrMethod()) { + !Tmpl->isInLocalScopeForInstantiation()) { FunctionDecl *ExceptionSpecTemplate = Tmpl; if (EPI.ExceptionSpec.Type == EST_Uninstantiated) ExceptionSpecTemplate = EPI.ExceptionSpec.SourceTemplate; @@ -4734,6 +4898,9 @@ VarTemplateSpecializationDecl *Sema::CompleteVarTemplateSpecializationDecl( // Instantiate the initializer. InstantiateVariableInitializer(VarSpec, PatternDecl, TemplateArgs); + if (getLangOpts().OpenCL) + deduceOpenCLAddressSpace(VarSpec); + return VarSpec; } @@ -4774,6 +4941,7 @@ void Sema::BuildVariableInstantiation( NewVar->setCXXForRangeDecl(OldVar->isCXXForRangeDecl()); NewVar->setObjCForDecl(OldVar->isObjCForDecl()); NewVar->setConstexpr(OldVar->isConstexpr()); + MaybeAddCUDAConstantAttr(NewVar); NewVar->setInitCapture(OldVar->isInitCapture()); NewVar->setPreviousDeclInSameBlockScope( OldVar->isPreviousDeclInSameBlockScope()); @@ -5537,6 +5705,20 @@ DeclContext *Sema::FindInstantiatedContext(SourceLocation Loc, DeclContext* DC, } else return DC; } +/// Determine whether the given context is dependent on template parameters at +/// level \p Level or below. +/// +/// Sometimes we only substitute an inner set of template arguments and leave +/// the outer templates alone. In such cases, contexts dependent only on the +/// outer levels are not effectively dependent. +static bool isDependentContextAtLevel(DeclContext *DC, unsigned Level) { + if (!DC->isDependentContext()) + return false; + if (!Level) + return true; + return cast<Decl>(DC)->getTemplateDepth() > Level; +} + /// Find the instantiation of the given declaration within the /// current instantiation. /// @@ -5567,6 +5749,10 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, const MultiLevelTemplateArgumentList &TemplateArgs, bool FindingInstantiatedContext) { DeclContext *ParentDC = D->getDeclContext(); + // Determine whether our parent context depends on any of the tempalte + // arguments we're currently substituting. + bool ParentDependsOnArgs = isDependentContextAtLevel( + ParentDC, TemplateArgs.getNumRetainedOuterLevels()); // FIXME: Parmeters of pointer to functions (y below) that are themselves // parameters (p below) can have their ParentDC set to the translation-unit // - thus we can not consistently check if the ParentDC of such a parameter @@ -5583,15 +5769,14 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // - as long as we have a ParmVarDecl whose parent is non-dependent and // whose type is not instantiation dependent, do nothing to the decl // - otherwise find its instantiated decl. - if (isa<ParmVarDecl>(D) && !ParentDC->isDependentContext() && + if (isa<ParmVarDecl>(D) && !ParentDependsOnArgs && !cast<ParmVarDecl>(D)->getType()->isInstantiationDependentType()) return D; if (isa<ParmVarDecl>(D) || isa<NonTypeTemplateParmDecl>(D) || isa<TemplateTypeParmDecl>(D) || isa<TemplateTemplateParmDecl>(D) || - ((ParentDC->isFunctionOrMethod() || - isa<OMPDeclareReductionDecl>(ParentDC) || - isa<OMPDeclareMapperDecl>(ParentDC)) && - ParentDC->isDependentContext()) || + (ParentDependsOnArgs && (ParentDC->isFunctionOrMethod() || + isa<OMPDeclareReductionDecl>(ParentDC) || + isa<OMPDeclareMapperDecl>(ParentDC))) || (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda())) { // D is a local of some kind. Look into the map of local // declarations to their instantiations. @@ -5634,6 +5819,9 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, bool NeedInstantiate = false; if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(D)) NeedInstantiate = RD->isLocalClass(); + else if (isa<TypedefNameDecl>(D) && + isa<CXXDeductionGuideDecl>(D->getDeclContext())) + NeedInstantiate = true; else NeedInstantiate = isa<EnumDecl>(D); if (NeedInstantiate) { @@ -5742,7 +5930,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, // anonymous unions in class templates). } - if (!ParentDC->isDependentContext()) + if (!ParentDependsOnArgs) return D; ParentDC = FindInstantiatedContext(Loc, ParentDC, TemplateArgs); @@ -5811,10 +5999,11 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, if (!Result) { if (isa<UsingShadowDecl>(D)) { // UsingShadowDecls can instantiate to nothing because of using hiding. - } else if (Diags.hasErrorOccurred()) { - // We've already complained about something, so most likely this - // declaration failed to instantiate. There's no point in complaining - // further, since this is normal in invalid code. + } else if (Diags.hasUncompilableErrorOccurred()) { + // We've already complained about some ill-formed code, so most likely + // this declaration failed to instantiate. There's no point in + // complaining further, since this is normal in invalid code. + // FIXME: Use more fine-grained 'invalid' tracking for this. } else if (IsBeingInstantiated) { // The class in which this member exists is currently being // instantiated, and we haven't gotten around to instantiating this @@ -5854,6 +6043,7 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, /// Performs template instantiation for all implicit template /// instantiations we have seen until this point. void Sema::PerformPendingInstantiations(bool LocalOnly) { + std::deque<PendingImplicitInstantiation> delayedPCHInstantiations; while (!PendingLocalImplicitInstantiations.empty() || (!LocalOnly && !PendingInstantiations.empty())) { PendingImplicitInstantiation Inst; @@ -5884,6 +6074,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { if (Function->isDefined()) Function->setInstantiationIsPending(false); } + // Definition of a PCH-ed template declaration may be available only in the TU. + if (!LocalOnly && LangOpts.PCHInstantiateTemplates && + TUKind == TU_Prefix && Function->instantiationIsPending()) + delayedPCHInstantiations.push_back(Inst); continue; } @@ -5929,6 +6123,9 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, DefinitionRequired, true); } + + if (!LocalOnly && LangOpts.PCHInstantiateTemplates) + PendingInstantiations.swap(delayedPCHInstantiations); } void Sema::PerformDependentDiagnostics(const DeclContext *Pattern, diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp index d947d6d282be..7b77d1cb482a 100644 --- a/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -847,6 +847,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_typeofExpr: case TST_decltype: + case TST_extint: if (DS.getRepAsExpr() && DS.getRepAsExpr()->containsUnexpandedParameterPack()) return true; @@ -880,6 +881,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_auto: case TST_auto_type: case TST_decltype_auto: + case TST_BFloat16: #define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t: #include "clang/Basic/OpenCLImageTypes.def" case TST_unknown_anytype: @@ -940,7 +942,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { if (Expr *TRC = D.getTrailingRequiresClause()) if (TRC->containsUnexpandedParameterPack()) return true; - + return false; } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index 3884fdae8fe7..b8f7f1a58159 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -27,6 +27,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" @@ -34,6 +35,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/DerivedTypes.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -128,6 +130,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, case ParsedAttr::AT_NSReturnsRetained: \ case ParsedAttr::AT_NoReturn: \ case ParsedAttr::AT_Regparm: \ + case ParsedAttr::AT_CmseNSCall: \ case ParsedAttr::AT_AnyX86NoCallerSavedRegisters: \ case ParsedAttr::AT_AnyX86NoCfCheck: \ CALLING_CONV_ATTRS_CASELIST @@ -1251,6 +1254,26 @@ getImageAccess(const ParsedAttributesView &Attrs) { return OpenCLAccessAttr::Keyword_read_only; } +static QualType ConvertConstrainedAutoDeclSpecToType(Sema &S, DeclSpec &DS, + AutoTypeKeyword AutoKW) { + assert(DS.isConstrainedAuto()); + TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); + TemplateArgumentListInfo TemplateArgsInfo; + TemplateArgsInfo.setLAngleLoc(TemplateId->LAngleLoc); + TemplateArgsInfo.setRAngleLoc(TemplateId->RAngleLoc); + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + llvm::SmallVector<TemplateArgument, 8> TemplateArgs; + for (auto &ArgLoc : TemplateArgsInfo.arguments()) + TemplateArgs.push_back(ArgLoc.getArgument()); + return S.Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false, + /*IsPack=*/false, + cast<ConceptDecl>(TemplateId->Template.get() + .getAsTemplateDecl()), + TemplateArgs); +} + /// Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -1419,6 +1442,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; } + case DeclSpec::TST_extint: { + if (!S.Context.getTargetInfo().hasExtIntType()) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "_ExtInt"; + Result = S.BuildExtIntType(DS.getTypeSpecSign() == TSS_unsigned, + DS.getRepAsExpr(), DS.getBeginLoc()); + if (Result.isNull()) { + Result = Context.IntTy; + declarator.setInvalidType(true); + } + break; + } case DeclSpec::TST_accum: { switch (DS.getTypeSpecWidth()) { case DeclSpec::TSW_short: @@ -1486,6 +1521,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.Float16Ty; break; case DeclSpec::TST_half: Result = Context.HalfTy; break; + case DeclSpec::TST_BFloat16: + if (!S.Context.getTargetInfo().hasBFloat16Type()) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__bf16"; + Result = Context.BFloat16Ty; + break; case DeclSpec::TST_float: Result = Context.FloatTy; break; case DeclSpec::TST_double: if (DS.getTypeSpecWidth() == DeclSpec::TSW_long) @@ -1495,6 +1536,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type() && + !S.getLangOpts().SYCLIsDevice && !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; @@ -1595,6 +1637,11 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_auto: + if (DS.isConstrainedAuto()) { + Result = ConvertConstrainedAutoDeclSpecToType(S, DS, + AutoTypeKeyword::Auto); + break; + } Result = Context.getAutoType(QualType(), AutoTypeKeyword::Auto, false); break; @@ -1603,6 +1650,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; case DeclSpec::TST_decltype_auto: + if (DS.isConstrainedAuto()) { + Result = + ConvertConstrainedAutoDeclSpecToType(S, DS, + AutoTypeKeyword::DecltypeAuto); + break; + } Result = Context.getAutoType(QualType(), AutoTypeKeyword::DecltypeAuto, /*IsDependent*/ false); break; @@ -1645,6 +1698,12 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; } + // FIXME: we want resulting declarations to be marked invalid, but claiming + // the type is invalid is too strong - e.g. it causes ActOnTypeName to return + // a null type. + if (Result->containsErrors()) + declarator.setInvalidType(); + if (S.getLangOpts().OpenCL && S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) declarator.setInvalidType(true); @@ -1700,7 +1759,7 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // The effect of a cv-qualifier-seq in a function declarator is not the // same as adding cv-qualification on top of the function type. In the // latter case, the cv-qualifiers are ignored. - if (TypeQuals && Result->isFunctionType()) { + if (Result->isFunctionType()) { diagnoseAndRemoveTypeQualifiers( S, DS, TypeQuals, Result, DeclSpec::TQ_const | DeclSpec::TQ_volatile, S.getLangOpts().CPlusPlus @@ -2121,6 +2180,45 @@ QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) { return Context.getWritePipeType(T); } +/// Build a extended int type. +/// +/// \param IsUnsigned Boolean representing the signedness of the type. +/// +/// \param BitWidth Size of this int type in bits, or an expression representing +/// that. +/// +/// \param Loc Location of the keyword. +QualType Sema::BuildExtIntType(bool IsUnsigned, Expr *BitWidth, + SourceLocation Loc) { + if (BitWidth->isInstantiationDependent()) + return Context.getDependentExtIntType(IsUnsigned, BitWidth); + + llvm::APSInt Bits(32); + ExprResult ICE = VerifyIntegerConstantExpression(BitWidth, &Bits); + + if (ICE.isInvalid()) + return QualType(); + + int64_t NumBits = Bits.getSExtValue(); + if (!IsUnsigned && NumBits < 2) { + Diag(Loc, diag::err_ext_int_bad_size) << 0; + return QualType(); + } + + if (IsUnsigned && NumBits < 1) { + Diag(Loc, diag::err_ext_int_bad_size) << 1; + return QualType(); + } + + if (NumBits > llvm::IntegerType::MAX_INT_BITS) { + Diag(Loc, diag::err_ext_int_max_size) << IsUnsigned + << llvm::IntegerType::MAX_INT_BITS; + return QualType(); + } + + return Context.getExtIntType(IsUnsigned, NumBits); +} + /// Check whether the specified array size makes the array type a VLA. If so, /// return true, if not, return the size of the array in SizeVal. static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { @@ -2182,7 +2280,7 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } if (T->isVoidType() || T->isIncompleteArrayType()) { - Diag(Loc, diag::err_illegal_decl_array_incomplete_type) << T; + Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 0 << T; return QualType(); } @@ -2200,11 +2298,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, } else { // C99 6.7.5.2p1: If the element type is an incomplete or function type, // reject it (e.g. void ary[7], struct foo ary[7], void ary[7]()) - if (RequireCompleteType(Loc, T, - diag::err_illegal_decl_array_incomplete_type)) + if (RequireCompleteSizedType(Loc, T, + diag::err_array_incomplete_or_sizeless_type)) return QualType(); } + if (T->isSizelessType()) { + Diag(Loc, diag::err_array_incomplete_or_sizeless_type) << 1 << T; + return QualType(); + } + if (T->isFunctionType()) { Diag(Loc, diag::err_illegal_decl_array_of_functions) << getPrintableNameForEntity(Entity) << T; @@ -2290,13 +2393,6 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, ? diag::err_typecheck_zero_array_size : diag::ext_typecheck_zero_array_size) << ArraySize->getSourceRange(); - - if (ASM == ArrayType::Static) { - Diag(ArraySize->getBeginLoc(), - diag::warn_typecheck_zero_static_array_size) - << ArraySize->getSourceRange(); - ASM = ArrayType::Normal; - } } else if (!T->isDependentType() && !T->isVariablyModifiedType() && !T->isIncompleteType() && !T->isUndeducedType()) { // Is the array too large? @@ -2392,28 +2488,35 @@ QualType Sema::BuildVectorType(QualType CurType, Expr *SizeExpr, return Context.getDependentVectorType(CurType, SizeExpr, AttrLoc, VectorType::GenericVector); - unsigned VectorSize = static_cast<unsigned>(VecSize.getZExtValue() * 8); + // vecSize is specified in bytes - convert to bits. + if (!VecSize.isIntN(61)) { + // Bit size will overflow uint64. + Diag(AttrLoc, diag::err_attribute_size_too_large) + << SizeExpr->getSourceRange() << "vector"; + return QualType(); + } + uint64_t VectorSizeBits = VecSize.getZExtValue() * 8; unsigned TypeSize = static_cast<unsigned>(Context.getTypeSize(CurType)); - if (VectorSize == 0) { - Diag(AttrLoc, diag::err_attribute_zero_size) << SizeExpr->getSourceRange(); + if (VectorSizeBits == 0) { + Diag(AttrLoc, diag::err_attribute_zero_size) + << SizeExpr->getSourceRange() << "vector"; return QualType(); } - // vecSize is specified in bytes - convert to bits. - if (VectorSize % TypeSize) { + if (VectorSizeBits % TypeSize) { Diag(AttrLoc, diag::err_attribute_invalid_size) << SizeExpr->getSourceRange(); return QualType(); } - if (VectorType::isVectorSizeTooLarge(VectorSize / TypeSize)) { + if (VectorSizeBits / TypeSize > std::numeric_limits<uint32_t>::max()) { Diag(AttrLoc, diag::err_attribute_size_too_large) - << SizeExpr->getSourceRange(); + << SizeExpr->getSourceRange() << "vector"; return QualType(); } - return Context.getVectorType(CurType, VectorSize / TypeSize, + return Context.getVectorType(CurType, VectorSizeBits / TypeSize, VectorType::GenericVector); } @@ -2445,19 +2548,18 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } + if (!vecSize.isIntN(32)) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << ArraySize->getSourceRange() << "vector"; + return QualType(); + } // Unlike gcc's vector_size attribute, the size is specified as the // number of elements, not the number of bytes. unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); if (vectorSize == 0) { Diag(AttrLoc, diag::err_attribute_zero_size) - << ArraySize->getSourceRange(); - return QualType(); - } - - if (VectorType::isVectorSizeTooLarge(vectorSize)) { - Diag(AttrLoc, diag::err_attribute_size_too_large) - << ArraySize->getSourceRange(); + << ArraySize->getSourceRange() << "vector"; return QualType(); } @@ -2467,6 +2569,84 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return Context.getDependentSizedExtVectorType(T, ArraySize, AttrLoc); } +QualType Sema::BuildMatrixType(QualType ElementTy, Expr *NumRows, Expr *NumCols, + SourceLocation AttrLoc) { + assert(Context.getLangOpts().MatrixTypes && + "Should never build a matrix type when it is disabled"); + + // Check element type, if it is not dependent. + if (!ElementTy->isDependentType() && + !MatrixType::isValidElementType(ElementTy)) { + Diag(AttrLoc, diag::err_attribute_invalid_matrix_type) << ElementTy; + return QualType(); + } + + if (NumRows->isTypeDependent() || NumCols->isTypeDependent() || + NumRows->isValueDependent() || NumCols->isValueDependent()) + return Context.getDependentSizedMatrixType(ElementTy, NumRows, NumCols, + AttrLoc); + + // Both row and column values can only be 20 bit wide currently. + llvm::APSInt ValueRows(32), ValueColumns(32); + + bool const RowsIsInteger = NumRows->isIntegerConstantExpr(ValueRows, Context); + bool const ColumnsIsInteger = + NumCols->isIntegerConstantExpr(ValueColumns, Context); + + auto const RowRange = NumRows->getSourceRange(); + auto const ColRange = NumCols->getSourceRange(); + + // Both are row and column expressions are invalid. + if (!RowsIsInteger && !ColumnsIsInteger) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "matrix_type" << AANT_ArgumentIntegerConstant << RowRange + << ColRange; + return QualType(); + } + + // Only the row expression is invalid. + if (!RowsIsInteger) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "matrix_type" << AANT_ArgumentIntegerConstant << RowRange; + return QualType(); + } + + // Only the column expression is invalid. + if (!ColumnsIsInteger) { + Diag(AttrLoc, diag::err_attribute_argument_type) + << "matrix_type" << AANT_ArgumentIntegerConstant << ColRange; + return QualType(); + } + + // Check the matrix dimensions. + unsigned MatrixRows = static_cast<unsigned>(ValueRows.getZExtValue()); + unsigned MatrixColumns = static_cast<unsigned>(ValueColumns.getZExtValue()); + if (MatrixRows == 0 && MatrixColumns == 0) { + Diag(AttrLoc, diag::err_attribute_zero_size) + << "matrix" << RowRange << ColRange; + return QualType(); + } + if (MatrixRows == 0) { + Diag(AttrLoc, diag::err_attribute_zero_size) << "matrix" << RowRange; + return QualType(); + } + if (MatrixColumns == 0) { + Diag(AttrLoc, diag::err_attribute_zero_size) << "matrix" << ColRange; + return QualType(); + } + if (!ConstantMatrixType::isDimensionValid(MatrixRows)) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << RowRange << "matrix row"; + return QualType(); + } + if (!ConstantMatrixType::isDimensionValid(MatrixColumns)) { + Diag(AttrLoc, diag::err_attribute_size_too_large) + << ColRange << "matrix column"; + return QualType(); + } + return Context.getConstantMatrixType(ElementTy, MatrixRows, MatrixColumns); +} + bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { if (T->isArrayType() || T->isFunctionType()) { Diag(Loc, diag::err_func_returning_array_function) @@ -2496,7 +2676,7 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { // C++2a [dcl.fct]p12: // A volatile-qualified return type is deprecated - if (T.isVolatileQualified() && getLangOpts().CPlusPlus2a) + if (T.isVolatileQualified() && getLangOpts().CPlusPlus20) Diag(Loc, diag::warn_deprecated_volatile_return) << T; return false; @@ -2581,7 +2761,7 @@ QualType Sema::BuildFunctionType(QualType T, // C++2a [dcl.fct]p4: // A parameter with volatile-qualified type is deprecated - if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus2a) + if (ParamType.isVolatileQualified() && getLangOpts().CPlusPlus20) Diag(Loc, diag::warn_deprecated_volatile_param) << ParamType; ParamTypes[Idx] = ParamType; @@ -2921,6 +3101,87 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, D.getDeclSpec().getUnalignedSpecLoc()); } +static void CopyTypeConstraintFromAutoType(Sema &SemaRef, const AutoType *Auto, + AutoTypeLoc AutoLoc, + TemplateTypeParmDecl *TP, + SourceLocation EllipsisLoc) { + + TemplateArgumentListInfo TAL(AutoLoc.getLAngleLoc(), AutoLoc.getRAngleLoc()); + for (unsigned Idx = 0; Idx < AutoLoc.getNumArgs(); ++Idx) + TAL.addArgument(AutoLoc.getArgLoc(Idx)); + + SemaRef.AttachTypeConstraint( + AutoLoc.getNestedNameSpecifierLoc(), AutoLoc.getConceptNameInfo(), + AutoLoc.getNamedConcept(), + AutoLoc.hasExplicitTemplateArgs() ? &TAL : nullptr, TP, EllipsisLoc); +} + +static QualType InventTemplateParameter( + TypeProcessingState &state, QualType T, TypeSourceInfo *TSI, AutoType *Auto, + InventedTemplateParameterInfo &Info) { + Sema &S = state.getSema(); + Declarator &D = state.getDeclarator(); + + const unsigned TemplateParameterDepth = Info.AutoTemplateParameterDepth; + const unsigned AutoParameterPosition = Info.TemplateParams.size(); + const bool IsParameterPack = D.hasEllipsis(); + + // If auto is mentioned in a lambda parameter or abbreviated function + // template context, convert it to a template parameter type. + + // Create the TemplateTypeParmDecl here to retrieve the corresponding + // template parameter type. Template parameters are temporarily added + // to the TU until the associated TemplateDecl is created. + TemplateTypeParmDecl *InventedTemplateParam = + TemplateTypeParmDecl::Create( + S.Context, S.Context.getTranslationUnitDecl(), + /*KeyLoc=*/D.getDeclSpec().getTypeSpecTypeLoc(), + /*NameLoc=*/D.getIdentifierLoc(), + TemplateParameterDepth, AutoParameterPosition, + S.InventAbbreviatedTemplateParameterTypeName( + D.getIdentifier(), AutoParameterPosition), false, + IsParameterPack, /*HasTypeConstraint=*/Auto->isConstrained()); + InventedTemplateParam->setImplicit(); + Info.TemplateParams.push_back(InventedTemplateParam); + // Attach type constraints + if (Auto->isConstrained()) { + if (TSI) { + CopyTypeConstraintFromAutoType( + S, Auto, TSI->getTypeLoc().getContainedAutoTypeLoc(), + InventedTemplateParam, D.getEllipsisLoc()); + } else { + TemplateIdAnnotation *TemplateId = D.getDeclSpec().getRepAsTemplateId(); + TemplateArgumentListInfo TemplateArgsInfo; + if (TemplateId->LAngleLoc.isValid()) { + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + S.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + } + S.AttachTypeConstraint( + D.getDeclSpec().getTypeSpecScope().getWithLocInContext(S.Context), + DeclarationNameInfo(DeclarationName(TemplateId->Name), + TemplateId->TemplateNameLoc), + cast<ConceptDecl>(TemplateId->Template.get().getAsTemplateDecl()), + TemplateId->LAngleLoc.isValid() ? &TemplateArgsInfo : nullptr, + InventedTemplateParam, D.getEllipsisLoc()); + } + } + + // If TSI is nullptr, this is a constrained declspec auto and the type + // constraint will be attached later in TypeSpecLocFiller + + // Replace the 'auto' in the function parameter with this invented + // template type parameter. + // FIXME: Retain some type sugar to indicate that this was written + // as 'auto'? + return state.ReplaceAutoType( + T, QualType(InventedTemplateParam->getTypeForDecl(), 0)); +} + +static TypeSourceInfo * +GetTypeSourceInfoForDeclarator(TypeProcessingState &State, + QualType T, TypeSourceInfo *ReturnTypeInfo); + static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, TypeSourceInfo *&ReturnTypeInfo) { Sema &SemaRef = state.getSema(); @@ -2991,54 +3252,58 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, break; case DeclaratorContext::ObjCParameterContext: case DeclaratorContext::ObjCResultContext: - case DeclaratorContext::PrototypeContext: Error = 0; break; - case DeclaratorContext::LambdaExprParameterContext: - // In C++14, generic lambdas allow 'auto' in their parameters. - if (!SemaRef.getLangOpts().CPlusPlus14 || - !Auto || Auto->getKeyword() != AutoTypeKeyword::Auto) - Error = 16; - else { - // If auto is mentioned in a lambda parameter context, convert it to a - // template parameter type. - sema::LambdaScopeInfo *LSI = SemaRef.getCurLambda(); - assert(LSI && "No LambdaScopeInfo on the stack!"); - const unsigned TemplateParameterDepth = LSI->AutoTemplateParameterDepth; - const unsigned AutoParameterPosition = LSI->TemplateParams.size(); - const bool IsParameterPack = D.hasEllipsis(); - - // Create the TemplateTypeParmDecl here to retrieve the corresponding - // template parameter type. Template parameters are temporarily added - // to the TU until the associated TemplateDecl is created. - TemplateTypeParmDecl *CorrespondingTemplateParam = - TemplateTypeParmDecl::Create( - SemaRef.Context, SemaRef.Context.getTranslationUnitDecl(), - /*KeyLoc*/ SourceLocation(), /*NameLoc*/ D.getBeginLoc(), - TemplateParameterDepth, AutoParameterPosition, - /*Identifier*/ nullptr, false, IsParameterPack, - /*HasTypeConstraint=*/false); - CorrespondingTemplateParam->setImplicit(); - LSI->TemplateParams.push_back(CorrespondingTemplateParam); - // Replace the 'auto' in the function parameter with this invented - // template type parameter. - // FIXME: Retain some type sugar to indicate that this was written - // as 'auto'. - T = state.ReplaceAutoType( - T, QualType(CorrespondingTemplateParam->getTypeForDecl(), 0)); + case DeclaratorContext::RequiresExprContext: + Error = 22; + break; + case DeclaratorContext::PrototypeContext: + case DeclaratorContext::LambdaExprParameterContext: { + InventedTemplateParameterInfo *Info = nullptr; + if (D.getContext() == DeclaratorContext::PrototypeContext) { + // With concepts we allow 'auto' in function parameters. + if (!SemaRef.getLangOpts().CPlusPlus20 || !Auto || + Auto->getKeyword() != AutoTypeKeyword::Auto) { + Error = 0; + break; + } else if (!SemaRef.getCurScope()->isFunctionDeclarationScope()) { + Error = 21; + break; + } else if (D.hasTrailingReturnType()) { + // This might be OK, but we'll need to convert the trailing return + // type later. + break; + } + + Info = &SemaRef.InventedParameterInfos.back(); + } else { + // In C++14, generic lambdas allow 'auto' in their parameters. + if (!SemaRef.getLangOpts().CPlusPlus14 || !Auto || + Auto->getKeyword() != AutoTypeKeyword::Auto) { + Error = 16; + break; + } + Info = SemaRef.getCurLambda(); + assert(Info && "No LambdaScopeInfo on the stack!"); } + T = InventTemplateParameter(state, T, nullptr, Auto, *Info); break; + } case DeclaratorContext::MemberContext: { if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_static || D.isFunctionDeclarator()) break; bool Cxx = SemaRef.getLangOpts().CPlusPlus; - switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { - case TTK_Enum: llvm_unreachable("unhandled tag kind"); - case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break; - case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break; - case TTK_Class: Error = 5; /* Class member */ break; - case TTK_Interface: Error = 6; /* Interface member */ break; + if (isa<ObjCContainerDecl>(SemaRef.CurContext)) { + Error = 6; // Interface member. + } else { + switch (cast<TagDecl>(SemaRef.CurContext)->getTagKind()) { + case TTK_Enum: llvm_unreachable("unhandled tag kind"); + case TTK_Struct: Error = Cxx ? 1 : 2; /* Struct member */ break; + case TTK_Union: Error = Cxx ? 3 : 4; /* Union member */ break; + case TTK_Class: Error = 5; /* Class member */ break; + case TTK_Interface: Error = 6; /* Interface member */ break; + } } if (D.getDeclSpec().isFriendSpecified()) Error = 20; // Friend type @@ -3221,6 +3486,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::ObjCParameterContext: case DeclaratorContext::ObjCResultContext: case DeclaratorContext::KNRTypeListContext: + case DeclaratorContext::RequiresExprContext: // C++ [dcl.fct]p6: // Types shall not be defined in return or parameter types. DiagID = diag::err_type_defined_in_param_type; @@ -4028,10 +4294,6 @@ static bool DiagnoseMultipleAddrSpaceAttributes(Sema &S, LangAS ASOld, return false; } -static TypeSourceInfo * -GetTypeSourceInfoForDeclarator(TypeProcessingState &State, - QualType T, TypeSourceInfo *ReturnTypeInfo); - static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, QualType declSpecType, TypeSourceInfo *TInfo) { @@ -4279,6 +4541,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorContext::TemplateTypeArgContext: case DeclaratorContext::TypeNameContext: case DeclaratorContext::FunctionalCastContext: + case DeclaratorContext::RequiresExprContext: // Don't infer in these contexts. break; } @@ -4606,7 +4869,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } else if (D.getContext() != DeclaratorContext::LambdaExprContext && (T.hasQualifiers() || !isa<AutoType>(T) || cast<AutoType>(T)->getKeyword() != - AutoTypeKeyword::Auto)) { + AutoTypeKeyword::Auto || + cast<AutoType>(T)->isConstrained())) { S.Diag(D.getDeclSpec().getTypeSpecTypeLoc(), diag::err_trailing_return_without_auto) << T << D.getDeclSpec().getSourceRange(); @@ -4617,7 +4881,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // An error occurred parsing the trailing return type. T = Context.IntTy; D.setInvalidType(true); - } + } else if (S.getLangOpts().CPlusPlus20) + // Handle cases like: `auto f() -> auto` or `auto f() -> C auto`. + if (AutoType *Auto = T->getContainedAutoType()) + if (S.getCurScope()->isFunctionDeclarationScope()) + T = InventTemplateParameter(state, T, TInfo, Auto, + S.InventedParameterInfos.back()); } else { // This function type is not the type of the entity being declared, // so checking the 'auto' is not the responsibility of this chunk. @@ -4721,7 +4990,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++2a [dcl.fct]p12: // A volatile-qualified return type is deprecated - if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a) + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus20) S.Diag(DeclType.Loc, diag::warn_deprecated_volatile_return) << T; } @@ -4863,8 +5132,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // FIXME: This really should be in BuildFunctionType. if (S.getLangOpts().OpenCL) { if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) { - S.Diag(Param->getLocation(), - diag::err_opencl_half_param) << ParamTy; + S.Diag(Param->getLocation(), diag::err_opencl_invalid_param) + << ParamTy << 0; D.setInvalidType(); Param->setInvalidDecl(); } @@ -4883,6 +5152,11 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, Param->setKNRPromoted(true); } } + } else if (S.getLangOpts().OpenCL && ParamTy->isBlockPointerType()) { + // OpenCL 2.0 s6.12.5: A block cannot be a parameter of a function. + S.Diag(Param->getLocation(), diag::err_opencl_invalid_param) + << ParamTy << 1 /*hint off*/; + D.setInvalidType(); } if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) { @@ -5212,7 +5486,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C++2a [dcl.fct]p4: // A parameter with volatile-qualified type is deprecated - if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus2a && + if (T.isVolatileQualified() && S.getLangOpts().CPlusPlus20 && (D.getContext() == DeclaratorContext::PrototypeContext || D.getContext() == DeclaratorContext::LambdaExprParameterContext)) S.Diag(D.getIdentifierLoc(), diag::warn_deprecated_volatile_param) << T; @@ -5227,6 +5501,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, switch (D.getContext()) { case DeclaratorContext::PrototypeContext: case DeclaratorContext::LambdaExprParameterContext: + case DeclaratorContext::RequiresExprContext: // C++0x [dcl.fct]p13: // [...] When it is part of a parameter-declaration-clause, the // parameter pack is a function parameter pack (14.5.3). The type T @@ -5236,7 +5511,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // // We represent function parameter packs as function parameters whose // type is a pack expansion. - if (!T->containsUnexpandedParameterPack()) { + if (!T->containsUnexpandedParameterPack() && + (!LangOpts.CPlusPlus20 || !T->getContainedAutoType())) { S.Diag(D.getEllipsisLoc(), diag::err_function_parameter_pack_without_parameter_packs) << T << D.getSourceRange(); @@ -5444,14 +5720,15 @@ static void fillAttributedTypeLoc(AttributedTypeLoc TL, namespace { class TypeSpecLocFiller : public TypeLocVisitor<TypeSpecLocFiller> { + Sema &SemaRef; ASTContext &Context; TypeProcessingState &State; const DeclSpec &DS; public: - TypeSpecLocFiller(ASTContext &Context, TypeProcessingState &State, + TypeSpecLocFiller(Sema &S, ASTContext &Context, TypeProcessingState &State, const DeclSpec &DS) - : Context(Context), State(State), DS(DS) {} + : SemaRef(S), Context(Context), State(State), DS(DS) {} void VisitAttributedTypeLoc(AttributedTypeLoc TL) { Visit(TL.getModifiedLoc()); @@ -5579,6 +5856,34 @@ namespace { TL.copy( TInfo->getTypeLoc().castAs<DependentTemplateSpecializationTypeLoc>()); } + void VisitAutoTypeLoc(AutoTypeLoc TL) { + assert(DS.getTypeSpecType() == TST_auto || + DS.getTypeSpecType() == TST_decltype_auto || + DS.getTypeSpecType() == TST_auto_type || + DS.getTypeSpecType() == TST_unspecified); + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + if (!DS.isConstrainedAuto()) + return; + TemplateIdAnnotation *TemplateId = DS.getRepAsTemplateId(); + if (DS.getTypeSpecScope().isNotEmpty()) + TL.setNestedNameSpecifierLoc( + DS.getTypeSpecScope().getWithLocInContext(Context)); + else + TL.setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); + TL.setTemplateKWLoc(TemplateId->TemplateKWLoc); + TL.setConceptNameLoc(TemplateId->TemplateNameLoc); + TL.setFoundDecl(nullptr); + TL.setLAngleLoc(TemplateId->LAngleLoc); + TL.setRAngleLoc(TemplateId->RAngleLoc); + if (TemplateId->NumArgs == 0) + return; + TemplateArgumentListInfo TemplateArgsInfo; + ASTTemplateArgsPtr TemplateArgsPtr(TemplateId->getTemplateArgs(), + TemplateId->NumArgs); + SemaRef.translateTemplateArguments(TemplateArgsPtr, TemplateArgsInfo); + for (unsigned I = 0; I < TemplateId->NumArgs; ++I) + TL.setArgLocInfo(I, TemplateArgsInfo.arguments()[I].getLocInfo()); + } void VisitTagTypeLoc(TagTypeLoc TL) { TL.setNameLoc(DS.getTypeSpecTypeNameLoc()); } @@ -5609,6 +5914,14 @@ namespace { TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); } + void VisitExtIntTypeLoc(ExtIntTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + + void VisitDependentExtIntTypeLoc(DependentExtIntTypeLoc TL) { + TL.setNameLoc(DS.getTypeSpecTypeLoc()); + } + void VisitTypeLoc(TypeLoc TL) { // FIXME: add other typespec types and change this to an assert. TL.initialize(Context, DS.getTypeSpecTypeLoc()); @@ -5692,7 +6005,7 @@ namespace { } // Finally fill in MemberPointerLocInfo fields. - TL.setStarLoc(Chunk.Loc); + TL.setStarLoc(SourceLocation::getFromRawEncoding(Chunk.Mem.StarLoc)); TL.setClassTInfo(ClsTInfo); } void VisitLValueReferenceTypeLoc(LValueReferenceTypeLoc TL) { @@ -5735,6 +6048,9 @@ namespace { assert(Chunk.Kind == DeclaratorChunk::Pipe); TL.setKWLoc(Chunk.Loc); } + void VisitExtIntTypeLoc(ExtIntTypeLoc TL) { + TL.setNameLoc(Chunk.Loc); + } void VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc TL) { TL.setExpansionLoc(Chunk.Loc); } @@ -5785,6 +6101,21 @@ fillDependentAddressSpaceTypeLoc(DependentAddressSpaceTypeLoc DASTL, "no address_space attribute found at the expected location!"); } +static void fillMatrixTypeLoc(MatrixTypeLoc MTL, + const ParsedAttributesView &Attrs) { + for (const ParsedAttr &AL : Attrs) { + if (AL.getKind() == ParsedAttr::AT_MatrixType) { + MTL.setAttrNameLoc(AL.getLoc()); + MTL.setAttrRowOperand(AL.getArgAsExpr(0)); + MTL.setAttrColumnOperand(AL.getArgAsExpr(1)); + MTL.setAttrOperandParensRange(SourceRange()); + return; + } + } + + llvm_unreachable("no matrix_type attribute found at the expected location!"); +} + /// Create and instantiate a TypeSourceInfo with type source information. /// /// \param T QualType referring to the type as written in source code. @@ -5833,6 +6164,9 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, CurrTL = TL.getPointeeTypeLoc().getUnqualifiedLoc(); } + if (MatrixTypeLoc TL = CurrTL.getAs<MatrixTypeLoc>()) + fillMatrixTypeLoc(TL, D.getTypeObject(i).getAttrs()); + // FIXME: Ordering here? while (AdjustedTypeLoc TL = CurrTL.getAs<AdjustedTypeLoc>()) CurrTL = TL.getNextTypeLoc().getUnqualifiedLoc(); @@ -5848,7 +6182,7 @@ GetTypeSourceInfoForDeclarator(TypeProcessingState &State, assert(TL.getFullDataSize() == CurrTL.getFullDataSize()); memcpy(CurrTL.getOpaqueData(), TL.getOpaqueData(), TL.getFullDataSize()); } else { - TypeSpecLocFiller(S.Context, State, D.getDeclSpec()).Visit(CurrTL); + TypeSpecLocFiller(S, S.Context, State, D.getDeclSpec()).Visit(CurrTL); } return TInfo; @@ -6349,6 +6683,7 @@ namespace { Desugar, Attributed, Parens, + Array, Pointer, BlockPointer, Reference, @@ -6369,6 +6704,10 @@ namespace { } else if (isa<ParenType>(Ty)) { T = cast<ParenType>(Ty)->getInnerType(); Stack.push_back(Parens); + } else if (isa<ConstantArrayType>(Ty) || isa<VariableArrayType>(Ty) || + isa<IncompleteArrayType>(Ty)) { + T = cast<ArrayType>(Ty)->getElementType(); + Stack.push_back(Array); } else if (isa<PointerType>(Ty)) { T = cast<PointerType>(Ty)->getPointeeType(); Stack.push_back(Pointer); @@ -6446,6 +6785,27 @@ namespace { case MacroQualified: return wrap(C, cast<MacroQualifiedType>(Old)->getUnderlyingType(), I); + case Array: { + if (const auto *CAT = dyn_cast<ConstantArrayType>(Old)) { + QualType New = wrap(C, CAT->getElementType(), I); + return C.getConstantArrayType(New, CAT->getSize(), CAT->getSizeExpr(), + CAT->getSizeModifier(), + CAT->getIndexTypeCVRQualifiers()); + } + + if (const auto *VAT = dyn_cast<VariableArrayType>(Old)) { + QualType New = wrap(C, VAT->getElementType(), I); + return C.getVariableArrayType( + New, VAT->getSizeExpr(), VAT->getSizeModifier(), + VAT->getIndexTypeCVRQualifiers(), VAT->getBracketsRange()); + } + + const auto *IAT = cast<IncompleteArrayType>(Old); + QualType New = wrap(C, IAT->getElementType(), I); + return C.getIncompleteArrayType(New, IAT->getSizeModifier(), + IAT->getIndexTypeCVRQualifiers()); + } + case Pointer: { QualType New = wrap(C, cast<PointerType>(Old)->getPointeeType(), I); return C.getPointerType(New); @@ -6673,15 +7033,15 @@ static bool checkNullabilityTypeSpecifier(TypeProcessingState &state, // attributes, require that the type be a single-level pointer. if (isContextSensitive) { // Make sure that the pointee isn't itself a pointer type. - const Type *pointeeType; + const Type *pointeeType = nullptr; if (desugared->isArrayType()) pointeeType = desugared->getArrayElementTypeNoTypeQual(); - else + else if (desugared->isAnyPointerType()) pointeeType = desugared->getPointeeType().getTypePtr(); - if (pointeeType->isAnyPointerType() || - pointeeType->isObjCObjectPointerType() || - pointeeType->isMemberPointerType()) { + if (pointeeType && (pointeeType->isAnyPointerType() || + pointeeType->isObjCObjectPointerType() || + pointeeType->isMemberPointerType())) { S.Diag(nullabilityLoc, diag::err_nullability_cs_multilevel) << DiagNullabilityKind(nullability, true) << type; @@ -6914,6 +7274,25 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, return true; } + if (attr.getKind() == ParsedAttr::AT_CmseNSCall) { + // Delay if this is not a function type. + if (!unwrapped.isFunctionType()) + return false; + + // Ignore if we don't have CMSE enabled. + if (!S.getLangOpts().Cmse) { + S.Diag(attr.getLoc(), diag::warn_attribute_ignored) << attr; + attr.setInvalid(); + return true; + } + + // Otherwise we can process right away. + FunctionType::ExtInfo EI = + unwrapped.get()->getExtInfo().withCmseNSCall(true); + type = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + return true; + } + // ns_returns_retained is not always a type attribute, but if we got // here, we're treating it as one right now. if (attr.getKind() == ParsedAttr::AT_NSReturnsRetained) { @@ -7273,15 +7652,16 @@ static bool isPermittedNeonBaseType(QualType &Ty, Triple.getArch() == llvm::Triple::aarch64_be; if (VecKind == VectorType::NeonPolyVector) { if (IsPolyUnsigned) { - // AArch64 polynomial vectors are unsigned and support poly64. + // AArch64 polynomial vectors are unsigned. return BTy->getKind() == BuiltinType::UChar || BTy->getKind() == BuiltinType::UShort || BTy->getKind() == BuiltinType::ULong || BTy->getKind() == BuiltinType::ULongLong; } else { - // AArch32 polynomial vector are signed. + // AArch32 polynomial vectors are signed. return BTy->getKind() == BuiltinType::SChar || - BTy->getKind() == BuiltinType::Short; + BTy->getKind() == BuiltinType::Short || + BTy->getKind() == BuiltinType::LongLong; } } @@ -7302,7 +7682,8 @@ static bool isPermittedNeonBaseType(QualType &Ty, BTy->getKind() == BuiltinType::LongLong || BTy->getKind() == BuiltinType::ULongLong || BTy->getKind() == BuiltinType::Float || - BTy->getKind() == BuiltinType::Half; + BTy->getKind() == BuiltinType::Half || + BTy->getKind() == BuiltinType::BFloat16; } /// HandleNeonVectorTypeAttr - The "neon_vector_type" and @@ -7360,6 +7741,23 @@ static void HandleNeonVectorTypeAttr(QualType &CurType, const ParsedAttr &Attr, CurType = S.Context.getVectorType(CurType, numElts, VecKind); } +static void HandleArmMveStrictPolymorphismAttr(TypeProcessingState &State, + QualType &CurType, + ParsedAttr &Attr) { + const VectorType *VT = dyn_cast<VectorType>(CurType); + if (!VT || VT->getVectorKind() != VectorType::NeonVector) { + State.getSema().Diag(Attr.getLoc(), + diag::err_attribute_arm_mve_polymorphism); + Attr.setInvalid(); + return; + } + + CurType = + State.getAttributedType(createSimpleAttr<ArmMveStrictPolymorphismAttr>( + State.getSema().Context, Attr), + CurType, CurType); +} + /// Handle OpenCL Access Qualifier Attribute. static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, Sema &S) { @@ -7416,6 +7814,68 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const ParsedAttr &Attr, } } +/// HandleMatrixTypeAttr - "matrix_type" attribute, like ext_vector_type +static void HandleMatrixTypeAttr(QualType &CurType, const ParsedAttr &Attr, + Sema &S) { + if (!S.getLangOpts().MatrixTypes) { + S.Diag(Attr.getLoc(), diag::err_builtin_matrix_disabled); + return; + } + + if (Attr.getNumArgs() != 2) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_number_arguments) + << Attr << 2; + return; + } + + Expr *RowsExpr = nullptr; + Expr *ColsExpr = nullptr; + + // TODO: Refactor parameter extraction into separate function + // Get the number of rows + if (Attr.isArgIdent(0)) { + CXXScopeSpec SS; + SourceLocation TemplateKeywordLoc; + UnqualifiedId id; + id.setIdentifier(Attr.getArgAsIdent(0)->Ident, Attr.getLoc()); + ExprResult Rows = S.ActOnIdExpression(S.getCurScope(), SS, + TemplateKeywordLoc, id, false, false); + + if (Rows.isInvalid()) + // TODO: maybe a good error message would be nice here + return; + RowsExpr = Rows.get(); + } else { + assert(Attr.isArgExpr(0) && + "Argument to should either be an identity or expression"); + RowsExpr = Attr.getArgAsExpr(0); + } + + // Get the number of columns + if (Attr.isArgIdent(1)) { + CXXScopeSpec SS; + SourceLocation TemplateKeywordLoc; + UnqualifiedId id; + id.setIdentifier(Attr.getArgAsIdent(1)->Ident, Attr.getLoc()); + ExprResult Columns = S.ActOnIdExpression( + S.getCurScope(), SS, TemplateKeywordLoc, id, false, false); + + if (Columns.isInvalid()) + // TODO: a good error message would be nice here + return; + RowsExpr = Columns.get(); + } else { + assert(Attr.isArgExpr(1) && + "Argument to should either be an identity or expression"); + ColsExpr = Attr.getArgAsExpr(1); + } + + // Create the matrix type. + QualType T = S.BuildMatrixType(CurType, RowsExpr, ColsExpr, Attr.getLoc()); + if (!T.isNull()) + CurType = T; +} + static void HandleLifetimeBoundAttr(TypeProcessingState &State, QualType &CurType, ParsedAttr &Attr) { @@ -7544,6 +8004,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, VectorType::NeonPolyVector); attr.setUsedAsTypeAttr(); break; + case ParsedAttr::AT_ArmMveStrictPolymorphism: { + HandleArmMveStrictPolymorphismAttr(state, type, attr); + attr.setUsedAsTypeAttr(); + break; + } case ParsedAttr::AT_OpenCLAccess: HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); @@ -7562,6 +8027,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, break; } + case ParsedAttr::AT_MatrixType: + HandleMatrixTypeAttr(type, attr, state.getSema()); + attr.setUsedAsTypeAttr(); + break; + MS_TYPE_ATTRS_CASELIST: if (!handleMSPointerTypeQualifierAttr(state, attr, type)) attr.setUsedAsTypeAttr(); @@ -7638,6 +8108,15 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case ParsedAttr::AT_AcquireHandle: { if (!type->isFunctionType()) return; + + if (attr.getNumArgs() != 1) { + state.getSema().Diag(attr.getLoc(), + diag::err_attribute_wrong_number_arguments) + << attr << 1; + attr.setInvalid(); + return; + } + StringRef HandleType; if (!state.getSema().checkStringLiteralArgumentAttr(attr, 0, HandleType)) return; @@ -7722,12 +8201,14 @@ void Sema::completeExprArrayBound(Expr *E) { /// case of a reference type, the referred-to type). /// /// \param E The expression whose type is required to be complete. +/// \param Kind Selects which completeness rules should be applied. /// \param Diagnoser The object that will emit a diagnostic if the type is /// incomplete. /// /// \returns \c true if the type of \p E is incomplete and diagnosed, \c false /// otherwise. -bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) { +bool Sema::RequireCompleteExprType(Expr *E, CompleteTypeKind Kind, + TypeDiagnoser &Diagnoser) { QualType T = E->getType(); // Incomplete array types may be completed by the initializer attached to @@ -7742,12 +8223,12 @@ bool Sema::RequireCompleteExprType(Expr *E, TypeDiagnoser &Diagnoser) { // FIXME: Are there other cases which require instantiating something other // than the type to complete the type of an expression? - return RequireCompleteType(E->getExprLoc(), T, Diagnoser); + return RequireCompleteType(E->getExprLoc(), T, Kind, Diagnoser); } bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) { BoundTypeDiagnoser<> Diagnoser(DiagID); - return RequireCompleteExprType(E, Diagnoser); + return RequireCompleteExprType(E, CompleteTypeKind::Default, Diagnoser); } /// Ensure that the type T is a complete type. @@ -7765,11 +8246,14 @@ bool Sema::RequireCompleteExprType(Expr *E, unsigned DiagID) { /// /// @param T The type that this routine is examining for completeness. /// +/// @param Kind Selects which completeness rules should be applied. +/// /// @returns @c true if @p T is incomplete and a diagnostic was emitted, /// @c false otherwise. bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, TypeDiagnoser &Diagnoser) { - if (RequireCompleteTypeImpl(Loc, T, &Diagnoser)) + if (RequireCompleteTypeImpl(Loc, T, Kind, &Diagnoser)) return true; if (const TagType *Tag = T->getAs<TagType>()) { if (!Tag->getDecl()->isCompleteDefinitionRequired()) { @@ -7823,10 +8307,12 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, } else if (auto *ED = dyn_cast<EnumDecl>(D)) { if (auto *Pattern = ED->getTemplateInstantiationPattern()) ED = Pattern; - if (OnlyNeedComplete && ED->isFixed()) { - // If the enum has a fixed underlying type, and we're only looking for a - // complete type (not a definition), any visible declaration of it will - // do. + if (OnlyNeedComplete && (ED->isFixed() || getLangOpts().MSVCCompat)) { + // If the enum has a fixed underlying type, it may have been forward + // declared. In -fms-compatibility, `enum Foo;` will also forward declare + // the enum and assign it the underlying type of `int`. Since we're only + // looking for a complete type (not a definition), any visible declaration + // of it will do. *Suggested = nullptr; for (auto *Redecl : ED->redecls()) { if (isVisible(Redecl)) @@ -7918,6 +8404,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { /// The implementation of RequireCompleteType bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, + CompleteTypeKind Kind, TypeDiagnoser *Diagnoser) { // FIXME: Add this assertion to make sure we always get instantiation points. // assert(!Loc.isInvalid() && "Invalid location in RequireCompleteType"); @@ -7931,7 +8418,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, if (!MPTy->getClass()->isDependentType()) { if (getLangOpts().CompleteMemberPointers && !MPTy->getClass()->getAsCXXRecordDecl()->isBeingDefined() && - RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), + RequireCompleteType(Loc, QualType(MPTy->getClass(), 0), Kind, diag::err_memptr_incomplete)) return true; @@ -7945,7 +8432,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } NamedDecl *Def = nullptr; - bool Incomplete = T->isIncompleteType(&Def); + bool AcceptSizeless = (Kind == CompleteTypeKind::AcceptSizeless); + bool Incomplete = (T->isIncompleteType(&Def) || + (!AcceptSizeless && T->isSizelessBuiltinType())); // Check that any necessary explicit specializations are visible. For an // enum, we just need the declaration, so don't check this. @@ -7999,7 +8488,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If the external source completed the type, go through the motions // again to ensure we're allowed to use the completed type. if (!T->isIncompleteType()) - return RequireCompleteTypeImpl(Loc, T, Diagnoser); + return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser); } } @@ -8051,7 +8540,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // instantiation produced an error, so that repeated calls to this // function give consistent answers. if (!T->isIncompleteType()) - return RequireCompleteTypeImpl(Loc, T, Diagnoser); + return RequireCompleteTypeImpl(Loc, T, Kind, Diagnoser); } } @@ -8065,14 +8554,14 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // If the type was a forward declaration of a class/struct/union // type, produce a note. - if (Tag && !Tag->isInvalidDecl()) + if (Tag && !Tag->isInvalidDecl() && !Tag->getLocation().isInvalid()) Diag(Tag->getLocation(), Tag->isBeingDefined() ? diag::note_type_being_defined : diag::note_forward_declaration) << Context.getTagDeclType(Tag); // If the Objective-C class was a forward declaration, produce a note. - if (IFace && !IFace->isInvalidDecl()) + if (IFace && !IFace->isInvalidDecl() && !IFace->getLocation().isInvalid()) Diag(IFace->getLocation(), diag::note_forward_class); // If we have external information that we can use to suggest a fix, @@ -8084,9 +8573,9 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } bool Sema::RequireCompleteType(SourceLocation Loc, QualType T, - unsigned DiagID) { + CompleteTypeKind Kind, unsigned DiagID) { BoundTypeDiagnoser<> Diagnoser(DiagID); - return RequireCompleteType(Loc, T, Diagnoser); + return RequireCompleteType(Loc, T, Kind, Diagnoser); } /// Get diagnostic %select index for tag kind for @@ -8184,7 +8673,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, return true; } } - } else if (getLangOpts().CPlusPlus2a ? !RD->hasConstexprDestructor() + } else if (getLangOpts().CPlusPlus20 ? !RD->hasConstexprDestructor() : !RD->hasTrivialDestructor()) { // All fields and bases are of literal types, so have trivial or constexpr // destructors. If this class's destructor is non-trivial / non-constexpr, @@ -8194,7 +8683,7 @@ bool Sema::RequireLiteralType(SourceLocation Loc, QualType T, if (!Dtor) return true; - if (getLangOpts().CPlusPlus2a) { + if (getLangOpts().CPlusPlus20) { Diag(Dtor->getLocation(), diag::note_non_literal_non_constexpr_dtor) << RD; } else { @@ -8386,9 +8875,17 @@ QualType Sema::BuildAtomicType(QualType T, SourceLocation Loc) { DisallowedKind = 4; else if (T.hasQualifiers()) DisallowedKind = 5; + else if (T->isSizelessType()) + DisallowedKind = 6; else if (!T.isTriviallyCopyableType(Context)) // Some other non-trivially-copyable type (probably a C++ class) - DisallowedKind = 6; + DisallowedKind = 7; + else if (auto *ExtTy = T->getAs<ExtIntType>()) { + if (ExtTy->getNumBits() < 8) + DisallowedKind = 8; + else if (!llvm::isPowerOf2_32(ExtTy->getNumBits())) + DisallowedKind = 9; + } if (DisallowedKind != -1) { Diag(Loc, diag::err_atomic_specifier_bad_type) << DisallowedKind << T; diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 3b827fbc950b..ae0e9f1119b4 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -19,6 +19,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" +#include "clang/AST/ExprConcepts.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/ExprObjC.h" #include "clang/AST/ExprOpenMP.h" @@ -27,6 +28,7 @@ #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtObjC.h" #include "clang/AST/StmtOpenMP.h" +#include "clang/Basic/OpenMPKinds.h" #include "clang/Sema/Designator.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Ownership.h" @@ -156,6 +158,13 @@ public: /// existing lambdas. bool ReplacingOriginal() { return false; } + /// Wether CXXConstructExpr can be skipped when they are implicit. + /// They will be reconstructed when used if needed. + /// This is usefull when the user that cause rebuilding of the + /// CXXConstructExpr is outside of the expression at which the TreeTransform + /// started. + bool AllowSkippingCXXConstructExpr() { return true; } + /// Returns the location of the entity being transformed, if that /// information was not available elsewhere in the AST. /// @@ -211,6 +220,14 @@ public: return T.isNull(); } + /// Transform a template parameter depth level. + /// + /// During a transformation that transforms template parameters, this maps + /// an old template parameter depth to a new depth. + unsigned TransformTemplateDepth(unsigned Depth) { + return Depth; + } + /// Determine whether the given call argument should be dropped, e.g., /// because it is a default argument. /// @@ -509,6 +526,15 @@ public: DeclarationNameInfo TransformDeclarationNameInfo(const DeclarationNameInfo &NameInfo); + bool TransformRequiresExprRequirements(ArrayRef<concepts::Requirement *> Reqs, + llvm::SmallVectorImpl<concepts::Requirement *> &Transformed); + concepts::TypeRequirement * + TransformTypeRequirement(concepts::TypeRequirement *Req); + concepts::ExprRequirement * + TransformExprRequirement(concepts::ExprRequirement *Req); + concepts::NestedRequirement * + TransformNestedRequirement(concepts::NestedRequirement *Req); + /// Transform the given template name. /// /// \param SS The nested-name-specifier that qualifies the template @@ -704,10 +730,10 @@ public: #define ABSTRACT_STMT(Stmt) #include "clang/AST/StmtNodes.inc" -#define OPENMP_CLAUSE(Name, Class) \ +#define OMP_CLAUSE_CLASS(Enum, Str, Class) \ LLVM_ATTRIBUTE_NOINLINE \ OMPClause *Transform ## Class(Class *S); -#include "clang/Basic/OpenMPKinds.def" +#include "llvm/Frontend/OpenMP/OMPKinds.def" /// Build a new qualified type given its unqualified type and type location. /// @@ -868,6 +894,16 @@ public: Expr *SizeExpr, SourceLocation AttributeLoc); + /// Build a new matrix type given the element type and dimensions. + QualType RebuildConstantMatrixType(QualType ElementType, unsigned NumRows, + unsigned NumColumns); + + /// Build a new matrix type given the type and dependently-defined + /// dimensions. + QualType RebuildDependentSizedMatrixType(QualType ElementType, Expr *RowExpr, + Expr *ColumnExpr, + SourceLocation AttributeLoc); + /// Build a new DependentAddressSpaceType or return the pointee /// type variable with the correct address space (retrieved from /// AddrSpaceExpr) applied to it. The former will be returned in cases @@ -941,12 +977,16 @@ public: /// Build a new C++11 auto type. /// /// By default, builds a new AutoType with the given deduced type. - QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword) { + QualType RebuildAutoType(QualType Deduced, AutoTypeKeyword Keyword, + ConceptDecl *TypeConstraintConcept, + ArrayRef<TemplateArgument> TypeConstraintArgs) { // Note, IsDependent is always false here: we implicitly convert an 'auto' // which has been deduced to a dependent type into an undeduced 'auto', so // that we'll retry deduction after the transformation. return SemaRef.Context.getAutoType(Deduced, Keyword, - /*IsDependent*/ false); + /*IsDependent*/ false, /*IsPack=*/false, + TypeConstraintConcept, + TypeConstraintArgs); } /// By default, builds a new DeducedTemplateSpecializationType with the given @@ -1056,23 +1096,8 @@ public: } if (Keyword == ETK_None || Keyword == ETK_Typename) { - QualType T = SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, - *Id, IdLoc); - // If a dependent name resolves to a deduced template specialization type, - // check that we're in one of the syntactic contexts permitting it. - if (!DeducedTSTContext) { - if (auto *Deduced = dyn_cast_or_null<DeducedTemplateSpecializationType>( - T.isNull() ? nullptr : T->getContainedDeducedType())) { - SemaRef.Diag(IdLoc, diag::err_dependent_deduced_tst) - << (int)SemaRef.getTemplateNameKindForDiagnostics( - Deduced->getTemplateName()) - << QualType(QualifierLoc.getNestedNameSpecifier()->getAsType(), 0); - if (auto *TD = Deduced->getTemplateName().getAsTemplateDecl()) - SemaRef.Diag(TD->getLocation(), diag::note_template_decl_here); - return QualType(); - } - } - return T; + return SemaRef.CheckTypenameType(Keyword, KeywordLoc, QualifierLoc, + *Id, IdLoc, DeducedTSTContext); } TagTypeKind Kind = TypeWithKeyword::getTagTypeKindForKeyword(Keyword); @@ -1168,6 +1193,14 @@ public: QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc, bool isReadPipe); + /// Build an extended int given its value type. + QualType RebuildExtIntType(bool IsUnsigned, unsigned NumBits, + SourceLocation Loc); + + /// Build a dependent extended int given its value type. + QualType RebuildDependentExtIntType(bool IsUnsigned, Expr *NumBitsExpr, + SourceLocation Loc); + /// Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template /// that the template name refers to. @@ -1314,9 +1347,10 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildWhileStmt(SourceLocation WhileLoc, - Sema::ConditionResult Cond, Stmt *Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, Body); + StmtResult RebuildWhileStmt(SourceLocation WhileLoc, SourceLocation LParenLoc, + Sema::ConditionResult Cond, + SourceLocation RParenLoc, Stmt *Body) { + return getSema().ActOnWhileStmt(WhileLoc, LParenLoc, Cond, RParenLoc, Body); } /// Build a new do-while statement. @@ -1603,8 +1637,7 @@ public: /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPDefaultClause(OpenMPDefaultClauseKind Kind, - SourceLocation KindKwLoc, + OMPClause *RebuildOMPDefaultClause(DefaultKind Kind, SourceLocation KindKwLoc, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -1704,17 +1737,16 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPReductionClause(ArrayRef<Expr *> VarList, - SourceLocation StartLoc, - SourceLocation LParenLoc, - SourceLocation ColonLoc, - SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId, - ArrayRef<Expr *> UnresolvedReductions) { + OMPClause *RebuildOMPReductionClause( + ArrayRef<Expr *> VarList, OpenMPReductionClauseModifier Modifier, + SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation ColonLoc, + SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { return getSema().ActOnOpenMPReductionClause( - VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, - ReductionId, UnresolvedReductions); + VarList, Modifier, StartLoc, LParenLoc, ModifierLoc, ColonLoc, EndLoc, + ReductionIdScopeSpec, ReductionId, UnresolvedReductions); } /// Build a new OpenMP 'task_reduction' clause. @@ -1813,28 +1845,42 @@ public: EndLoc); } + /// Build a new OpenMP 'depobj' pseudo clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDepobjClause(Expr *Depobj, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDepobjClause(Depobj, StartLoc, LParenLoc, + EndLoc); + } + /// Build a new OpenMP 'depend' pseudo clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. OMPClause * - RebuildOMPDependClause(OpenMPDependClauseKind DepKind, SourceLocation DepLoc, - SourceLocation ColonLoc, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPDependClause(DepKind, DepLoc, ColonLoc, VarList, - StartLoc, LParenLoc, EndLoc); + RebuildOMPDependClause(Expr *DepModifier, OpenMPDependClauseKind DepKind, + SourceLocation DepLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDependClause(DepModifier, DepKind, DepLoc, + ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); } /// Build a new OpenMP 'device' clause. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPDeviceClause(Expr *Device, SourceLocation StartLoc, + OMPClause *RebuildOMPDeviceClause(OpenMPDeviceClauseModifier Modifier, + Expr *Device, SourceLocation StartLoc, SourceLocation LParenLoc, + SourceLocation ModifierLoc, SourceLocation EndLoc) { - return getSema().ActOnOpenMPDeviceClause(Device, StartLoc, LParenLoc, - EndLoc); + return getSema().ActOnOpenMPDeviceClause(Modifier, Device, StartLoc, + LParenLoc, ModifierLoc, EndLoc); } /// Build a new OpenMP 'map' clause. @@ -1933,6 +1979,16 @@ public: return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc); } + /// Build a new OpenMP 'detach' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPDetachClause(Expr *Evt, SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPDetachClause(Evt, StartLoc, LParenLoc, EndLoc); + } + /// Build a new OpenMP 'dist_schedule' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -1981,6 +2037,15 @@ public: return getSema().ActOnOpenMPUseDevicePtrClause(VarList, Locs); } + /// Build a new OpenMP 'use_device_addr' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUseDeviceAddrClause(ArrayRef<Expr *> VarList, + const OMPVarListLocTy &Locs) { + return getSema().ActOnOpenMPUseDeviceAddrClause(VarList, Locs); + } + /// Build a new OpenMP 'is_device_ptr' clause. /// /// By default, performs semantic analysis to build the new OpenMP clause. @@ -2017,6 +2082,67 @@ public: EndLoc); } + /// Build a new OpenMP 'inclusive' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPInclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPInclusiveClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'exclusive' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPExclusiveClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPExclusiveClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'uses_allocators' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUsesAllocatorsClause( + ArrayRef<Sema::UsesAllocatorsData> Data, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPUsesAllocatorClause(StartLoc, LParenLoc, EndLoc, + Data); + } + + /// Build a new OpenMP 'affinity' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPAffinityClause(SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation ColonLoc, + SourceLocation EndLoc, Expr *Modifier, + ArrayRef<Expr *> Locators) { + return getSema().ActOnOpenMPAffinityClause(StartLoc, LParenLoc, ColonLoc, + EndLoc, Modifier, Locators); + } + + /// Build a new OpenMP 'order' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPOrderClause(OpenMPOrderClauseKind Kind, + SourceLocation KindKwLoc, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPOrderClause(Kind, KindKwLoc, StartLoc, + LParenLoc, EndLoc); + } + /// Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -2294,16 +2420,53 @@ public: RBracketLoc); } + /// Build a new matrix subscript expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildMatrixSubscriptExpr(Expr *Base, Expr *RowIdx, + Expr *ColumnIdx, + SourceLocation RBracketLoc) { + return getSema().CreateBuiltinMatrixSubscriptExpr(Base, RowIdx, ColumnIdx, + RBracketLoc); + } + /// Build a new array section expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. ExprResult RebuildOMPArraySectionExpr(Expr *Base, SourceLocation LBracketLoc, Expr *LowerBound, - SourceLocation ColonLoc, Expr *Length, + SourceLocation ColonLocFirst, + SourceLocation ColonLocSecond, + Expr *Length, Expr *Stride, SourceLocation RBracketLoc) { return getSema().ActOnOMPArraySectionExpr(Base, LBracketLoc, LowerBound, - ColonLoc, Length, RBracketLoc); + ColonLocFirst, ColonLocSecond, + Length, Stride, RBracketLoc); + } + + /// Build a new array shaping expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildOMPArrayShapingExpr(Expr *Base, SourceLocation LParenLoc, + SourceLocation RParenLoc, + ArrayRef<Expr *> Dims, + ArrayRef<SourceRange> BracketsRanges) { + return getSema().ActOnOMPArrayShapingExpr(Base, LParenLoc, RParenLoc, Dims, + BracketsRanges); + } + + /// Build a new iterator expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildOMPIteratorExpr( + SourceLocation IteratorKwLoc, SourceLocation LLoc, SourceLocation RLoc, + ArrayRef<Sema::OMPIteratorData> Data) { + return getSema().ActOnOMPIteratorExpr(/*Scope=*/nullptr, IteratorKwLoc, + LLoc, RLoc, Data); } /// Build a new call expression. @@ -2314,8 +2477,8 @@ public: MultiExprArg Args, SourceLocation RParenLoc, Expr *ExecConfig = nullptr) { - return getSema().BuildCallExpr(/*Scope=*/nullptr, Callee, LParenLoc, Args, - RParenLoc, ExecConfig); + return getSema().ActOnCallExpr( + /*Scope=*/nullptr, Callee, LParenLoc, Args, RParenLoc, ExecConfig); } /// Build a new member access expression. @@ -2527,10 +2690,10 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildStmtExpr(SourceLocation LParenLoc, - Stmt *SubStmt, - SourceLocation RParenLoc) { - return getSema().ActOnStmtExpr(LParenLoc, SubStmt, RParenLoc); + ExprResult RebuildStmtExpr(SourceLocation LParenLoc, Stmt *SubStmt, + SourceLocation RParenLoc, unsigned TemplateDepth) { + return getSema().BuildStmtExpr(LParenLoc, SubStmt, RParenLoc, + TemplateDepth); } /// Build a new __builtin_choose_expr expression. @@ -2609,6 +2772,10 @@ public: RAngleLoc, LParenLoc, SubExpr, RParenLoc); + case Stmt::CXXAddrspaceCastExprClass: + return getDerived().RebuildCXXAddrspaceCastExpr( + OpLoc, LAngleLoc, TInfo, RAngleLoc, LParenLoc, SubExpr, RParenLoc); + default: llvm_unreachable("Invalid C++ named cast"); } @@ -2682,6 +2849,16 @@ public: SourceRange(LParenLoc, RParenLoc)); } + ExprResult + RebuildCXXAddrspaceCastExpr(SourceLocation OpLoc, SourceLocation LAngleLoc, + TypeSourceInfo *TInfo, SourceLocation RAngleLoc, + SourceLocation LParenLoc, Expr *SubExpr, + SourceLocation RParenLoc) { + return getSema().BuildCXXNamedCast( + OpLoc, tok::kw_addrspace_cast, TInfo, SubExpr, + SourceRange(LAngleLoc, RAngleLoc), SourceRange(LParenLoc, RParenLoc)); + } + /// Build a new C++ functional-style cast expression. /// /// By default, performs semantic analysis to build the new expression. @@ -2735,24 +2912,19 @@ public: /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, - SourceLocation TypeidLoc, - TypeSourceInfo *Operand, - SourceLocation RParenLoc) { - return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, - RParenLoc); + ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc, + TypeSourceInfo *Operand, + SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ __uuidof(expr) expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. - ExprResult RebuildCXXUuidofExpr(QualType TypeInfoType, - SourceLocation TypeidLoc, - Expr *Operand, - SourceLocation RParenLoc) { - return getSema().BuildCXXUuidof(TypeInfoType, TypeidLoc, Operand, - RParenLoc); + ExprResult RebuildCXXUuidofExpr(QualType Type, SourceLocation TypeidLoc, + Expr *Operand, SourceLocation RParenLoc) { + return getSema().BuildCXXUuidof(Type, TypeidLoc, Operand, RParenLoc); } /// Build a new C++ "this" expression. @@ -2931,9 +3103,14 @@ public: bool RequiresZeroInit, CXXConstructExpr::ConstructionKind ConstructKind, SourceRange ParenRange) { + // Reconstruct the constructor we originally found, which might be + // different if this is a call to an inherited constructor. + CXXConstructorDecl *FoundCtor = Constructor; + if (Constructor->isInheritingConstructor()) + FoundCtor = Constructor->getInheritedConstructor().getConstructor(); + SmallVector<Expr*, 8> ConvertedArgs; - if (getSema().CompleteConstructorCall(Constructor, Args, Loc, - ConvertedArgs)) + if (getSema().CompleteConstructorCall(FoundCtor, Args, Loc, ConvertedArgs)) return ExprError(); return getSema().BuildCXXConstructExpr(Loc, T, Constructor, @@ -3078,7 +3255,56 @@ public: return Result; } - /// \brief Build a new Objective-C boxed expression. + /// \brief Build a new requires expression. + /// + /// By default, performs semantic analysis to build the new expression. + /// Subclasses may override this routine to provide different behavior. + ExprResult RebuildRequiresExpr(SourceLocation RequiresKWLoc, + RequiresExprBodyDecl *Body, + ArrayRef<ParmVarDecl *> LocalParameters, + ArrayRef<concepts::Requirement *> Requirements, + SourceLocation ClosingBraceLoc) { + return RequiresExpr::Create(SemaRef.Context, RequiresKWLoc, Body, + LocalParameters, Requirements, ClosingBraceLoc); + } + + concepts::TypeRequirement * + RebuildTypeRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return SemaRef.BuildTypeRequirement(SubstDiag); + } + + concepts::TypeRequirement *RebuildTypeRequirement(TypeSourceInfo *T) { + return SemaRef.BuildTypeRequirement(T); + } + + concepts::ExprRequirement * + RebuildExprRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag, bool IsSimple, + SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement Ret) { + return SemaRef.BuildExprRequirement(SubstDiag, IsSimple, NoexceptLoc, + std::move(Ret)); + } + + concepts::ExprRequirement * + RebuildExprRequirement(Expr *E, bool IsSimple, SourceLocation NoexceptLoc, + concepts::ExprRequirement::ReturnTypeRequirement Ret) { + return SemaRef.BuildExprRequirement(E, IsSimple, NoexceptLoc, + std::move(Ret)); + } + + concepts::NestedRequirement * + RebuildNestedRequirement( + concepts::Requirement::SubstitutionDiagnostic *SubstDiag) { + return SemaRef.BuildNestedRequirement(SubstDiag); + } + + concepts::NestedRequirement *RebuildNestedRequirement(Expr *Constraint) { + return SemaRef.BuildNestedRequirement(Constraint); + } + + /// \brief Build a new Objective-C boxed expression. /// /// By default, performs semantic analysis to build the new expression. /// Subclasses may override this routine to provide different behavior. @@ -3382,6 +3608,11 @@ public: Sema::AtomicArgumentOrder::AST); } + ExprResult RebuildRecoveryExpr(SourceLocation BeginLoc, SourceLocation EndLoc, + ArrayRef<Expr *> SubExprs) { + return getSema().CreateRecoveryExpr(BeginLoc, EndLoc, SubExprs); + } + private: TypeLoc TransformTypeInObjectScope(TypeLoc TL, QualType ObjectType, @@ -3446,10 +3677,10 @@ OMPClause *TreeTransform<Derived>::TransformOMPClause(OMPClause *S) { switch (S->getClauseKind()) { default: break; // Transform individual clause nodes -#define OPENMP_CLAUSE(Name, Class) \ - case OMPC_ ## Name : \ +#define OMP_CLAUSE_CLASS(Enum, Str, Class) \ + case Enum: \ return getDerived().Transform ## Class(cast<Class>(S)); -#include "clang/Basic/OpenMPKinds.def" +#include "llvm/Frontend/OpenMP/OMPKinds.def" } return S; @@ -3966,50 +4197,8 @@ template<typename Derived> void TreeTransform<Derived>::InventTemplateArgumentLoc( const TemplateArgument &Arg, TemplateArgumentLoc &Output) { - SourceLocation Loc = getDerived().getBaseLocation(); - switch (Arg.getKind()) { - case TemplateArgument::Null: - llvm_unreachable("null template argument in TreeTransform"); - break; - - case TemplateArgument::Type: - Output = TemplateArgumentLoc(Arg, - SemaRef.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); - - break; - - case TemplateArgument::Template: - case TemplateArgument::TemplateExpansion: { - NestedNameSpecifierLocBuilder Builder; - TemplateName Template = Arg.getAsTemplateOrTemplatePattern(); - if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) - Builder.MakeTrivial(SemaRef.Context, DTN->getQualifier(), Loc); - else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Builder.MakeTrivial(SemaRef.Context, QTN->getQualifier(), Loc); - - if (Arg.getKind() == TemplateArgument::Template) - Output = TemplateArgumentLoc(Arg, - Builder.getWithLocInContext(SemaRef.Context), - Loc); - else - Output = TemplateArgumentLoc(Arg, - Builder.getWithLocInContext(SemaRef.Context), - Loc, Loc); - - break; - } - - case TemplateArgument::Expression: - Output = TemplateArgumentLoc(Arg, Arg.getAsExpr()); - break; - - case TemplateArgument::Declaration: - case TemplateArgument::Integral: - case TemplateArgument::Pack: - case TemplateArgument::NullPtr: - Output = TemplateArgumentLoc(Arg, TemplateArgumentLocInfo()); - break; - } + Output = getSema().getTrivialTemplateArgumentLoc( + Arg, QualType(), getDerived().getBaseLocation()); } template<typename Derived> @@ -4019,12 +4208,45 @@ bool TreeTransform<Derived>::TransformTemplateArgument( const TemplateArgument &Arg = Input.getArgument(); switch (Arg.getKind()) { case TemplateArgument::Null: - case TemplateArgument::Integral: case TemplateArgument::Pack: - case TemplateArgument::Declaration: - case TemplateArgument::NullPtr: llvm_unreachable("Unexpected TemplateArgument"); + case TemplateArgument::Integral: + case TemplateArgument::NullPtr: + case TemplateArgument::Declaration: { + // Transform a resolved template argument straight to a resolved template + // argument. We get here when substituting into an already-substituted + // template type argument during concept satisfaction checking. + QualType T = Arg.getNonTypeTemplateArgumentType(); + QualType NewT = getDerived().TransformType(T); + if (NewT.isNull()) + return true; + + ValueDecl *D = Arg.getKind() == TemplateArgument::Declaration + ? Arg.getAsDecl() + : nullptr; + ValueDecl *NewD = D ? cast_or_null<ValueDecl>(getDerived().TransformDecl( + getDerived().getBaseLocation(), D)) + : nullptr; + if (D && !NewD) + return true; + + if (NewT == T && D == NewD) + Output = Input; + else if (Arg.getKind() == TemplateArgument::Integral) + Output = TemplateArgumentLoc( + TemplateArgument(getSema().Context, Arg.getAsIntegral(), NewT), + TemplateArgumentLocInfo()); + else if (Arg.getKind() == TemplateArgument::NullPtr) + Output = TemplateArgumentLoc(TemplateArgument(NewT, /*IsNullPtr=*/true), + TemplateArgumentLocInfo()); + else + Output = TemplateArgumentLoc(TemplateArgument(NewD, NewT), + TemplateArgumentLocInfo()); + + return false; + } + case TemplateArgument::Type: { TypeSourceInfo *DI = Input.getTypeSourceInfo(); if (!DI) @@ -4456,7 +4678,10 @@ QualType TreeTransform<Derived>::RebuildQualifiedType(QualType T, Deduced = SemaRef.Context.getQualifiedType(Deduced.getUnqualifiedType(), Qs); T = SemaRef.Context.getAutoType(Deduced, AutoTy->getKeyword(), - AutoTy->isDependentType()); + AutoTy->isDependentType(), + /*isPack=*/false, + AutoTy->getTypeConstraintConcept(), + AutoTy->getTypeConstraintArguments()); } else { // Otherwise, complain about the addition of a qualifier to an // already-qualified type. @@ -5016,6 +5241,86 @@ QualType TreeTransform<Derived>::TransformDependentSizedExtVectorType( } template <typename Derived> +QualType +TreeTransform<Derived>::TransformConstantMatrixType(TypeLocBuilder &TLB, + ConstantMatrixTypeLoc TL) { + const ConstantMatrixType *T = TL.getTypePtr(); + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || ElementType != T->getElementType()) { + Result = getDerived().RebuildConstantMatrixType( + ElementType, T->getNumRows(), T->getNumColumns()); + if (Result.isNull()) + return QualType(); + } + + ConstantMatrixTypeLoc NewTL = TLB.push<ConstantMatrixTypeLoc>(Result); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrRowOperand(TL.getAttrRowOperand()); + NewTL.setAttrColumnOperand(TL.getAttrColumnOperand()); + + return Result; +} + +template <typename Derived> +QualType TreeTransform<Derived>::TransformDependentSizedMatrixType( + TypeLocBuilder &TLB, DependentSizedMatrixTypeLoc TL) { + const DependentSizedMatrixType *T = TL.getTypePtr(); + + QualType ElementType = getDerived().TransformType(T->getElementType()); + if (ElementType.isNull()) { + return QualType(); + } + + // Matrix dimensions are constant expressions. + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + + Expr *origRows = TL.getAttrRowOperand(); + if (!origRows) + origRows = T->getRowExpr(); + Expr *origColumns = TL.getAttrColumnOperand(); + if (!origColumns) + origColumns = T->getColumnExpr(); + + ExprResult rowResult = getDerived().TransformExpr(origRows); + rowResult = SemaRef.ActOnConstantExpression(rowResult); + if (rowResult.isInvalid()) + return QualType(); + + ExprResult columnResult = getDerived().TransformExpr(origColumns); + columnResult = SemaRef.ActOnConstantExpression(columnResult); + if (columnResult.isInvalid()) + return QualType(); + + Expr *rows = rowResult.get(); + Expr *columns = columnResult.get(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || ElementType != T->getElementType() || + rows != origRows || columns != origColumns) { + Result = getDerived().RebuildDependentSizedMatrixType( + ElementType, rows, columns, T->getAttributeLoc()); + + if (Result.isNull()) + return QualType(); + } + + // We might have any sort of matrix type now, but fortunately they + // all have the same location layout. + MatrixTypeLoc NewTL = TLB.push<MatrixTypeLoc>(Result); + NewTL.setAttrNameLoc(TL.getAttrNameLoc()); + NewTL.setAttrOperandParensRange(TL.getAttrOperandParensRange()); + NewTL.setAttrRowOperand(rows); + NewTL.setAttrColumnOperand(columns); + return Result; +} + +template <typename Derived> QualType TreeTransform<Derived>::TransformDependentAddressSpaceType( TypeLocBuilder &TLB, DependentAddressSpaceTypeLoc TL) { const DependentAddressSpaceType *T = TL.getTypePtr(); @@ -5189,21 +5494,29 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( PackExpansionTypeLoc ExpansionTL = TL.castAs<PackExpansionTypeLoc>(); TypeLoc Pattern = ExpansionTL.getPatternLoc(); SemaRef.collectUnexpandedParameterPacks(Pattern, Unexpanded); - assert(Unexpanded.size() > 0 && "Could not find parameter packs!"); // Determine whether we should expand the parameter packs. bool ShouldExpand = false; bool RetainExpansion = false; - Optional<unsigned> OrigNumExpansions = - ExpansionTL.getTypePtr()->getNumExpansions(); - NumExpansions = OrigNumExpansions; - if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), - Pattern.getSourceRange(), - Unexpanded, - ShouldExpand, - RetainExpansion, - NumExpansions)) { - return true; + Optional<unsigned> OrigNumExpansions; + if (Unexpanded.size() > 0) { + OrigNumExpansions = ExpansionTL.getTypePtr()->getNumExpansions(); + NumExpansions = OrigNumExpansions; + if (getDerived().TryExpandParameterPacks(ExpansionTL.getEllipsisLoc(), + Pattern.getSourceRange(), + Unexpanded, + ShouldExpand, + RetainExpansion, + NumExpansions)) { + return true; + } + } else { +#ifndef NDEBUG + const AutoType *AT = + Pattern.getType().getTypePtr()->getContainedAutoType(); + assert((AT && (!AT->isDeduced() || AT->getDeducedType().isNull())) && + "Could not find parameter packs or undeduced auto type!"); +#endif } if (ShouldExpand) { @@ -5263,6 +5576,9 @@ bool TreeTransform<Derived>::TransformFunctionTypeParams( indexAdjustment, NumExpansions, /*ExpectParameterPack=*/true); + assert(NewParm->isParameterPack() && + "Parameter pack no longer a parameter pack after " + "transformation."); } else { NewParm = getDerived().TransformFunctionTypeParam( OldParm, indexAdjustment, None, /*ExpectParameterPack=*/ false); @@ -5768,32 +6084,6 @@ QualType TreeTransform<Derived>::TransformUnaryTransformType( } template<typename Derived> -QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, - AutoTypeLoc TL) { - const AutoType *T = TL.getTypePtr(); - QualType OldDeduced = T->getDeducedType(); - QualType NewDeduced; - if (!OldDeduced.isNull()) { - NewDeduced = getDerived().TransformType(OldDeduced); - if (NewDeduced.isNull()) - return QualType(); - } - - QualType Result = TL.getType(); - if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || - T->isDependentType()) { - Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword()); - if (Result.isNull()) - return QualType(); - } - - AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); - NewTL.setNameLoc(TL.getNameLoc()); - - return Result; -} - -template<typename Derived> QualType TreeTransform<Derived>::TransformDeducedTemplateSpecializationType( TypeLocBuilder &TLB, DeducedTemplateSpecializationTypeLoc TL) { const DeducedTemplateSpecializationType *T = TL.getTypePtr(); @@ -5990,6 +6280,57 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB, return Result; } +template <typename Derived> +QualType TreeTransform<Derived>::TransformExtIntType(TypeLocBuilder &TLB, + ExtIntTypeLoc TL) { + const ExtIntType *EIT = TL.getTypePtr(); + QualType Result = TL.getType(); + + if (getDerived().AlwaysRebuild()) { + Result = getDerived().RebuildExtIntType(EIT->isUnsigned(), + EIT->getNumBits(), TL.getNameLoc()); + if (Result.isNull()) + return QualType(); + } + + ExtIntTypeLoc NewTL = TLB.push<ExtIntTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + return Result; +} + +template <typename Derived> +QualType TreeTransform<Derived>::TransformDependentExtIntType( + TypeLocBuilder &TLB, DependentExtIntTypeLoc TL) { + const DependentExtIntType *EIT = TL.getTypePtr(); + + EnterExpressionEvaluationContext Unevaluated( + SemaRef, Sema::ExpressionEvaluationContext::ConstantEvaluated); + ExprResult BitsExpr = getDerived().TransformExpr(EIT->getNumBitsExpr()); + BitsExpr = SemaRef.ActOnConstantExpression(BitsExpr); + + if (BitsExpr.isInvalid()) + return QualType(); + + QualType Result = TL.getType(); + + if (getDerived().AlwaysRebuild() || BitsExpr.get() != EIT->getNumBitsExpr()) { + Result = getDerived().RebuildDependentExtIntType( + EIT->isUnsigned(), BitsExpr.get(), TL.getNameLoc()); + + if (Result.isNull()) + return QualType(); + } + + if (isa<DependentExtIntType>(Result)) { + DependentExtIntTypeLoc NewTL = TLB.push<DependentExtIntTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } else { + ExtIntTypeLoc NewTL = TLB.push<ExtIntTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + } + return Result; +} + /// Simple iterator that traverses the template arguments in a /// container that provides a \c getArgLoc() member function. /// @@ -6054,6 +6395,71 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB, } }; +template<typename Derived> +QualType TreeTransform<Derived>::TransformAutoType(TypeLocBuilder &TLB, + AutoTypeLoc TL) { + const AutoType *T = TL.getTypePtr(); + QualType OldDeduced = T->getDeducedType(); + QualType NewDeduced; + if (!OldDeduced.isNull()) { + NewDeduced = getDerived().TransformType(OldDeduced); + if (NewDeduced.isNull()) + return QualType(); + } + + ConceptDecl *NewCD = nullptr; + TemplateArgumentListInfo NewTemplateArgs; + NestedNameSpecifierLoc NewNestedNameSpec; + if (TL.getTypePtr()->isConstrained()) { + NewCD = cast_or_null<ConceptDecl>( + getDerived().TransformDecl( + TL.getConceptNameLoc(), + TL.getTypePtr()->getTypeConstraintConcept())); + + NewTemplateArgs.setLAngleLoc(TL.getLAngleLoc()); + NewTemplateArgs.setRAngleLoc(TL.getRAngleLoc()); + typedef TemplateArgumentLocContainerIterator<AutoTypeLoc> ArgIterator; + if (getDerived().TransformTemplateArguments(ArgIterator(TL, 0), + ArgIterator(TL, + TL.getNumArgs()), + NewTemplateArgs)) + return QualType(); + + if (TL.getNestedNameSpecifierLoc()) { + NewNestedNameSpec + = getDerived().TransformNestedNameSpecifierLoc( + TL.getNestedNameSpecifierLoc()); + if (!NewNestedNameSpec) + return QualType(); + } + } + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || NewDeduced != OldDeduced || + T->isDependentType()) { + llvm::SmallVector<TemplateArgument, 4> NewArgList; + NewArgList.reserve(NewArgList.size()); + for (const auto &ArgLoc : NewTemplateArgs.arguments()) + NewArgList.push_back(ArgLoc.getArgument()); + Result = getDerived().RebuildAutoType(NewDeduced, T->getKeyword(), NewCD, + NewArgList); + if (Result.isNull()) + return QualType(); + } + + AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); + NewTL.setNameLoc(TL.getNameLoc()); + NewTL.setNestedNameSpecifierLoc(NewNestedNameSpec); + NewTL.setTemplateKWLoc(TL.getTemplateKWLoc()); + NewTL.setConceptNameLoc(TL.getConceptNameLoc()); + NewTL.setFoundDecl(TL.getFoundDecl()); + NewTL.setLAngleLoc(TL.getLAngleLoc()); + NewTL.setRAngleLoc(TL.getRAngleLoc()); + for (unsigned I = 0; I < TL.getNumArgs(); ++I) + NewTL.setArgLocInfo(I, NewTemplateArgs.arguments()[I].getLocInfo()); + + return Result; +} template <typename Derived> QualType TreeTransform<Derived>::TransformTemplateSpecializationType( @@ -6930,7 +7336,8 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { Body.get() == S->getBody()) return Owned(S); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get()); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), S->getLParenLoc(), + Cond, S->getRParenLoc(), Body.get()); } template<typename Derived> @@ -7228,7 +7635,8 @@ TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { return StmtError(); StmtResult FinalSuspend = getDerived().TransformStmt(S->getFinalSuspendStmt()); - if (FinalSuspend.isInvalid()) + if (FinalSuspend.isInvalid() || + !SemaRef.checkFinalSuspendNoThrow(FinalSuspend.get())) return StmtError(); ScopeInfo->setCoroutineSuspends(InitSuspend.get(), FinalSuspend.get()); assert(isa<Expr>(InitSuspend.get()) && isa<Expr>(FinalSuspend.get())); @@ -7684,8 +8092,12 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); - if (NewStmt.isInvalid()) + if (NewStmt.isInvalid() && LoopVar.get() != S->getLoopVarStmt()) { + // Might not have attached any initializer to the loop variable. + getSema().ActOnInitializerError( + cast<DeclStmt>(LoopVar.get())->getSingleDecl()); return StmtError(); + } } StmtResult Body = getDerived().TransformStmt(S->getBody()); @@ -8152,6 +8564,28 @@ TreeTransform<Derived>::TransformOMPFlushDirective(OMPFlushDirective *D) { template <typename Derived> StmtResult +TreeTransform<Derived>::TransformOMPDepobjDirective(OMPDepobjDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_depobj, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPScanDirective(OMPScanDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_scan, DirName, nullptr, + D->getBeginLoc()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPOrderedDirective(OMPOrderedDirective *D) { DeclarationNameInfo DirName; getDerived().getSema().StartOpenMPDSABlock(OMPD_ordered, DirName, nullptr, @@ -8638,6 +9072,19 @@ TreeTransform<Derived>::TransformOMPOrderedClause(OMPOrderedClause *C) { template <typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPDetachClause(OMPDetachClause *C) { + ExprResult E; + if (Expr *Evt = C->getEventHandler()) { + E = getDerived().TransformExpr(Evt); + if (E.isInvalid()) + return nullptr; + } + return getDerived().RebuildOMPDetachClause(E.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPNowaitClause(OMPNowaitClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; @@ -8692,6 +9139,34 @@ TreeTransform<Derived>::TransformOMPSeqCstClause(OMPSeqCstClause *C) { template <typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPAcqRelClause(OMPAcqRelClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPAcquireClause(OMPAcquireClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPReleaseClause(OMPReleaseClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPRelaxedClause(OMPRelaxedClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPThreadsClause(OMPThreadsClause *C) { // No need to rebuild this clause, no template-dependent parameters. return C; @@ -8711,6 +9186,13 @@ TreeTransform<Derived>::TransformOMPNogroupClause(OMPNogroupClause *C) { } template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPDestroyClause(OMPDestroyClause *C) { + // No need to rebuild this clause, no template-dependent parameters. + return C; +} + +template <typename Derived> OMPClause *TreeTransform<Derived>::TransformOMPUnifiedAddressClause( OMPUnifiedAddressClause *C) { llvm_unreachable("unified_address clause cannot appear in dependent context"); @@ -8847,8 +9329,9 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) { UnresolvedReductions.push_back(nullptr); } return getDerived().RebuildOMPReductionClause( - Vars, C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), - C->getEndLoc(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); + Vars, C->getModifier(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getColonLoc(), C->getEndLoc(), + ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template <typename Derived> @@ -9025,8 +9508,25 @@ OMPClause *TreeTransform<Derived>::TransformOMPFlushClause(OMPFlushClause *C) { template <typename Derived> OMPClause * +TreeTransform<Derived>::TransformOMPDepobjClause(OMPDepobjClause *C) { + ExprResult E = getDerived().TransformExpr(C->getDepobj()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPDepobjClause(E.get(), C->getBeginLoc(), + C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) { llvm::SmallVector<Expr *, 16> Vars; + Expr *DepModifier = C->getModifier(); + if (DepModifier) { + ExprResult DepModRes = getDerived().TransformExpr(DepModifier); + if (DepModRes.isInvalid()) + return nullptr; + DepModifier = DepModRes.get(); + } Vars.reserve(C->varlist_size()); for (auto *VE : C->varlists()) { ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); @@ -9035,8 +9535,9 @@ TreeTransform<Derived>::TransformOMPDependClause(OMPDependClause *C) { Vars.push_back(EVar.get()); } return getDerived().RebuildOMPDependClause( - C->getDependencyKind(), C->getDependencyLoc(), C->getColonLoc(), Vars, - C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + DepModifier, C->getDependencyKind(), C->getDependencyLoc(), + C->getColonLoc(), Vars, C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); } template <typename Derived> @@ -9045,8 +9546,9 @@ TreeTransform<Derived>::TransformOMPDeviceClause(OMPDeviceClause *C) { ExprResult E = getDerived().TransformExpr(C->getDevice()); if (E.isInvalid()) return nullptr; - return getDerived().RebuildOMPDeviceClause(E.get(), C->getBeginLoc(), - C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPDeviceClause( + C->getModifier(), E.get(), C->getBeginLoc(), C->getLParenLoc(), + C->getModifierLoc(), C->getEndLoc()); } template <typename Derived, class T> @@ -9269,6 +9771,21 @@ OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause( } template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPUseDeviceAddrClause( + OMPUseDeviceAddrClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + OMPVarListLocTy Locs(C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); + return getDerived().RebuildOMPUseDeviceAddrClause(Vars, Locs); +} + +template <typename Derived> OMPClause * TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { llvm::SmallVector<Expr *, 16> Vars; @@ -9298,6 +9815,91 @@ TreeTransform<Derived>::TransformOMPNontemporalClause(OMPNontemporalClause *C) { Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); } +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPInclusiveClause(OMPInclusiveClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPInclusiveClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPExclusiveClause(OMPExclusiveClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPExclusiveClause( + Vars, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPUsesAllocatorsClause( + OMPUsesAllocatorsClause *C) { + SmallVector<Sema::UsesAllocatorsData, 16> Data; + Data.reserve(C->getNumberOfAllocators()); + for (unsigned I = 0, E = C->getNumberOfAllocators(); I < E; ++I) { + OMPUsesAllocatorsClause::Data D = C->getAllocatorData(I); + ExprResult Allocator = getDerived().TransformExpr(D.Allocator); + if (Allocator.isInvalid()) + continue; + ExprResult AllocatorTraits; + if (Expr *AT = D.AllocatorTraits) { + AllocatorTraits = getDerived().TransformExpr(AT); + if (AllocatorTraits.isInvalid()) + continue; + } + Sema::UsesAllocatorsData &NewD = Data.emplace_back(); + NewD.Allocator = Allocator.get(); + NewD.AllocatorTraits = AllocatorTraits.get(); + NewD.LParenLoc = D.LParenLoc; + NewD.RParenLoc = D.RParenLoc; + } + return getDerived().RebuildOMPUsesAllocatorsClause( + Data, C->getBeginLoc(), C->getLParenLoc(), C->getEndLoc()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPAffinityClause(OMPAffinityClause *C) { + SmallVector<Expr *, 4> Locators; + Locators.reserve(C->varlist_size()); + ExprResult ModifierRes; + if (Expr *Modifier = C->getModifier()) { + ModifierRes = getDerived().TransformExpr(Modifier); + if (ModifierRes.isInvalid()) + return nullptr; + } + for (Expr *E : C->varlists()) { + ExprResult Locator = getDerived().TransformExpr(E); + if (Locator.isInvalid()) + continue; + Locators.push_back(Locator.get()); + } + return getDerived().RebuildOMPAffinityClause( + C->getBeginLoc(), C->getLParenLoc(), C->getColonLoc(), C->getEndLoc(), + ModifierRes.get(), Locators); +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPOrderClause(OMPOrderClause *C) { + return getDerived().RebuildOMPOrderClause(C->getKind(), C->getKindKwLoc(), + C->getBeginLoc(), C->getLParenLoc(), + C->getEndLoc()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -9581,6 +10183,24 @@ TreeTransform<Derived>::TransformTypoExpr(TypoExpr *E) { return E; } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformRecoveryExpr(RecoveryExpr *E) { + llvm::SmallVector<Expr *, 8> Children; + bool Changed = false; + for (Expr *C : E->subExpressions()) { + ExprResult NewC = getDerived().TransformExpr(C); + if (NewC.isInvalid()) + return ExprError(); + Children.push_back(NewC.get()); + + Changed |= NewC.get() != C; + } + if (!getDerived().AlwaysRebuild() && !Changed) + return E; + return getDerived().RebuildRecoveryExpr(E->getBeginLoc(), E->getEndLoc(), + Children); +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformPseudoObjectExpr(PseudoObjectExpr *E) { @@ -9680,6 +10300,29 @@ TreeTransform<Derived>::TransformArraySubscriptExpr(ArraySubscriptExpr *E) { template <typename Derived> ExprResult +TreeTransform<Derived>::TransformMatrixSubscriptExpr(MatrixSubscriptExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + ExprResult RowIdx = getDerived().TransformExpr(E->getRowIdx()); + if (RowIdx.isInvalid()) + return ExprError(); + + ExprResult ColumnIdx = getDerived().TransformExpr(E->getColumnIdx()); + if (ColumnIdx.isInvalid()) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && + RowIdx.get() == E->getRowIdx() && ColumnIdx.get() == E->getColumnIdx()) + return E; + + return getDerived().RebuildMatrixSubscriptExpr( + Base.get(), RowIdx.get(), ColumnIdx.get(), E->getRBracketLoc()); +} + +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { ExprResult Base = getDerived().TransformExpr(E->getBase()); if (Base.isInvalid()) @@ -9699,13 +10342,105 @@ TreeTransform<Derived>::TransformOMPArraySectionExpr(OMPArraySectionExpr *E) { return ExprError(); } + ExprResult Stride; + if (Expr *Str = E->getStride()) { + Stride = getDerived().TransformExpr(Str); + if (Stride.isInvalid()) + return ExprError(); + } + if (!getDerived().AlwaysRebuild() && Base.get() == E->getBase() && LowerBound.get() == E->getLowerBound() && Length.get() == E->getLength()) return E; return getDerived().RebuildOMPArraySectionExpr( - Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), E->getColonLoc(), - Length.get(), E->getRBracketLoc()); + Base.get(), E->getBase()->getEndLoc(), LowerBound.get(), + E->getColonLocFirst(), E->getColonLocSecond(), Length.get(), Stride.get(), + E->getRBracketLoc()); +} + +template <typename Derived> +ExprResult +TreeTransform<Derived>::TransformOMPArrayShapingExpr(OMPArrayShapingExpr *E) { + ExprResult Base = getDerived().TransformExpr(E->getBase()); + if (Base.isInvalid()) + return ExprError(); + + SmallVector<Expr *, 4> Dims; + bool ErrorFound = false; + for (Expr *Dim : E->getDimensions()) { + ExprResult DimRes = getDerived().TransformExpr(Dim); + if (DimRes.isInvalid()) { + ErrorFound = true; + continue; + } + Dims.push_back(DimRes.get()); + } + + if (ErrorFound) + return ExprError(); + return getDerived().RebuildOMPArrayShapingExpr(Base.get(), E->getLParenLoc(), + E->getRParenLoc(), Dims, + E->getBracketsRanges()); +} + +template <typename Derived> +ExprResult +TreeTransform<Derived>::TransformOMPIteratorExpr(OMPIteratorExpr *E) { + unsigned NumIterators = E->numOfIterators(); + SmallVector<Sema::OMPIteratorData, 4> Data(NumIterators); + + bool ErrorFound = false; + bool NeedToRebuild = getDerived().AlwaysRebuild(); + for (unsigned I = 0; I < NumIterators; ++I) { + auto *D = cast<VarDecl>(E->getIteratorDecl(I)); + Data[I].DeclIdent = D->getIdentifier(); + Data[I].DeclIdentLoc = D->getLocation(); + if (D->getLocation() == D->getBeginLoc()) { + assert(SemaRef.Context.hasSameType(D->getType(), SemaRef.Context.IntTy) && + "Implicit type must be int."); + } else { + TypeSourceInfo *TSI = getDerived().TransformType(D->getTypeSourceInfo()); + QualType DeclTy = getDerived().TransformType(D->getType()); + Data[I].Type = SemaRef.CreateParsedType(DeclTy, TSI); + } + OMPIteratorExpr::IteratorRange Range = E->getIteratorRange(I); + ExprResult Begin = getDerived().TransformExpr(Range.Begin); + ExprResult End = getDerived().TransformExpr(Range.End); + ExprResult Step = getDerived().TransformExpr(Range.Step); + ErrorFound = ErrorFound || + !(!D->getTypeSourceInfo() || (Data[I].Type.getAsOpaquePtr() && + !Data[I].Type.get().isNull())) || + Begin.isInvalid() || End.isInvalid() || Step.isInvalid(); + if (ErrorFound) + continue; + Data[I].Range.Begin = Begin.get(); + Data[I].Range.End = End.get(); + Data[I].Range.Step = Step.get(); + Data[I].AssignLoc = E->getAssignLoc(I); + Data[I].ColonLoc = E->getColonLoc(I); + Data[I].SecColonLoc = E->getSecondColonLoc(I); + NeedToRebuild = + NeedToRebuild || + (D->getTypeSourceInfo() && Data[I].Type.get().getTypePtrOrNull() != + D->getType().getTypePtrOrNull()) || + Range.Begin != Data[I].Range.Begin || Range.End != Data[I].Range.End || + Range.Step != Data[I].Range.Step; + } + if (ErrorFound) + return ExprError(); + if (!NeedToRebuild) + return E; + + ExprResult Res = getDerived().RebuildOMPIteratorExpr( + E->getIteratorKwLoc(), E->getLParenLoc(), E->getRParenLoc(), Data); + if (!Res.isUsable()) + return Res; + auto *IE = cast<OMPIteratorExpr>(Res.get()); + for (unsigned I = 0; I < NumIterators; ++I) + getDerived().transformedLocalDecl(E->getIteratorDecl(I), + IE->getIteratorDecl(I)); + return Res; } template<typename Derived> @@ -9837,9 +10572,15 @@ TreeTransform<Derived>::TransformBinaryOperator(BinaryOperator *E) { RHS.get() == E->getRHS()) return E; - Sema::FPContractStateRAII FPContractState(getSema()); - getSema().FPFeatures = E->getFPFeatures(); - + if (E->isCompoundAssignmentOp()) + // FPFeatures has already been established from trailing storage + return getDerived().RebuildBinaryOperator( + E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); + FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().RebuildBinaryOperator(E->getOperatorLoc(), E->getOpcode(), LHS.get(), RHS.get()); } @@ -9892,6 +10633,11 @@ template<typename Derived> ExprResult TreeTransform<Derived>::TransformCompoundAssignOperator( CompoundAssignOperator *E) { + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); + FPOptionsOverride NewOverrides(E->getFPFeatures(getSema().getLangOpts())); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().TransformBinaryOperator(E); } @@ -10245,16 +10991,18 @@ TreeTransform<Derived>::TransformStmtExpr(StmtExpr *E) { return ExprError(); } - if (!getDerived().AlwaysRebuild() && + unsigned OldDepth = E->getTemplateDepth(); + unsigned NewDepth = getDerived().TransformTemplateDepth(OldDepth); + + if (!getDerived().AlwaysRebuild() && OldDepth == NewDepth && SubStmt.get() == E->getSubStmt()) { // Calling this an 'error' is unintuitive, but it does the right thing. SemaRef.ActOnStmtExprError(); return SemaRef.MaybeBindToTemporary(E); } - return getDerived().RebuildStmtExpr(E->getLParenLoc(), - SubStmt.get(), - E->getRParenLoc()); + return getDerived().RebuildStmtExpr(E->getLParenLoc(), SubStmt.get(), + E->getRParenLoc(), NewDepth); } template<typename Derived> @@ -10363,8 +11111,11 @@ TreeTransform<Derived>::TransformCXXOperatorCallExpr(CXXOperatorCallExpr *E) { (E->getNumArgs() != 2 || Second.get() == E->getArg(1))) return SemaRef.MaybeBindToTemporary(E); - Sema::FPContractStateRAII FPContractState(getSema()); - getSema().FPFeatures = E->getFPFeatures(); + Sema::FPFeaturesStateRAII FPFeaturesState(getSema()); + FPOptionsOverride NewOverrides(E->getFPFeatures()); + getSema().CurFPFeatures = + NewOverrides.applyOverrides(getSema().getLangOpts()); + getSema().FpPragmaStack.CurrentValue = NewOverrides.getAsOpaqueInt(); return getDerived().RebuildCXXOperatorCallExpr(E->getOperator(), E->getOperatorLoc(), @@ -10491,6 +11242,12 @@ TreeTransform<Derived>::TransformCXXConstCastExpr(CXXConstCastExpr *E) { template<typename Derived> ExprResult +TreeTransform<Derived>::TransformCXXAddrspaceCastExpr(CXXAddrspaceCastExpr *E) { + return getDerived().TransformCXXNamedCastExpr(E); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXFunctionalCastExpr( CXXFunctionalCastExpr *E) { TypeSourceInfo *Type = @@ -11179,6 +11936,146 @@ TreeTransform<Derived>::TransformConceptSpecializationExpr( &TransArgs); } +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformRequiresExpr(RequiresExpr *E) { + SmallVector<ParmVarDecl*, 4> TransParams; + SmallVector<QualType, 4> TransParamTypes; + Sema::ExtParameterInfoBuilder ExtParamInfos; + + // C++2a [expr.prim.req]p2 + // Expressions appearing within a requirement-body are unevaluated operands. + EnterExpressionEvaluationContext Ctx( + SemaRef, Sema::ExpressionEvaluationContext::Unevaluated); + + RequiresExprBodyDecl *Body = RequiresExprBodyDecl::Create( + getSema().Context, getSema().CurContext, + E->getBody()->getBeginLoc()); + + Sema::ContextRAII SavedContext(getSema(), Body, /*NewThisContext*/false); + + if (getDerived().TransformFunctionTypeParams(E->getRequiresKWLoc(), + E->getLocalParameters(), + /*ParamTypes=*/nullptr, + /*ParamInfos=*/nullptr, + TransParamTypes, &TransParams, + ExtParamInfos)) + return ExprError(); + + for (ParmVarDecl *Param : TransParams) + Param->setDeclContext(Body); + + SmallVector<concepts::Requirement *, 4> TransReqs; + if (getDerived().TransformRequiresExprRequirements(E->getRequirements(), + TransReqs)) + return ExprError(); + + for (concepts::Requirement *Req : TransReqs) { + if (auto *ER = dyn_cast<concepts::ExprRequirement>(Req)) { + if (ER->getReturnTypeRequirement().isTypeConstraint()) { + ER->getReturnTypeRequirement() + .getTypeConstraintTemplateParameterList()->getParam(0) + ->setDeclContext(Body); + } + } + } + + return getDerived().RebuildRequiresExpr(E->getRequiresKWLoc(), Body, + TransParams, TransReqs, + E->getRBraceLoc()); +} + +template<typename Derived> +bool TreeTransform<Derived>::TransformRequiresExprRequirements( + ArrayRef<concepts::Requirement *> Reqs, + SmallVectorImpl<concepts::Requirement *> &Transformed) { + for (concepts::Requirement *Req : Reqs) { + concepts::Requirement *TransReq = nullptr; + if (auto *TypeReq = dyn_cast<concepts::TypeRequirement>(Req)) + TransReq = getDerived().TransformTypeRequirement(TypeReq); + else if (auto *ExprReq = dyn_cast<concepts::ExprRequirement>(Req)) + TransReq = getDerived().TransformExprRequirement(ExprReq); + else + TransReq = getDerived().TransformNestedRequirement( + cast<concepts::NestedRequirement>(Req)); + if (!TransReq) + return true; + Transformed.push_back(TransReq); + } + return false; +} + +template<typename Derived> +concepts::TypeRequirement * +TreeTransform<Derived>::TransformTypeRequirement( + concepts::TypeRequirement *Req) { + if (Req->isSubstitutionFailure()) { + if (getDerived().AlwaysRebuild()) + return getDerived().RebuildTypeRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + TypeSourceInfo *TransType = getDerived().TransformType(Req->getType()); + if (!TransType) + return nullptr; + return getDerived().RebuildTypeRequirement(TransType); +} + +template<typename Derived> +concepts::ExprRequirement * +TreeTransform<Derived>::TransformExprRequirement(concepts::ExprRequirement *Req) { + llvm::PointerUnion<Expr *, concepts::Requirement::SubstitutionDiagnostic *> TransExpr; + if (Req->isExprSubstitutionFailure()) + TransExpr = Req->getExprSubstitutionDiagnostic(); + else { + ExprResult TransExprRes = getDerived().TransformExpr(Req->getExpr()); + if (TransExprRes.isInvalid()) + return nullptr; + TransExpr = TransExprRes.get(); + } + + llvm::Optional<concepts::ExprRequirement::ReturnTypeRequirement> TransRetReq; + const auto &RetReq = Req->getReturnTypeRequirement(); + if (RetReq.isEmpty()) + TransRetReq.emplace(); + else if (RetReq.isSubstitutionFailure()) + TransRetReq.emplace(RetReq.getSubstitutionDiagnostic()); + else if (RetReq.isTypeConstraint()) { + TemplateParameterList *OrigTPL = + RetReq.getTypeConstraintTemplateParameterList(); + TemplateParameterList *TPL = + getDerived().TransformTemplateParameterList(OrigTPL); + if (!TPL) + return nullptr; + TransRetReq.emplace(TPL); + } + assert(TransRetReq.hasValue() && + "All code paths leading here must set TransRetReq"); + if (Expr *E = TransExpr.dyn_cast<Expr *>()) + return getDerived().RebuildExprRequirement(E, Req->isSimple(), + Req->getNoexceptLoc(), + std::move(*TransRetReq)); + return getDerived().RebuildExprRequirement( + TransExpr.get<concepts::Requirement::SubstitutionDiagnostic *>(), + Req->isSimple(), Req->getNoexceptLoc(), std::move(*TransRetReq)); +} + +template<typename Derived> +concepts::NestedRequirement * +TreeTransform<Derived>::TransformNestedRequirement( + concepts::NestedRequirement *Req) { + if (Req->isSubstitutionFailure()) { + if (getDerived().AlwaysRebuild()) + return getDerived().RebuildNestedRequirement( + Req->getSubstitutionDiagnostic()); + return Req; + } + ExprResult TransConstraint = + getDerived().TransformExpr(Req->getConstraintExpr()); + if (TransConstraint.isInvalid()) + return nullptr; + return getDerived().RebuildNestedRequirement(TransConstraint.get()); +} template<typename Derived> ExprResult @@ -11303,10 +12200,11 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { // CXXConstructExprs other than for list-initialization and // CXXTemporaryObjectExpr are always implicit, so when we have // a 1-argument construction we just transform that argument. - if ((E->getNumArgs() == 1 || - (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) && - (!getDerived().DropCallArgument(E->getArg(0))) && - !E->isListInitialization()) + if (getDerived().AllowSkippingCXXConstructExpr() && + ((E->getNumArgs() == 1 || + (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) && + (!getDerived().DropCallArgument(E->getArg(0))) && + !E->isListInitialization())) return getDerived().TransformExpr(E->getArg(0)); TemporaryBase Rebase(*this, /*FIXME*/ E->getBeginLoc(), DeclarationName()); @@ -11560,6 +12458,8 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { NewTrailingRequiresClause = getDerived().TransformExpr(TRC); // Create the local class that will describe the lambda. + // FIXME: KnownDependent below is wrong when substituting inside a templated + // context that isn't a DeclContext (such as a variable template). CXXRecordDecl *OldClass = E->getLambdaClass(); CXXRecordDecl *Class = getSema().createLambdaClosureType(E->getIntroducerRange(), @@ -11584,19 +12484,6 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { LSI->CallOperator = NewCallOperator; - for (unsigned I = 0, NumParams = NewCallOperator->getNumParams(); - I != NumParams; ++I) { - auto *P = NewCallOperator->getParamDecl(I); - if (P->hasUninstantiatedDefaultArg()) { - EnterExpressionEvaluationContext Eval( - getSema(), - Sema::ExpressionEvaluationContext::PotentiallyEvaluatedIfUsed, P); - ExprResult R = getDerived().TransformExpr( - E->getCallOperator()->getParamDecl(I)->getDefaultArg()); - P->setDefaultArg(R.get()); - } - } - getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); getDerived().transformedLocalDecl(E->getCallOperator(), {NewCallOperator}); @@ -13092,6 +13979,21 @@ TreeTransform<Derived>::RebuildDependentSizedExtVectorType(QualType ElementType, return SemaRef.BuildExtVectorType(ElementType, SizeExpr, AttributeLoc); } +template <typename Derived> +QualType TreeTransform<Derived>::RebuildConstantMatrixType( + QualType ElementType, unsigned NumRows, unsigned NumColumns) { + return SemaRef.Context.getConstantMatrixType(ElementType, NumRows, + NumColumns); +} + +template <typename Derived> +QualType TreeTransform<Derived>::RebuildDependentSizedMatrixType( + QualType ElementType, Expr *RowExpr, Expr *ColumnExpr, + SourceLocation AttributeLoc) { + return SemaRef.BuildMatrixType(ElementType, RowExpr, ColumnExpr, + AttributeLoc); +} + template<typename Derived> QualType TreeTransform<Derived>::RebuildFunctionProtoType( QualType T, @@ -13206,6 +14108,23 @@ QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType, : SemaRef.BuildWritePipeType(ValueType, KWLoc); } +template <typename Derived> +QualType TreeTransform<Derived>::RebuildExtIntType(bool IsUnsigned, + unsigned NumBits, + SourceLocation Loc) { + llvm::APInt NumBitsAP(SemaRef.Context.getIntWidth(SemaRef.Context.IntTy), + NumBits, true); + IntegerLiteral *Bits = IntegerLiteral::Create(SemaRef.Context, NumBitsAP, + SemaRef.Context.IntTy, Loc); + return SemaRef.BuildExtIntType(IsUnsigned, Bits, Loc); +} + +template <typename Derived> +QualType TreeTransform<Derived>::RebuildDependentExtIntType( + bool IsUnsigned, Expr *NumBitsExpr, SourceLocation Loc) { + return SemaRef.BuildExtIntType(IsUnsigned, NumBitsExpr, Loc); +} + template<typename Derived> TemplateName TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, @@ -13227,11 +14146,10 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, UnqualifiedId TemplateName; TemplateName.setIdentifier(&Name, NameLoc); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, TemplateName, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName(/*Scope=*/nullptr, SS, TemplateKWLoc, + TemplateName, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, + AllowInjectedClassName); return Template.get(); } @@ -13248,11 +14166,9 @@ TreeTransform<Derived>::RebuildTemplateName(CXXScopeSpec &SS, SourceLocation SymbolLocations[3] = { NameLoc, NameLoc, NameLoc }; Name.setOperatorFunctionId(NameLoc, Operator, SymbolLocations); Sema::TemplateTy Template; - getSema().ActOnDependentTemplateName(/*Scope=*/nullptr, - SS, TemplateKWLoc, Name, - ParsedType::make(ObjectType), - /*EnteringContext=*/false, - Template, AllowInjectedClassName); + getSema().ActOnTemplateName( + /*Scope=*/nullptr, SS, TemplateKWLoc, Name, ParsedType::make(ObjectType), + /*EnteringContext=*/false, Template, AllowInjectedClassName); return Template.get(); } diff --git a/clang/lib/Sema/UsedDeclVisitor.h b/clang/lib/Sema/UsedDeclVisitor.h new file mode 100644 index 000000000000..d207e07f451a --- /dev/null +++ b/clang/lib/Sema/UsedDeclVisitor.h @@ -0,0 +1,102 @@ +//===- UsedDeclVisitor.h - ODR-used declarations visitor --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// +// +// This file defines UsedDeclVisitor, a CRTP class which visits all the +// declarations that are ODR-used by an expression or statement. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H +#define LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H + +#include "clang/AST/EvaluatedExprVisitor.h" +#include "clang/Sema/SemaInternal.h" + +namespace clang { +template <class Derived> +class UsedDeclVisitor : public EvaluatedExprVisitor<Derived> { +protected: + Sema &S; + +public: + typedef EvaluatedExprVisitor<Derived> Inherited; + + UsedDeclVisitor(Sema &S) : Inherited(S.Context), S(S) {} + + Derived &asImpl() { return *static_cast<Derived *>(this); } + + void VisitDeclRefExpr(DeclRefExpr *E) { + auto *D = E->getDecl(); + if (isa<FunctionDecl>(D) || isa<VarDecl>(D)) { + asImpl().visitUsedDecl(E->getLocation(), D); + } + } + + void VisitMemberExpr(MemberExpr *E) { + auto *D = E->getMemberDecl(); + if (isa<FunctionDecl>(D) || isa<VarDecl>(D)) { + asImpl().visitUsedDecl(E->getMemberLoc(), D); + } + asImpl().Visit(E->getBase()); + } + + void VisitCapturedStmt(CapturedStmt *Node) { + asImpl().visitUsedDecl(Node->getBeginLoc(), Node->getCapturedDecl()); + Inherited::VisitCapturedStmt(Node); + } + + void VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + asImpl().visitUsedDecl( + E->getBeginLoc(), + const_cast<CXXDestructorDecl *>(E->getTemporary()->getDestructor())); + asImpl().Visit(E->getSubExpr()); + } + + void VisitCXXNewExpr(CXXNewExpr *E) { + if (E->getOperatorNew()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorNew()); + if (E->getOperatorDelete()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete()); + Inherited::VisitCXXNewExpr(E); + } + + void VisitCXXDeleteExpr(CXXDeleteExpr *E) { + if (E->getOperatorDelete()) + asImpl().visitUsedDecl(E->getBeginLoc(), E->getOperatorDelete()); + QualType Destroyed = S.Context.getBaseElementType(E->getDestroyedType()); + if (const RecordType *DestroyedRec = Destroyed->getAs<RecordType>()) { + CXXRecordDecl *Record = cast<CXXRecordDecl>(DestroyedRec->getDecl()); + asImpl().visitUsedDecl(E->getBeginLoc(), S.LookupDestructor(Record)); + } + + Inherited::VisitCXXDeleteExpr(E); + } + + void VisitCXXConstructExpr(CXXConstructExpr *E) { + asImpl().visitUsedDecl(E->getBeginLoc(), E->getConstructor()); + Inherited::VisitCXXConstructExpr(E); + } + + void VisitCXXDefaultArgExpr(CXXDefaultArgExpr *E) { + asImpl().Visit(E->getExpr()); + } + + void visitUsedDecl(SourceLocation Loc, Decl *D) { + if (auto *CD = dyn_cast<CapturedDecl>(D)) { + if (auto *S = CD->getBody()) { + asImpl().Visit(S); + } + } else if (auto *CD = dyn_cast<BlockDecl>(D)) { + if (auto *S = CD->getBody()) { + asImpl().Visit(S); + } + } + } +}; +} // end namespace clang + +#endif // LLVM_CLANG_LIB_SEMA_USEDDECLVISITOR_H |