diff options
Diffstat (limited to 'lib/Sema')
43 files changed, 11833 insertions, 6399 deletions
diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index 67762bde3439d..5953d020b4fbc 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -37,12 +37,8 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaInternal.h" -#include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/BitVector.h" -#include "llvm/ADT/FoldingSet.h" -#include "llvm/ADT/ImmutableMap.h" #include "llvm/ADT/MapVector.h" -#include "llvm/ADT/PostOrderIterator.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringRef.h" @@ -50,7 +46,6 @@ #include <algorithm> #include <deque> #include <iterator> -#include <vector> using namespace clang; @@ -370,7 +365,7 @@ static ControlFlowKind CheckFallThrough(AnalysisDeclContext &AC) { CFGStmt CS = ri->castAs<CFGStmt>(); const Stmt *S = CS.getStmt(); - if (isa<ReturnStmt>(S)) { + if (isa<ReturnStmt>(S) || isa<CoreturnStmt>(S)) { HasLiveReturn = true; continue; } @@ -421,7 +416,7 @@ struct CheckFallThroughDiagnostics { unsigned diag_AlwaysFallThrough_HasNoReturn; unsigned diag_AlwaysFallThrough_ReturnsNonVoid; unsigned diag_NeverFallThroughOrReturn; - enum { Function, Block, Lambda } funMode; + enum { Function, Block, Lambda, Coroutine } funMode; SourceLocation FuncLoc; static CheckFallThroughDiagnostics MakeForFunction(const Decl *Func) { @@ -457,6 +452,19 @@ struct CheckFallThroughDiagnostics { return D; } + static CheckFallThroughDiagnostics MakeForCoroutine(const Decl *Func) { + CheckFallThroughDiagnostics D; + D.FuncLoc = Func->getLocation(); + D.diag_MaybeFallThrough_HasNoReturn = 0; + D.diag_MaybeFallThrough_ReturnsNonVoid = + diag::warn_maybe_falloff_nonvoid_coroutine; + D.diag_AlwaysFallThrough_HasNoReturn = 0; + D.diag_AlwaysFallThrough_ReturnsNonVoid = + diag::warn_falloff_nonvoid_coroutine; + D.funMode = Coroutine; + return D; + } + static CheckFallThroughDiagnostics MakeForBlock() { CheckFallThroughDiagnostics D; D.diag_MaybeFallThrough_HasNoReturn = @@ -499,7 +507,13 @@ struct CheckFallThroughDiagnostics { (!ReturnsVoid || D.isIgnored(diag::warn_suggest_noreturn_block, FuncLoc)); } - + if (funMode == Coroutine) { + return (ReturnsVoid || + D.isIgnored(diag::warn_maybe_falloff_nonvoid_function, FuncLoc) || + D.isIgnored(diag::warn_maybe_falloff_nonvoid_coroutine, + FuncLoc)) && + (!HasNoReturn); + } // For blocks / lambdas. return ReturnsVoid && !HasNoReturn; } @@ -519,11 +533,14 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, bool ReturnsVoid = false; bool HasNoReturn = false; - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - ReturnsVoid = FD->getReturnType()->isVoidType(); + if (const auto *FD = dyn_cast<FunctionDecl>(D)) { + if (const auto *CBody = dyn_cast<CoroutineBodyStmt>(Body)) + ReturnsVoid = CBody->getFallthroughHandler() != nullptr; + else + ReturnsVoid = FD->getReturnType()->isVoidType(); HasNoReturn = FD->isNoReturn(); } - else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { + else if (const auto *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnsVoid = MD->getReturnType()->isVoidType(); HasNoReturn = MD->hasAttr<NoReturnAttr>(); } @@ -1991,13 +2008,22 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, // Warning: check missing 'return' if (P.enableCheckFallThrough) { + auto IsCoro = [&]() { + if (auto *FD = dyn_cast<FunctionDecl>(D)) + if (FD->getBody() && isa<CoroutineBodyStmt>(FD->getBody())) + return true; + return false; + }; const CheckFallThroughDiagnostics &CD = - (isa<BlockDecl>(D) ? CheckFallThroughDiagnostics::MakeForBlock() - : (isa<CXXMethodDecl>(D) && - cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && - cast<CXXMethodDecl>(D)->getParent()->isLambda()) - ? CheckFallThroughDiagnostics::MakeForLambda() - : CheckFallThroughDiagnostics::MakeForFunction(D)); + (isa<BlockDecl>(D) + ? CheckFallThroughDiagnostics::MakeForBlock() + : (isa<CXXMethodDecl>(D) && + cast<CXXMethodDecl>(D)->getOverloadedOperator() == OO_Call && + cast<CXXMethodDecl>(D)->getParent()->isLambda()) + ? CheckFallThroughDiagnostics::MakeForLambda() + : (IsCoro() + ? CheckFallThroughDiagnostics::MakeForCoroutine(D) + : CheckFallThroughDiagnostics::MakeForFunction(D))); CheckFallThroughForBody(S, D, Body, blkExpr, CD, AC); } diff --git a/lib/Sema/AttributeList.cpp b/lib/Sema/AttributeList.cpp index cae9393f9f3aa..55e9601bf5e58 100644 --- a/lib/Sema/AttributeList.cpp +++ b/lib/Sema/AttributeList.cpp @@ -20,7 +20,6 @@ #include "clang/Basic/TargetInfo.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/SmallString.h" -#include "llvm/ADT/StringSwitch.h" using namespace clang; IdentifierLoc *IdentifierLoc::create(ASTContext &Ctx, SourceLocation Loc, @@ -63,7 +62,7 @@ void *AttributeFactory::allocate(size_t size) { } // Otherwise, allocate something new. - return Alloc.Allocate(size, llvm::AlignOf<AttributeFactory>::Alignment); + return Alloc.Allocate(size, alignof(AttributeFactory)); } void AttributeFactory::reclaimPool(AttributeList *cur) { diff --git a/lib/Sema/CodeCompleteConsumer.cpp b/lib/Sema/CodeCompleteConsumer.cpp index 9a4f0d921bf45..f5b0104462f78 100644 --- a/lib/Sema/CodeCompleteConsumer.cpp +++ b/lib/Sema/CodeCompleteConsumer.cpp @@ -17,6 +17,7 @@ #include "clang/AST/DeclTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/Sema.h" +#include "clang/Lex/Preprocessor.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Twine.h" @@ -327,9 +328,9 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { CodeCompletionString *CodeCompletionBuilder::TakeString() { void *Mem = getAllocator().Allocate( - sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() - + sizeof(const char *) * Annotations.size(), - llvm::alignOf<CodeCompletionString>()); + sizeof(CodeCompletionString) + sizeof(Chunk) * Chunks.size() + + sizeof(const char *) * Annotations.size(), + alignof(CodeCompletionString)); CodeCompletionString *Result = new (Mem) CodeCompletionString(Chunks.data(), Chunks.size(), Priority, Availability, @@ -428,6 +429,26 @@ CodeCompleteConsumer::OverloadCandidate::getFunctionType() const { CodeCompleteConsumer::~CodeCompleteConsumer() { } +bool PrintingCodeCompleteConsumer::isResultFilteredOut(StringRef Filter, + CodeCompletionResult Result) { + switch (Result.Kind) { + case CodeCompletionResult::RK_Declaration: { + return !(Result.Declaration->getIdentifier() && + Result.Declaration->getIdentifier()->getName().startswith(Filter)); + } + case CodeCompletionResult::RK_Keyword: { + return !StringRef(Result.Keyword).startswith(Filter); + } + case CodeCompletionResult::RK_Macro: { + return !Result.Macro->getName().startswith(Filter); + } + case CodeCompletionResult::RK_Pattern: { + return !StringRef(Result.Pattern->getAsString()).startswith(Filter); + } + } + llvm_unreachable("Unknown code completion result Kind."); +} + void PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, CodeCompletionContext Context, @@ -435,8 +456,12 @@ PrintingCodeCompleteConsumer::ProcessCodeCompleteResults(Sema &SemaRef, unsigned NumResults) { std::stable_sort(Results, Results + NumResults); + StringRef Filter = SemaRef.getPreprocessor().getCodeCompletionFilter(); + // Print the results. for (unsigned I = 0; I != NumResults; ++I) { + if(!Filter.empty() && isResultFilteredOut(Filter, Results[I])) + continue; OS << "COMPLETION: "; switch (Results[I].Kind) { case CodeCompletionResult::RK_Declaration: diff --git a/lib/Sema/DeclSpec.cpp b/lib/Sema/DeclSpec.cpp index b9d2843b0558c..a55cdcccee5df 100644 --- a/lib/Sema/DeclSpec.cpp +++ b/lib/Sema/DeclSpec.cpp @@ -173,6 +173,8 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, unsigned NumExceptions, Expr *NoexceptExpr, CachedTokens *ExceptionSpecTokens, + ArrayRef<NamedDecl*> + DeclsInPrototype, SourceLocation LocalRangeBegin, SourceLocation LocalRangeEnd, Declarator &TheDeclarator, @@ -204,7 +206,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.ExceptionSpecType = ESpecType; I.Fun.ExceptionSpecLocBeg = ESpecRange.getBegin().getRawEncoding(); I.Fun.ExceptionSpecLocEnd = ESpecRange.getEnd().getRawEncoding(); - I.Fun.NumExceptions = 0; + I.Fun.NumExceptionsOrDecls = 0; I.Fun.Exceptions = nullptr; I.Fun.NoexceptExpr = nullptr; I.Fun.HasTrailingReturnType = TrailingReturnType.isUsable() || @@ -220,16 +222,18 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, // parameter list there (in an effort to avoid new/delete traffic). If it // is already used (consider a function returning a function pointer) or too // small (function with too many parameters), go to the heap. - if (!TheDeclarator.InlineParamsUsed && + if (!TheDeclarator.InlineStorageUsed && NumParams <= llvm::array_lengthof(TheDeclarator.InlineParams)) { I.Fun.Params = TheDeclarator.InlineParams; + new (I.Fun.Params) ParamInfo[NumParams]; I.Fun.DeleteParams = false; - TheDeclarator.InlineParamsUsed = true; + TheDeclarator.InlineStorageUsed = true; } else { I.Fun.Params = new DeclaratorChunk::ParamInfo[NumParams]; I.Fun.DeleteParams = true; } - memcpy(I.Fun.Params, Params, sizeof(Params[0]) * NumParams); + for (unsigned i = 0; i < NumParams; i++) + I.Fun.Params[i] = std::move(Params[i]); } // Check what exception specification information we should actually store. @@ -238,7 +242,7 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, case EST_Dynamic: // new[] an exception array if needed if (NumExceptions) { - I.Fun.NumExceptions = NumExceptions; + I.Fun.NumExceptionsOrDecls = NumExceptions; I.Fun.Exceptions = new DeclaratorChunk::TypeAndRange[NumExceptions]; for (unsigned i = 0; i != NumExceptions; ++i) { I.Fun.Exceptions[i].Ty = Exceptions[i]; @@ -255,9 +259,52 @@ DeclaratorChunk DeclaratorChunk::getFunction(bool hasProto, I.Fun.ExceptionSpecTokens = ExceptionSpecTokens; break; } + + if (!DeclsInPrototype.empty()) { + assert(ESpecType == EST_None && NumExceptions == 0 && + "cannot have exception specifiers and decls in prototype"); + I.Fun.NumExceptionsOrDecls = DeclsInPrototype.size(); + // Copy the array of decls into stable heap storage. + I.Fun.DeclsInPrototype = new NamedDecl *[DeclsInPrototype.size()]; + for (size_t J = 0; J < DeclsInPrototype.size(); ++J) + I.Fun.DeclsInPrototype[J] = DeclsInPrototype[J]; + } + return I; } +void Declarator::setDecompositionBindings( + SourceLocation LSquareLoc, + ArrayRef<DecompositionDeclarator::Binding> Bindings, + SourceLocation RSquareLoc) { + assert(!hasName() && "declarator given multiple names!"); + + BindingGroup.LSquareLoc = LSquareLoc; + BindingGroup.RSquareLoc = RSquareLoc; + BindingGroup.NumBindings = Bindings.size(); + Range.setEnd(RSquareLoc); + + // We're now past the identifier. + SetIdentifier(nullptr, LSquareLoc); + Name.EndLocation = RSquareLoc; + + // Allocate storage for bindings and stash them away. + if (Bindings.size()) { + if (!InlineStorageUsed && + Bindings.size() <= llvm::array_lengthof(InlineBindings)) { + BindingGroup.Bindings = InlineBindings; + BindingGroup.DeleteBindings = false; + InlineStorageUsed = true; + } else { + BindingGroup.Bindings = + new DecompositionDeclarator::Binding[Bindings.size()]; + BindingGroup.DeleteBindings = true; + } + std::uninitialized_copy(Bindings.begin(), Bindings.end(), + BindingGroup.Bindings); + } +} + bool Declarator::isDeclarationOfFunction() const { for (unsigned i = 0, i_end = DeclTypeInfo.size(); i < i_end; ++i) { switch (DeclTypeInfo[i].Kind) { @@ -511,7 +558,7 @@ bool DeclSpec::SetStorageClassSpec(Sema &S, SCS SC, SourceLocation Loc, // OpenCL v1.2 s6.8 changes this to "The auto and register storage-class // specifiers are not supported." if (S.getLangOpts().OpenCL && - !S.getOpenCLOptions().cl_clang_storage_class_specifiers) { + !S.getOpenCLOptions().isEnabled("cl_clang_storage_class_specifiers")) { switch (SC) { case SCS_extern: case SCS_private_extern: @@ -578,14 +625,16 @@ bool DeclSpec::SetTypeSpecWidth(TSW W, SourceLocation Loc, const char *&PrevSpec, unsigned &DiagID, const PrintingPolicy &Policy) { - // Overwrite TSWLoc only if TypeSpecWidth was unspecified, so that + // Overwrite TSWRange.Begin only if TypeSpecWidth was unspecified, so that // for 'long long' we will keep the source location of the first 'long'. if (TypeSpecWidth == TSW_unspecified) - TSWLoc = Loc; + TSWRange.setBegin(Loc); // Allow turning long -> long long. else if (W != TSW_longlong || TypeSpecWidth != TSW_long) return BadSpecifier(W, (TSW)TypeSpecWidth, PrevSpec, DiagID); TypeSpecWidth = W; + // Remember location of the last 'long' + TSWRange.setEnd(Loc); return false; } @@ -965,9 +1014,9 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { TypeQualifiers)) { const unsigned NumLocs = 9; SourceLocation ExtraLocs[NumLocs] = { - TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, - TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc - }; + TSWRange.getBegin(), TSCLoc, TSSLoc, + AltiVecLoc, TQ_constLoc, TQ_restrictLoc, + TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc}; FixItHint Hints[NumLocs]; SourceLocation FirstLoc; for (unsigned I = 0; I != NumLocs; ++I) { @@ -1009,8 +1058,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) && (TypeSpecWidth != TSW_longlong)) - S.Diag(TSWLoc, diag::err_invalid_vector_bool_decl_spec) - << getSpecifierName((TSW)TypeSpecWidth); + S.Diag(TSWRange.getBegin(), diag::err_invalid_vector_bool_decl_spec) + << getSpecifierName((TSW)TypeSpecWidth); // vector bool long long requires VSX support or ZVector. if ((TypeSpecWidth == TSW_longlong) && @@ -1027,7 +1076,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { // vector long double and vector long long double are never allowed. // vector double is OK for Power7 and later, and ZVector. if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong) - S.Diag(TSWLoc, diag::err_invalid_vector_long_double_decl_spec); + S.Diag(TSWRange.getBegin(), + diag::err_invalid_vector_long_double_decl_spec); else if (!S.Context.getTargetInfo().hasFeature("vsx") && !S.getLangOpts().ZVector) S.Diag(TSTLoc, diag::err_invalid_vector_double_decl_spec); @@ -1038,10 +1088,11 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { } else if (TypeSpecWidth == TSW_long) { // vector long is unsupported for ZVector and deprecated for AltiVec. if (S.getLangOpts().ZVector) - S.Diag(TSWLoc, diag::err_invalid_vector_long_decl_spec); + S.Diag(TSWRange.getBegin(), diag::err_invalid_vector_long_decl_spec); else - S.Diag(TSWLoc, diag::warn_vector_long_decl_spec_combination) - << getSpecifierName((TST)TypeSpecType, Policy); + S.Diag(TSWRange.getBegin(), + diag::warn_vector_long_decl_spec_combination) + << getSpecifierName((TST)TypeSpecType, Policy); } if (TypeAltiVecPixel) { @@ -1074,8 +1125,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { - S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth - << getSpecifierName((TST)TypeSpecType, Policy); + S.Diag(TSWRange.getBegin(), diag::err_invalid_width_spec) + << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } @@ -1084,8 +1135,8 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { - S.Diag(TSWLoc, diag::err_invalid_width_spec) << (int)TypeSpecWidth - << getSpecifierName((TST)TypeSpecType, Policy); + S.Diag(TSWRange.getBegin(), diag::err_invalid_width_spec) + << (int)TypeSpecWidth << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } @@ -1267,6 +1318,7 @@ bool VirtSpecifiers::SetSpecifier(Specifier VS, SourceLocation Loc, switch (VS) { default: llvm_unreachable("Unknown specifier!"); case VS_Override: VS_overrideLoc = Loc; break; + case VS_GNU_Final: case VS_Sealed: case VS_Final: VS_finalLoc = Loc; break; } @@ -1279,6 +1331,7 @@ const char *VirtSpecifiers::getSpecifierName(Specifier VS) { default: llvm_unreachable("Unknown specifier"); case VS_Override: return "override"; case VS_Final: return "final"; + case VS_GNU_Final: return "__final"; case VS_Sealed: return "sealed"; } } diff --git a/lib/Sema/DelayedDiagnostic.cpp b/lib/Sema/DelayedDiagnostic.cpp index ceea04f276c97..2fa5718d4e9b5 100644 --- a/lib/Sema/DelayedDiagnostic.cpp +++ b/lib/Sema/DelayedDiagnostic.cpp @@ -20,7 +20,7 @@ using namespace clang; using namespace sema; DelayedDiagnostic -DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, +DelayedDiagnostic::makeAvailability(AvailabilityResult AR, SourceLocation Loc, const NamedDecl *D, const ObjCInterfaceDecl *UnknownObjCClass, @@ -28,42 +28,33 @@ DelayedDiagnostic::makeAvailability(Sema::AvailabilityDiagnostic AD, StringRef Msg, bool ObjCPropertyAccess) { DelayedDiagnostic DD; - switch (AD) { - case Sema::AD_Deprecation: - DD.Kind = Deprecation; - break; - case Sema::AD_Unavailable: - DD.Kind = Unavailable; - break; - case Sema::AD_Partial: - llvm_unreachable("AD_Partial diags should not be delayed"); - } + DD.Kind = Availability; DD.Triggered = false; DD.Loc = Loc; - DD.DeprecationData.Decl = D; - DD.DeprecationData.UnknownObjCClass = UnknownObjCClass; - DD.DeprecationData.ObjCProperty = ObjCProperty; + DD.AvailabilityData.Decl = D; + DD.AvailabilityData.UnknownObjCClass = UnknownObjCClass; + DD.AvailabilityData.ObjCProperty = ObjCProperty; char *MessageData = nullptr; if (Msg.size()) { MessageData = new char [Msg.size()]; memcpy(MessageData, Msg.data(), Msg.size()); } - DD.DeprecationData.Message = MessageData; - DD.DeprecationData.MessageLen = Msg.size(); - DD.DeprecationData.ObjCPropertyAccess = ObjCPropertyAccess; + DD.AvailabilityData.Message = MessageData; + DD.AvailabilityData.MessageLen = Msg.size(); + DD.AvailabilityData.AR = AR; + DD.AvailabilityData.ObjCPropertyAccess = ObjCPropertyAccess; return DD; } void DelayedDiagnostic::Destroy() { - switch (static_cast<DDKind>(Kind)) { + switch (Kind) { case Access: getAccessData().~AccessedEntity(); break; - case Deprecation: - case Unavailable: - delete [] DeprecationData.Message; + case Availability: + delete[] AvailabilityData.Message; break; case ForbiddenType: diff --git a/lib/Sema/JumpDiagnostics.cpp b/lib/Sema/JumpDiagnostics.cpp index bdbe06c4969d0..899d3fa83cc3c 100644 --- a/lib/Sema/JumpDiagnostics.cpp +++ b/lib/Sema/JumpDiagnostics.cpp @@ -325,30 +325,27 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, case Stmt::IfStmtClass: { IfStmt *IS = cast<IfStmt>(S); - if (!IS->isConstexpr()) + if (!(IS->isConstexpr() || IS->isObjCAvailabilityCheck())) break; + unsigned Diag = IS->isConstexpr() ? diag::note_protected_by_constexpr_if + : diag::note_protected_by_if_available; + if (VarDecl *Var = IS->getConditionVariable()) BuildScopeInformation(Var, ParentScope); // Cannot jump into the middle of the condition. unsigned NewParentScope = Scopes.size(); - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_constexpr_if, 0, - IS->getLocStart())); + Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart())); BuildScopeInformation(IS->getCond(), NewParentScope); // Jumps into either arm of an 'if constexpr' are not allowed. NewParentScope = Scopes.size(); - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_constexpr_if, 0, - IS->getLocStart())); + Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart())); BuildScopeInformation(IS->getThen(), NewParentScope); if (Stmt *Else = IS->getElse()) { NewParentScope = Scopes.size(); - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_constexpr_if, 0, - IS->getLocStart())); + Scopes.push_back(GotoScope(ParentScope, Diag, 0, IS->getLocStart())); BuildScopeInformation(Else, NewParentScope); } return; @@ -553,10 +550,8 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, // order to avoid blowing out the stack. while (true) { Stmt *Next; - if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt)) - Next = CS->getSubStmt(); - else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt)) - Next = DS->getSubStmt(); + if (SwitchCase *SC = dyn_cast<SwitchCase>(SubStmt)) + Next = SC->getSubStmt(); else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) Next = LS->getSubStmt(); else diff --git a/lib/Sema/MultiplexExternalSemaSource.cpp b/lib/Sema/MultiplexExternalSemaSource.cpp index eee4c00324baf..077a56ff8e7ff 100644 --- a/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/lib/Sema/MultiplexExternalSemaSource.cpp @@ -285,7 +285,8 @@ void MultiplexExternalSemaSource::ReadPendingInstantiations( } void MultiplexExternalSemaSource::ReadLateParsedTemplates( - llvm::MapVector<const FunctionDecl *, LateParsedTemplate *> &LPTMap) { + llvm::MapVector<const FunctionDecl *, std::unique_ptr<LateParsedTemplate>> + &LPTMap) { for (size_t i = 0; i < Sources.size(); ++i) Sources[i]->ReadLateParsedTemplates(LPTMap); } diff --git a/lib/Sema/ScopeInfo.cpp b/lib/Sema/ScopeInfo.cpp index 4b2e13e20deb7..3970b4136982f 100644 --- a/lib/Sema/ScopeInfo.cpp +++ b/lib/Sema/ScopeInfo.cpp @@ -29,6 +29,8 @@ void FunctionScopeInfo::Clear() { HasIndirectGoto = false; HasDroppedStmt = false; HasOMPDeclareReductionCombiner = false; + HasFallthroughStmt = false; + HasPotentialAvailabilityViolations = false; ObjCShouldCallSuper = false; ObjCIsDesignatedInit = false; ObjCWarnForNoDesignatedInitChain = false; diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 7777476063041..412f944f89c08 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTDiagnostic.h" #include "clang/AST/DeclCXX.h" @@ -22,7 +21,6 @@ #include "clang/AST/ExprCXX.h" #include "clang/AST/StmtCXX.h" #include "clang/Basic/DiagnosticOptions.h" -#include "clang/Basic/FileManager.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/HeaderSearch.h" @@ -30,14 +28,15 @@ #include "clang/Sema/CXXFieldCollector.h" #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/MultiplexExternalSemaSource.h" #include "clang/Sema/ObjCMethodList.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaConsumer.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/TemplateDeduction.h" -#include "llvm/ADT/APFloat.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallSet.h" using namespace clang; @@ -89,15 +88,14 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, VisContext(nullptr), IsBuildingRecoveryCallExpr(false), Cleanup{}, LateTemplateParser(nullptr), - LateTemplateParserCleanup(nullptr), - OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), + LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), + StdExperimentalNamespaceCache(nullptr), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), NSNumberDecl(nullptr), NSValueDecl(nullptr), NSStringDecl(nullptr), StringWithUTF8StringMethod(nullptr), ValueWithBytesObjCTypeMethod(nullptr), NSArrayDecl(nullptr), ArrayWithObjectsMethod(nullptr), NSDictionaryDecl(nullptr), DictionaryWithObjectsMethod(nullptr), - MSAsmLabelNameCounter(0), GlobalNewDeleteDeclared(false), TUKind(TUKind), NumSFINAEErrors(0), @@ -209,14 +207,11 @@ void Sema::Initialize() { addImplicitTypedef("size_t", Context.getSizeType()); } - // Initialize predefined OpenCL types and supported optional core features. + // Initialize predefined OpenCL types and supported extensions and (optional) + // core features. if (getLangOpts().OpenCL) { -#define OPENCLEXT(Ext) \ - if (Context.getTargetInfo().getSupportedOpenCLOpts().is_##Ext##_supported_core( \ - getLangOpts().OpenCLVersion)) \ - getOpenCLOptions().Ext = 1; -#include "clang/Basic/OpenCLExtensions.def" - + getOpenCLOptions().addSupport(Context.getTargetInfo().getSupportedOpenCLOpts()); + getOpenCLOptions().enableSupportedCore(getLangOpts().OpenCLVersion); addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); if (getLangOpts().OpenCLVersion >= 200) { @@ -227,26 +222,60 @@ void Sema::Initialize() { addImplicitTypedef("atomic_int", Context.getAtomicType(Context.IntTy)); addImplicitTypedef("atomic_uint", Context.getAtomicType(Context.UnsignedIntTy)); - addImplicitTypedef("atomic_long", Context.getAtomicType(Context.LongTy)); - addImplicitTypedef("atomic_ulong", - Context.getAtomicType(Context.UnsignedLongTy)); + auto AtomicLongT = Context.getAtomicType(Context.LongTy); + addImplicitTypedef("atomic_long", AtomicLongT); + auto AtomicULongT = Context.getAtomicType(Context.UnsignedLongTy); + addImplicitTypedef("atomic_ulong", AtomicULongT); addImplicitTypedef("atomic_float", Context.getAtomicType(Context.FloatTy)); - addImplicitTypedef("atomic_double", - Context.getAtomicType(Context.DoubleTy)); + auto AtomicDoubleT = Context.getAtomicType(Context.DoubleTy); + addImplicitTypedef("atomic_double", AtomicDoubleT); // OpenCLC v2.0, s6.13.11.6 requires that atomic_flag is implemented as // 32-bit integer and OpenCLC v2.0, s6.1.1 int is always 32-bit wide. addImplicitTypedef("atomic_flag", Context.getAtomicType(Context.IntTy)); - addImplicitTypedef("atomic_intptr_t", - Context.getAtomicType(Context.getIntPtrType())); - addImplicitTypedef("atomic_uintptr_t", - Context.getAtomicType(Context.getUIntPtrType())); - addImplicitTypedef("atomic_size_t", - Context.getAtomicType(Context.getSizeType())); - addImplicitTypedef("atomic_ptrdiff_t", - Context.getAtomicType(Context.getPointerDiffType())); + auto AtomicIntPtrT = Context.getAtomicType(Context.getIntPtrType()); + addImplicitTypedef("atomic_intptr_t", AtomicIntPtrT); + auto AtomicUIntPtrT = Context.getAtomicType(Context.getUIntPtrType()); + addImplicitTypedef("atomic_uintptr_t", AtomicUIntPtrT); + auto AtomicSizeT = Context.getAtomicType(Context.getSizeType()); + addImplicitTypedef("atomic_size_t", AtomicSizeT); + auto AtomicPtrDiffT = Context.getAtomicType(Context.getPointerDiffType()); + addImplicitTypedef("atomic_ptrdiff_t", AtomicPtrDiffT); + + // OpenCL v2.0 s6.13.11.6: + // - The atomic_long and atomic_ulong types are supported if the + // cl_khr_int64_base_atomics and cl_khr_int64_extended_atomics + // extensions are supported. + // - The atomic_double type is only supported if double precision + // is supported and the cl_khr_int64_base_atomics and + // cl_khr_int64_extended_atomics extensions are supported. + // - If the device address space is 64-bits, the data types + // atomic_intptr_t, atomic_uintptr_t, atomic_size_t and + // atomic_ptrdiff_t are supported if the cl_khr_int64_base_atomics and + // cl_khr_int64_extended_atomics extensions are supported. + std::vector<QualType> Atomic64BitTypes; + Atomic64BitTypes.push_back(AtomicLongT); + Atomic64BitTypes.push_back(AtomicULongT); + Atomic64BitTypes.push_back(AtomicDoubleT); + if (Context.getTypeSize(AtomicSizeT) == 64) { + Atomic64BitTypes.push_back(AtomicSizeT); + Atomic64BitTypes.push_back(AtomicIntPtrT); + Atomic64BitTypes.push_back(AtomicUIntPtrT); + Atomic64BitTypes.push_back(AtomicPtrDiffT); + } + for (auto &I : Atomic64BitTypes) + setOpenCLExtensionForType(I, + "cl_khr_int64_base_atomics cl_khr_int64_extended_atomics"); + + setOpenCLExtensionForType(AtomicDoubleT, "cl_khr_fp64"); } - } + + setOpenCLExtensionForType(Context.DoubleTy, "cl_khr_fp64"); + +#define GENERIC_IMAGE_TYPE_EXT(Type, Id, Ext) \ + setOpenCLExtensionForType(Context.Id, Ext); +#include "clang/Basic/OpenCLImageTypes.def" + }; if (Context.getTargetInfo().hasBuiltinMSVaList()) { DeclarationName MSVaList = &Context.Idents.get("__builtin_ms_va_list"); @@ -260,7 +289,6 @@ void Sema::Initialize() { } Sema::~Sema() { - llvm::DeleteContainerSeconds(LateParsedTemplateMap); if (VisContext) FreeVisContext(); // Kill all the active scopes. for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) @@ -393,6 +421,18 @@ ExprResult Sema::ImpCastExprToType(Expr *E, QualType Ty, if (ExprTy == TypeTy) return E; + // C++1z [conv.array]: The temporary materialization conversion is applied. + // We also use this to fuel C++ DR1213, which applies to C++11 onwards. + if (Kind == CK_ArrayToPointerDecay && getLangOpts().CPlusPlus && + E->getValueKind() == VK_RValue) { + // The temporary is an lvalue in C++98 and an xvalue otherwise. + ExprResult Materialized = CreateMaterializeTemporaryExpr( + E->getType(), E, !getLangOpts().CPlusPlus11); + if (Materialized.isInvalid()) + return ExprError(); + E = Materialized.get(); + } + if (ImplicitCastExpr *ImpCast = dyn_cast<ImplicitCastExpr>(E)) { if (ImpCast->getCastKind() == Kind && (!BasePath || BasePath->empty())) { ImpCast->setType(Ty); @@ -710,7 +750,8 @@ void Sema::ActOnEndOfTranslationUnit() { if (TUKind == TU_Prefix) { // Translation unit prefixes don't need any of the checking below. - TUScope = nullptr; + if (!PP.isIncrementalProcessingEnabled()) + TUScope = nullptr; return; } @@ -811,6 +852,7 @@ void Sema::ActOnEndOfTranslationUnit() { diag::err_tentative_def_incomplete_type)) VD->setInvalidDecl(); + // No initialization is performed for a tentative definition. CheckCompleteVariableDeclaration(VD); // Notify the consumer that we've completed a tentative definition. @@ -865,8 +907,11 @@ void Sema::ActOnEndOfTranslationUnit() { Diag(DiagD->getLocation(), diag::warn_unneeded_internal_decl) << /*variable*/1 << DiagD->getDeclName(); } else if (DiagD->getType().isConstQualified()) { - Diag(DiagD->getLocation(), diag::warn_unused_const_variable) - << DiagD->getDeclName(); + const SourceManager &SM = SourceMgr; + if (SM.getMainFileID() != SM.getFileID(DiagD->getLocation()) || + !PP.getLangOpts().IsHeaderFile) + Diag(DiagD->getLocation(), diag::warn_unused_const_variable) + << DiagD->getDeclName(); } else { Diag(DiagD->getLocation(), diag::warn_unused_variable) << DiagD->getDeclName(); @@ -909,7 +954,8 @@ void Sema::ActOnEndOfTranslationUnit() { assert(ParsingInitForAutoVars.empty() && "Didn't unmark var as having its initializer parsed"); - TUScope = nullptr; + if (!PP.isIncrementalProcessingEnabled()) + TUScope = nullptr; } @@ -1527,3 +1573,85 @@ const llvm::MapVector<FieldDecl *, Sema::DeleteLocs> & Sema::getMismatchingDeleteExpressions() const { return DeleteExprs; } + +void Sema::setOpenCLExtensionForType(QualType T, llvm::StringRef ExtStr) { + if (ExtStr.empty()) + return; + llvm::SmallVector<StringRef, 1> Exts; + ExtStr.split(Exts, " ", /* limit */ -1, /* keep empty */ false); + auto CanT = T.getCanonicalType().getTypePtr(); + for (auto &I : Exts) + OpenCLTypeExtMap[CanT].insert(I.str()); +} + +void Sema::setOpenCLExtensionForDecl(Decl *FD, StringRef ExtStr) { + llvm::SmallVector<StringRef, 1> Exts; + ExtStr.split(Exts, " ", /* limit */ -1, /* keep empty */ false); + if (Exts.empty()) + return; + for (auto &I : Exts) + OpenCLDeclExtMap[FD].insert(I.str()); +} + +void Sema::setCurrentOpenCLExtensionForType(QualType T) { + if (CurrOpenCLExtension.empty()) + return; + setOpenCLExtensionForType(T, CurrOpenCLExtension); +} + +void Sema::setCurrentOpenCLExtensionForDecl(Decl *D) { + if (CurrOpenCLExtension.empty()) + return; + setOpenCLExtensionForDecl(D, CurrOpenCLExtension); +} + +bool Sema::isOpenCLDisabledDecl(Decl *FD) { + auto Loc = OpenCLDeclExtMap.find(FD); + if (Loc == OpenCLDeclExtMap.end()) + return false; + for (auto &I : Loc->second) { + if (!getOpenCLOptions().isEnabled(I)) + return true; + } + return false; +} + +template <typename T, typename DiagLocT, typename DiagInfoT, typename MapT> +bool Sema::checkOpenCLDisabledTypeOrDecl(T D, DiagLocT DiagLoc, + DiagInfoT DiagInfo, MapT &Map, + unsigned Selector, + SourceRange SrcRange) { + auto Loc = Map.find(D); + if (Loc == Map.end()) + return false; + bool Disabled = false; + for (auto &I : Loc->second) { + if (I != CurrOpenCLExtension && !getOpenCLOptions().isEnabled(I)) { + Diag(DiagLoc, diag::err_opencl_requires_extension) << Selector << DiagInfo + << I << SrcRange; + Disabled = true; + } + } + return Disabled; +} + +bool Sema::checkOpenCLDisabledTypeDeclSpec(const DeclSpec &DS, QualType QT) { + // Check extensions for declared types. + Decl *Decl = nullptr; + if (auto TypedefT = dyn_cast<TypedefType>(QT.getTypePtr())) + Decl = TypedefT->getDecl(); + if (auto TagT = dyn_cast<TagType>(QT.getCanonicalType().getTypePtr())) + Decl = TagT->getDecl(); + auto Loc = DS.getTypeSpecTypeLoc(); + if (checkOpenCLDisabledTypeOrDecl(Decl, Loc, QT, OpenCLDeclExtMap)) + return true; + + // Check extensions for builtin types. + return checkOpenCLDisabledTypeOrDecl(QT.getCanonicalType().getTypePtr(), Loc, + QT, OpenCLTypeExtMap); +} + +bool Sema::checkOpenCLDisabledDecl(const Decl &D, const Expr &E) { + return checkOpenCLDisabledTypeOrDecl(&D, E.getLocStart(), "", + OpenCLDeclExtMap, 1, D.getSourceRange()); +} diff --git a/lib/Sema/SemaAttr.cpp b/lib/Sema/SemaAttr.cpp index 0d7fba5c6709f..bad9e7024267b 100644 --- a/lib/Sema/SemaAttr.cpp +++ b/lib/Sema/SemaAttr.cpp @@ -12,13 +12,13 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" using namespace clang; //===----------------------------------------------------------------------===// diff --git a/lib/Sema/SemaCUDA.cpp b/lib/Sema/SemaCUDA.cpp index 90af6d5a927ff..6f272ec839f53 100644 --- a/lib/Sema/SemaCUDA.cpp +++ b/lib/Sema/SemaCUDA.cpp @@ -18,11 +18,25 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" using namespace clang; +void Sema::PushForceCUDAHostDevice() { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + ForceCUDAHostDeviceDepth++; +} + +bool Sema::PopForceCUDAHostDevice() { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + if (ForceCUDAHostDeviceDepth == 0) + return false; + ForceCUDAHostDeviceDepth--; + return true; +} + ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, MultiExprArg ExecConfig, SourceLocation GGGLoc) { @@ -40,21 +54,73 @@ ExprResult Sema::ActOnCUDAExecConfigExpr(Scope *S, SourceLocation LLLLoc, /*IsExecConfig=*/true); } +Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const AttributeList *Attr) { + bool HasHostAttr = false; + bool HasDeviceAttr = false; + bool HasGlobalAttr = false; + bool HasInvalidTargetAttr = false; + while (Attr) { + switch(Attr->getKind()){ + case AttributeList::AT_CUDAGlobal: + HasGlobalAttr = true; + break; + case AttributeList::AT_CUDAHost: + HasHostAttr = true; + break; + case AttributeList::AT_CUDADevice: + HasDeviceAttr = true; + break; + case AttributeList::AT_CUDAInvalidTarget: + HasInvalidTargetAttr = true; + break; + default: + break; + } + Attr = Attr->getNext(); + } + if (HasInvalidTargetAttr) + return CFT_InvalidTarget; + + if (HasGlobalAttr) + return CFT_Global; + + if (HasHostAttr && HasDeviceAttr) + return CFT_HostDevice; + + if (HasDeviceAttr) + return CFT_Device; + + return CFT_Host; +} + +template <typename A> +static bool hasAttr(const FunctionDecl *D, bool IgnoreImplicitAttr) { + return D->hasAttrs() && llvm::any_of(D->getAttrs(), [&](Attr *Attribute) { + return isa<A>(Attribute) && + !(IgnoreImplicitAttr && Attribute->isImplicit()); + }); +} + /// IdentifyCUDATarget - Determine the CUDA compilation target for this function -Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { +Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D, + bool IgnoreImplicitHDAttr) { + // Code that lives outside a function is run on the host. + if (D == nullptr) + return CFT_Host; + if (D->hasAttr<CUDAInvalidTargetAttr>()) return CFT_InvalidTarget; if (D->hasAttr<CUDAGlobalAttr>()) return CFT_Global; - if (D->hasAttr<CUDADeviceAttr>()) { - if (D->hasAttr<CUDAHostAttr>()) + if (hasAttr<CUDADeviceAttr>(D, IgnoreImplicitHDAttr)) { + if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) return CFT_HostDevice; return CFT_Device; - } else if (D->hasAttr<CUDAHostAttr>()) { + } else if (hasAttr<CUDAHostAttr>(D, IgnoreImplicitHDAttr)) { return CFT_Host; - } else if (D->isImplicit()) { + } else if (D->isImplicit() && !IgnoreImplicitHDAttr) { // Some implicit declarations (like intrinsic functions) are not marked. // Set the most lenient target on them for maximal flexibility. return CFT_HostDevice; @@ -95,9 +161,8 @@ Sema::CUDAFunctionPreference Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee) { assert(Callee && "Callee must be valid."); + CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller); CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee); - CUDAFunctionTarget CallerTarget = - (Caller != nullptr) ? IdentifyCUDATarget(Caller) : Sema::CFT_Host; // If one of the targets is invalid, the check always fails, no matter what // the other target is. @@ -107,8 +172,7 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, // (a) Can't call global from some contexts until we support CUDA's // dynamic parallelism. if (CalleeTarget == CFT_Global && - (CallerTarget == CFT_Global || CallerTarget == CFT_Device || - (CallerTarget == CFT_HostDevice && getLangOpts().CUDAIsDevice))) + (CallerTarget == CFT_Global || CallerTarget == CFT_Device)) return CFP_Never; // (b) Calling HostDevice is OK for everyone. @@ -145,54 +209,31 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, llvm_unreachable("All cases should've been handled by now."); } -template <typename T> -static void EraseUnwantedCUDAMatchesImpl( - Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches, - std::function<const FunctionDecl *(const T &)> FetchDecl) { +void Sema::EraseUnwantedCUDAMatches( + const FunctionDecl *Caller, + SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches) { if (Matches.size() <= 1) return; + using Pair = std::pair<DeclAccessPair, FunctionDecl*>; + // Gets the CUDA function preference for a call from Caller to Match. - auto GetCFP = [&](const T &Match) { - return S.IdentifyCUDAPreference(Caller, FetchDecl(Match)); + auto GetCFP = [&](const Pair &Match) { + return IdentifyCUDAPreference(Caller, Match.second); }; // Find the best call preference among the functions in Matches. - Sema::CUDAFunctionPreference BestCFP = GetCFP(*std::max_element( + CUDAFunctionPreference BestCFP = GetCFP(*std::max_element( Matches.begin(), Matches.end(), - [&](const T &M1, const T &M2) { return GetCFP(M1) < GetCFP(M2); })); + [&](const Pair &M1, const Pair &M2) { return GetCFP(M1) < GetCFP(M2); })); // Erase all functions with lower priority. Matches.erase( - llvm::remove_if(Matches, - [&](const T &Match) { return GetCFP(Match) < BestCFP; }), + llvm::remove_if( + Matches, [&](const Pair &Match) { return GetCFP(Match) < BestCFP; }), Matches.end()); } -void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller, - SmallVectorImpl<FunctionDecl *> &Matches){ - EraseUnwantedCUDAMatchesImpl<FunctionDecl *>( - *this, Caller, Matches, [](const FunctionDecl *item) { return item; }); -} - -void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller, - SmallVectorImpl<DeclAccessPair> &Matches) { - EraseUnwantedCUDAMatchesImpl<DeclAccessPair>( - *this, Caller, Matches, [](const DeclAccessPair &item) { - return dyn_cast<FunctionDecl>(item.getDecl()); - }); -} - -void Sema::EraseUnwantedCUDAMatches( - const FunctionDecl *Caller, - SmallVectorImpl<std::pair<DeclAccessPair, FunctionDecl *>> &Matches){ - EraseUnwantedCUDAMatchesImpl<std::pair<DeclAccessPair, FunctionDecl *>>( - *this, Caller, Matches, - [](const std::pair<DeclAccessPair, FunctionDecl *> &item) { - return dyn_cast<FunctionDecl>(item.second); - }); -} - /// When an implicitly-declared special member has to invoke more than one /// base/field special member, conflicts may occur in the targets of these /// members. For example, if one base's member __host__ and another's is @@ -441,9 +482,23 @@ bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { // * a __device__ function with this signature was already declared, in which // case in which case we output an error, unless the __device__ decl is in a // system header, in which case we leave the constexpr function unattributed. -void Sema::maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *NewD, +// +// In addition, all function decls are treated as __host__ __device__ when +// ForceCUDAHostDeviceDepth > 0 (corresponding to code within a +// #pragma clang force_cuda_host_device_begin/end +// pair). +void Sema::maybeAddCUDAHostDeviceAttrs(FunctionDecl *NewD, const LookupResult &Previous) { - assert(getLangOpts().CUDA && "May be called only for CUDA compilations."); + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + + if (ForceCUDAHostDeviceDepth > 0) { + if (!NewD->hasAttr<CUDAHostAttr>()) + NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); + if (!NewD->hasAttr<CUDADeviceAttr>()) + NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); + return; + } + if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() || NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() || NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>()) @@ -480,3 +535,378 @@ void Sema::maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *NewD, NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); } + +// In CUDA, there are some constructs which may appear in semantically-valid +// code, but trigger errors if we ever generate code for the function in which +// they appear. Essentially every construct you're not allowed to use on the +// device falls into this category, because you are allowed to use these +// constructs in a __host__ __device__ function, but only if that function is +// never codegen'ed on the device. +// +// To handle semantic checking for these constructs, we keep track of the set of +// functions we know will be emitted, either because we could tell a priori that +// they would be emitted, or because they were transitively called by a +// known-emitted function. +// +// We also keep a partial call graph of which not-known-emitted functions call +// which other not-known-emitted functions. +// +// When we see something which is illegal if the current function is emitted +// (usually by way of CUDADiagIfDeviceCode, CUDADiagIfHostCode, or +// CheckCUDACall), we first check if the current function is known-emitted. If +// so, we immediately output the diagnostic. +// +// Otherwise, we "defer" the diagnostic. It sits in Sema::CUDADeferredDiags +// until we discover that the function is known-emitted, at which point we take +// it out of this map and emit the diagnostic. + +Sema::CUDADiagBuilder::CUDADiagBuilder(Kind K, SourceLocation Loc, + unsigned DiagID, FunctionDecl *Fn, + Sema &S) + : S(S), Loc(Loc), DiagID(DiagID), Fn(Fn), + ShowCallStack(K == K_ImmediateWithCallStack || K == K_Deferred) { + switch (K) { + case K_Nop: + break; + case K_Immediate: + case K_ImmediateWithCallStack: + ImmediateDiag.emplace(S.Diag(Loc, DiagID)); + break; + case K_Deferred: + assert(Fn && "Must have a function to attach the deferred diag to."); + PartialDiag.emplace(S.PDiag(DiagID)); + break; + } +} + +// Print notes showing how we can reach FD starting from an a priori +// known-callable function. +static void EmitCallStackNotes(Sema &S, FunctionDecl *FD) { + auto FnIt = S.CUDAKnownEmittedFns.find(FD); + while (FnIt != S.CUDAKnownEmittedFns.end()) { + DiagnosticBuilder Builder( + S.Diags.Report(FnIt->second.Loc, diag::note_called_by)); + Builder << FnIt->second.FD; + Builder.setForceEmit(); + + FnIt = S.CUDAKnownEmittedFns.find(FnIt->second.FD); + } +} + +Sema::CUDADiagBuilder::~CUDADiagBuilder() { + if (ImmediateDiag) { + // Emit our diagnostic and, if it was a warning or error, output a callstack + // if Fn isn't a priori known-emitted. + bool IsWarningOrError = S.getDiagnostics().getDiagnosticLevel( + DiagID, Loc) >= DiagnosticsEngine::Warning; + ImmediateDiag.reset(); // Emit the immediate diag. + if (IsWarningOrError && ShowCallStack) + EmitCallStackNotes(S, Fn); + } else if (PartialDiag) { + assert(ShowCallStack && "Must always show call stack for deferred diags."); + S.CUDADeferredDiags[Fn].push_back({Loc, std::move(*PartialDiag)}); + } +} + +// Do we know that we will eventually codegen the given function? +static bool IsKnownEmitted(Sema &S, FunctionDecl *FD) { + // Templates are emitted when they're instantiated. + if (FD->isDependentContext()) + return false; + + // When compiling for device, host functions are never emitted. Similarly, + // when compiling for host, device and global functions are never emitted. + // (Technically, we do emit a host-side stub for global functions, but this + // doesn't count for our purposes here.) + Sema::CUDAFunctionTarget T = S.IdentifyCUDATarget(FD); + if (S.getLangOpts().CUDAIsDevice && T == Sema::CFT_Host) + return false; + if (!S.getLangOpts().CUDAIsDevice && + (T == Sema::CFT_Device || T == Sema::CFT_Global)) + return false; + + // Check whether this function is externally visible -- if so, it's + // known-emitted. + // + // We have to check the GVA linkage of the function's *definition* -- if we + // only have a declaration, we don't know whether or not the function will be + // emitted, because (say) the definition could include "inline". + FunctionDecl *Def = FD->getDefinition(); + + // We may currently be parsing the body of FD, in which case + // FD->getDefinition() will be null, but we still want to treat FD as though + // it's a definition. + if (!Def && FD->willHaveBody()) + Def = FD; + + if (Def && + !isDiscardableGVALinkage(S.getASTContext().GetGVALinkageForFunction(Def))) + return true; + + // Otherwise, the function is known-emitted if it's in our set of + // known-emitted functions. + return S.CUDAKnownEmittedFns.count(FD) > 0; +} + +Sema::CUDADiagBuilder Sema::CUDADiagIfDeviceCode(SourceLocation Loc, + unsigned DiagID) { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + CUDADiagBuilder::Kind DiagKind = [&] { + switch (CurrentCUDATarget()) { + case CFT_Global: + case CFT_Device: + return CUDADiagBuilder::K_Immediate; + case CFT_HostDevice: + // An HD function counts as host code if we're compiling for host, and + // device code if we're compiling for device. Defer any errors in device + // mode until the function is known-emitted. + if (getLangOpts().CUDAIsDevice) { + return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) + ? CUDADiagBuilder::K_ImmediateWithCallStack + : CUDADiagBuilder::K_Deferred; + } + return CUDADiagBuilder::K_Nop; + + default: + return CUDADiagBuilder::K_Nop; + } + }(); + return CUDADiagBuilder(DiagKind, Loc, DiagID, + dyn_cast<FunctionDecl>(CurContext), *this); +} + +Sema::CUDADiagBuilder Sema::CUDADiagIfHostCode(SourceLocation Loc, + unsigned DiagID) { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + CUDADiagBuilder::Kind DiagKind = [&] { + switch (CurrentCUDATarget()) { + case CFT_Host: + return CUDADiagBuilder::K_Immediate; + case CFT_HostDevice: + // An HD function counts as host code if we're compiling for host, and + // device code if we're compiling for device. Defer any errors in device + // mode until the function is known-emitted. + if (getLangOpts().CUDAIsDevice) + return CUDADiagBuilder::K_Nop; + + return IsKnownEmitted(*this, dyn_cast<FunctionDecl>(CurContext)) + ? CUDADiagBuilder::K_ImmediateWithCallStack + : CUDADiagBuilder::K_Deferred; + default: + return CUDADiagBuilder::K_Nop; + } + }(); + return CUDADiagBuilder(DiagKind, Loc, DiagID, + dyn_cast<FunctionDecl>(CurContext), *this); +} + +// Emit any deferred diagnostics for FD and erase them from the map in which +// they're stored. +static void EmitDeferredDiags(Sema &S, FunctionDecl *FD) { + auto It = S.CUDADeferredDiags.find(FD); + if (It == S.CUDADeferredDiags.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); + } + S.CUDADeferredDiags.erase(It); + + // 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) + EmitCallStackNotes(S, FD); +} + +// 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. +static void MarkKnownEmitted(Sema &S, FunctionDecl *OrigCaller, + FunctionDecl *OrigCallee, SourceLocation OrigLoc) { + // Nothing to do if we already know that FD is emitted. + if (IsKnownEmitted(S, OrigCallee)) { + assert(!S.CUDACallGraph.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.CUDAKnownEmittedFns[C.Callee] = {C.Caller, C.Loc}; + EmitDeferredDiags(S, C.Callee); + + // 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.CUDAKnownEmittedFns.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.CUDACallGraph.find(C.Callee); + if (CGIt == S.CUDACallGraph.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 CUDACallGraph. + S.CUDACallGraph.erase(CGIt); + } +} + +bool Sema::CheckCUDACall(SourceLocation Loc, FunctionDecl *Callee) { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + assert(Callee && "Callee may not be null."); + // FIXME: Is bailing out early correct here? Should we instead assume that + // the caller is a global initializer? + FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext); + if (!Caller) + return true; + + // 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. + bool CallerKnownEmitted = IsKnownEmitted(*this, Caller); + if (CallerKnownEmitted) + MarkKnownEmitted(*this, Caller, Callee, Loc); + 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 (getLangOpts().CUDAIsDevice || IdentifyCUDATarget(Callee) != CFT_Global) + CUDACallGraph[Caller].insert({Callee, Loc}); + } + + CUDADiagBuilder::Kind DiagKind = [&] { + switch (IdentifyCUDAPreference(Caller, Callee)) { + case CFP_Never: + return CUDADiagBuilder::K_Immediate; + case CFP_WrongSide: + assert(Caller && "WrongSide calls require a non-null caller"); + // If we know the caller will be emitted, we know this wrong-side call + // will be emitted, so it's an immediate error. Otherwise, defer the + // error until we know the caller is emitted. + return CallerKnownEmitted ? CUDADiagBuilder::K_ImmediateWithCallStack + : CUDADiagBuilder::K_Deferred; + default: + return CUDADiagBuilder::K_Nop; + } + }(); + + if (DiagKind == CUDADiagBuilder::K_Nop) + return true; + + // Avoid emitting this error twice for the same location. Using a hashtable + // like this is unfortunate, but because we must continue parsing as normal + // after encountering a deferred error, it's otherwise very tricky for us to + // ensure that we only emit this deferred error once. + if (!LocsWithCUDACallDiags.insert({Caller, Loc}).second) + return true; + + CUDADiagBuilder(DiagKind, Loc, diag::err_ref_bad_target, Caller, *this) + << IdentifyCUDATarget(Callee) << Callee << IdentifyCUDATarget(Caller); + CUDADiagBuilder(DiagKind, Callee->getLocation(), diag::note_previous_decl, + Caller, *this) + << Callee; + return DiagKind != CUDADiagBuilder::K_Immediate && + DiagKind != CUDADiagBuilder::K_ImmediateWithCallStack; +} + +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)); + } +} + +void Sema::checkCUDATargetOverload(FunctionDecl *NewFD, + const LookupResult &Previous) { + assert(getLangOpts().CUDA && "Should only be called during CUDA compilation"); + CUDAFunctionTarget NewTarget = IdentifyCUDATarget(NewFD); + for (NamedDecl *OldND : Previous) { + FunctionDecl *OldFD = OldND->getAsFunction(); + if (!OldFD) + continue; + + CUDAFunctionTarget OldTarget = IdentifyCUDATarget(OldFD); + // Don't allow HD and global functions to overload other functions with the + // same signature. We allow overloading based on CUDA attributes so that + // functions can have different implementations on the host and device, but + // HD/global functions "exist" in some sense on both the host and device, so + // should have the same implementation on both sides. + if (NewTarget != OldTarget && + ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice) || + (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) && + !IsOverload(NewFD, OldFD, /* UseMemberUsingDeclRules = */ false, + /* ConsiderCudaAttrs = */ false)) { + Diag(NewFD->getLocation(), diag::err_cuda_ovl_target) + << NewTarget << NewFD->getDeclName() << OldTarget << OldFD; + Diag(OldFD->getLocation(), diag::note_previous_declaration); + NewFD->setInvalidDecl(); + break; + } + } +} + +template <typename AttrTy> +static void copyAttrIfPresent(Sema &S, FunctionDecl *FD, + const FunctionDecl &TemplateFD) { + if (AttrTy *Attribute = TemplateFD.getAttr<AttrTy>()) { + AttrTy *Clone = Attribute->clone(S.Context); + Clone->setInherited(true); + FD->addAttr(Clone); + } +} + +void Sema::inheritCUDATargetAttrs(FunctionDecl *FD, + const FunctionTemplateDecl &TD) { + const FunctionDecl &TemplateFD = *TD.getTemplatedDecl(); + copyAttrIfPresent<CUDAGlobalAttr>(*this, FD, TemplateFD); + copyAttrIfPresent<CUDAHostAttr>(*this, FD, TemplateFD); + copyAttrIfPresent<CUDADeviceAttr>(*this, FD, TemplateFD); +} diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 949263d24897b..d8971c0d37eba 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclTemplate.h" @@ -20,9 +19,9 @@ #include "clang/Basic/PartialDiagnostic.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/Support/raw_ostream.h" using namespace clang; /// \brief Find the current instantiation that associated with the given type. @@ -381,12 +380,11 @@ NamedDecl *Sema::FindFirstQualifierInScope(Scope *S, NestedNameSpecifier *NNS) { } bool Sema::isNonTypeNestedNameSpecifier(Scope *S, CXXScopeSpec &SS, - SourceLocation IdLoc, - IdentifierInfo &II, - ParsedType ObjectTypePtr) { - QualType ObjectType = GetTypeFromParser(ObjectTypePtr); - LookupResult Found(*this, &II, IdLoc, LookupNestedNameSpecifierName); - + NestedNameSpecInfo &IdInfo) { + QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); + LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, + LookupNestedNameSpecifierName); + // Determine where to perform name lookup DeclContext *LookupCtx = nullptr; bool isDependent = false; @@ -449,11 +447,8 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { /// by ActOnCXXNestedNameSpecifier. /// /// \param S Scope in which the nested-name-specifier occurs. -/// \param Identifier Identifier in the sequence "identifier" "::". -/// \param IdentifierLoc Location of the \p Identifier. -/// \param CCLoc Location of "::" following Identifier. -/// \param ObjectType Type of postfix expression if the nested-name-specifier -/// occurs in construct like: <tt>ptr->nns::f</tt>. +/// \param IdInfo Parser information about an identifier in the +/// nested-name-spec. /// \param EnteringContext If true, enter the context specified by the /// nested-name-specifier. /// \param SS Optional nested name specifier preceding the identifier. @@ -479,17 +474,15 @@ class NestedNameSpecifierValidatorCCC : public CorrectionCandidateCallback { /// dependent context, for example. Nor will it extend \p SS with the scope /// specifier. bool Sema::BuildCXXNestedNameSpecifier(Scope *S, - IdentifierInfo &Identifier, - SourceLocation IdentifierLoc, - SourceLocation CCLoc, - QualType ObjectType, + NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, NamedDecl *ScopeLookupResult, bool ErrorRecoveryLookup, bool *IsCorrectedToColon) { - LookupResult Found(*this, &Identifier, IdentifierLoc, + LookupResult Found(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, LookupNestedNameSpecifierName); + QualType ObjectType = GetTypeFromParser(IdInfo.ObjectType); // Determine where to perform name lookup DeclContext *LookupCtx = nullptr; @@ -574,7 +567,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // base object type or prior nested-name-specifier, so this // nested-name-specifier refers to an unknown specialization. Just build // a dependent nested-name-specifier. - SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } @@ -593,18 +586,19 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // allowed, suggest replacement to ':'. if (IsCorrectedToColon) { *IsCorrectedToColon = true; - Diag(CCLoc, diag::err_nested_name_spec_is_not_class) - << &Identifier << getLangOpts().CPlusPlus - << FixItHint::CreateReplacement(CCLoc, ":"); + Diag(IdInfo.CCLoc, diag::err_nested_name_spec_is_not_class) + << IdInfo.Identifier << getLangOpts().CPlusPlus + << FixItHint::CreateReplacement(IdInfo.CCLoc, ":"); if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) Diag(ND->getLocation(), diag::note_declared_at); return true; } // Replacement '::' -> ':' is not allowed, just issue respective error. Diag(R.getNameLoc(), diag::err_expected_class_or_namespace) - << &Identifier << getLangOpts().CPlusPlus; + << IdInfo.Identifier << getLangOpts().CPlusPlus; if (NamedDecl *ND = R.getAsSingle<NamedDecl>()) - Diag(ND->getLocation(), diag::note_entity_declared_at) << &Identifier; + Diag(ND->getLocation(), diag::note_entity_declared_at) + << IdInfo.Identifier; return true; } } @@ -639,7 +633,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, Found.addDecl(ND); Found.setLookupName(Corrected.getCorrection()); } else { - Found.setLookupName(&Identifier); + Found.setLookupName(IdInfo.Identifier); } } @@ -649,7 +643,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, bool AcceptSpec = isAcceptableNestedNameSpecifier(SD, &IsExtension); if (!AcceptSpec && IsExtension) { AcceptSpec = true; - Diag(IdentifierLoc, diag::ext_nested_name_spec_is_enum); + Diag(IdInfo.IdentifierLoc, diag::ext_nested_name_spec_is_enum); } if (AcceptSpec) { if (!ObjectType.isNull() && !ObjectTypeSearchedInScope && @@ -666,7 +660,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, // Note that C++11 does *not* perform this redundant lookup. NamedDecl *OuterDecl; if (S) { - LookupResult FoundOuter(*this, &Identifier, IdentifierLoc, + LookupResult FoundOuter(*this, IdInfo.Identifier, IdInfo.IdentifierLoc, LookupNestedNameSpecifierName); LookupName(FoundOuter, S); OuterDecl = FoundOuter.getAsSingle<NamedDecl>(); @@ -682,9 +676,9 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (ErrorRecoveryLookup) return true; - Diag(IdentifierLoc, + Diag(IdInfo.IdentifierLoc, diag::err_nested_name_member_ref_lookup_ambiguous) - << &Identifier; + << IdInfo.Identifier; Diag(SD->getLocation(), diag::note_ambig_member_ref_object_type) << ObjectType; Diag(OuterDecl->getLocation(), diag::note_ambig_member_ref_scope); @@ -703,16 +697,15 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, return false; // The use of a nested name specifier may trigger deprecation warnings. - DiagnoseUseOfDecl(SD, CCLoc); + DiagnoseUseOfDecl(SD, IdInfo.CCLoc); - if (NamespaceDecl *Namespace = dyn_cast<NamespaceDecl>(SD)) { - SS.Extend(Context, Namespace, IdentifierLoc, CCLoc); + SS.Extend(Context, Namespace, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } if (NamespaceAliasDecl *Alias = dyn_cast<NamespaceAliasDecl>(SD)) { - SS.Extend(Context, Alias, IdentifierLoc, CCLoc); + SS.Extend(Context, Alias, IdInfo.IdentifierLoc, IdInfo.CCLoc); return false; } @@ -722,41 +715,41 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (isa<InjectedClassNameType>(T)) { InjectedClassNameTypeLoc InjectedTL = TLB.push<InjectedClassNameTypeLoc>(T); - InjectedTL.setNameLoc(IdentifierLoc); + InjectedTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<RecordType>(T)) { RecordTypeLoc RecordTL = TLB.push<RecordTypeLoc>(T); - RecordTL.setNameLoc(IdentifierLoc); + RecordTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<TypedefType>(T)) { TypedefTypeLoc TypedefTL = TLB.push<TypedefTypeLoc>(T); - TypedefTL.setNameLoc(IdentifierLoc); + TypedefTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<EnumType>(T)) { EnumTypeLoc EnumTL = TLB.push<EnumTypeLoc>(T); - EnumTL.setNameLoc(IdentifierLoc); + EnumTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<TemplateTypeParmType>(T)) { TemplateTypeParmTypeLoc TemplateTypeTL = TLB.push<TemplateTypeParmTypeLoc>(T); - TemplateTypeTL.setNameLoc(IdentifierLoc); + TemplateTypeTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<UnresolvedUsingType>(T)) { UnresolvedUsingTypeLoc UnresolvedTL = TLB.push<UnresolvedUsingTypeLoc>(T); - UnresolvedTL.setNameLoc(IdentifierLoc); + UnresolvedTL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<SubstTemplateTypeParmType>(T)) { SubstTemplateTypeParmTypeLoc TL = TLB.push<SubstTemplateTypeParmTypeLoc>(T); - TL.setNameLoc(IdentifierLoc); + TL.setNameLoc(IdInfo.IdentifierLoc); } else if (isa<SubstTemplateTypeParmPackType>(T)) { SubstTemplateTypeParmPackTypeLoc TL = TLB.push<SubstTemplateTypeParmPackTypeLoc>(T); - TL.setNameLoc(IdentifierLoc); + TL.setNameLoc(IdInfo.IdentifierLoc); } else { llvm_unreachable("Unhandled TypeDecl node in nested-name-specifier"); } if (T->isEnumeralType()) - Diag(IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); + Diag(IdInfo.IdentifierLoc, diag::warn_cxx98_compat_enum_nested_name_spec); SS.Extend(Context, SourceLocation(), TLB.getTypeLocInContext(Context, T), - CCLoc); + IdInfo.CCLoc); return false; } @@ -795,9 +788,11 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (DC->isDependentContext() && DC->isFunctionOrMethod()) { CXXRecordDecl *ContainingClass = dyn_cast<CXXRecordDecl>(DC->getParent()); if (ContainingClass && ContainingClass->hasAnyDependentBases()) { - Diag(IdentifierLoc, diag::ext_undeclared_unqual_id_with_dependent_base) - << &Identifier << ContainingClass; - SS.Extend(Context, &Identifier, IdentifierLoc, CCLoc); + Diag(IdInfo.IdentifierLoc, + diag::ext_undeclared_unqual_id_with_dependent_base) + << IdInfo.Identifier << ContainingClass; + SS.Extend(Context, IdInfo.Identifier, IdInfo.IdentifierLoc, + IdInfo.CCLoc); return false; } } @@ -805,28 +800,27 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (!Found.empty()) { if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) - Diag(IdentifierLoc, diag::err_expected_class_or_namespace) + Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) << Context.getTypeDeclType(TD) << getLangOpts().CPlusPlus; else { - Diag(IdentifierLoc, diag::err_expected_class_or_namespace) - << &Identifier << getLangOpts().CPlusPlus; + Diag(IdInfo.IdentifierLoc, diag::err_expected_class_or_namespace) + << IdInfo.Identifier << getLangOpts().CPlusPlus; if (NamedDecl *ND = Found.getAsSingle<NamedDecl>()) - Diag(ND->getLocation(), diag::note_entity_declared_at) << &Identifier; + Diag(ND->getLocation(), diag::note_entity_declared_at) + << IdInfo.Identifier; } } else if (SS.isSet()) - Diag(IdentifierLoc, diag::err_no_member) << &Identifier << LookupCtx - << SS.getRange(); + Diag(IdInfo.IdentifierLoc, diag::err_no_member) << IdInfo.Identifier + << LookupCtx << SS.getRange(); else - Diag(IdentifierLoc, diag::err_undeclared_var_use) << &Identifier; + Diag(IdInfo.IdentifierLoc, diag::err_undeclared_var_use) + << IdInfo.Identifier; return true; } bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, - IdentifierInfo &Identifier, - SourceLocation IdentifierLoc, - SourceLocation CCLoc, - ParsedType ObjectType, + NestedNameSpecInfo &IdInfo, bool EnteringContext, CXXScopeSpec &SS, bool ErrorRecoveryLookup, @@ -834,9 +828,8 @@ bool Sema::ActOnCXXNestedNameSpecifier(Scope *S, if (SS.isInvalid()) return true; - return BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, CCLoc, - GetTypeFromParser(ObjectType), - EnteringContext, SS, + return BuildCXXNestedNameSpecifier(S, IdInfo, + EnteringContext, SS, /*ScopeLookupResult=*/nullptr, false, IsCorrectedToColon); } @@ -871,17 +864,12 @@ bool Sema::ActOnCXXNestedNameSpecifierDecltype(CXXScopeSpec &SS, /// /// The arguments are the same as those passed to ActOnCXXNestedNameSpecifier. bool Sema::IsInvalidUnlessNestedName(Scope *S, CXXScopeSpec &SS, - IdentifierInfo &Identifier, - SourceLocation IdentifierLoc, - SourceLocation ColonLoc, - ParsedType ObjectType, + NestedNameSpecInfo &IdInfo, bool EnteringContext) { if (SS.isInvalid()) return false; - return !BuildCXXNestedNameSpecifier(S, Identifier, IdentifierLoc, ColonLoc, - GetTypeFromParser(ObjectType), - EnteringContext, SS, + return !BuildCXXNestedNameSpecifier(S, IdInfo, EnteringContext, SS, /*ScopeLookupResult=*/nullptr, true); } @@ -987,9 +975,9 @@ void *Sema::SaveNestedNameSpecifierAnnotation(CXXScopeSpec &SS) { if (SS.isEmpty() || SS.isInvalid()) return nullptr; - void *Mem = Context.Allocate((sizeof(NestedNameSpecifierAnnotation) + - SS.location_size()), - llvm::alignOf<NestedNameSpecifierAnnotation>()); + void *Mem = Context.Allocate( + (sizeof(NestedNameSpecifierAnnotation) + SS.location_size()), + alignof(NestedNameSpecifierAnnotation)); NestedNameSpecifierAnnotation *Annotation = new (Mem) NestedNameSpecifierAnnotation; Annotation->NNS = SS.getScopeRep(); @@ -1013,6 +1001,11 @@ void Sema::RestoreNestedNameSpecifierAnnotation(void *AnnotationPtr, bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); + // Don't enter a declarator context when the current context is an Objective-C + // declaration. + if (isa<ObjCContainerDecl>(CurContext) || isa<ObjCMethodDecl>(CurContext)) + return false; + NestedNameSpecifier *Qualifier = SS.getScopeRep(); // There are only two places a well-formed program may qualify a diff --git a/lib/Sema/SemaCast.cpp b/lib/Sema/SemaCast.cpp index e83dd0716780f..6222e4cec47a0 100644 --- a/lib/Sema/SemaCast.cpp +++ b/lib/Sema/SemaCast.cpp @@ -256,6 +256,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, Op.CheckConstCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXConstCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.SrcExpr.get(), DestTInfo, @@ -279,6 +280,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, Op.CheckReinterpretCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXReinterpretCastExpr::Create(Context, Op.ResultType, Op.ValueKind, Op.Kind, Op.SrcExpr.get(), @@ -291,6 +293,7 @@ Sema::BuildCXXNamedCast(SourceLocation OpLoc, tok::TokenKind Kind, Op.CheckStaticCast(); if (Op.SrcExpr.isInvalid()) return ExprError(); + DiscardMisalignedMemberAddress(DestType.getTypePtr(), E); } return Op.complete(CXXStaticCastExpr::Create(Context, Op.ResultType, @@ -980,7 +983,7 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, // C++11 [expr.static.cast]p3: // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to cv2 // T2" if "cv2 T2" is reference-compatible with "cv1 T1". - tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, + tcr = TryLValueToRValueCast(Self, SrcExpr.get(), DestType, CStyle, Kind, BasePath, msg); if (tcr != TC_NotApplicable) return tcr; @@ -1131,12 +1134,12 @@ static TryCastResult TryStaticCast(Sema &Self, ExprResult &SrcExpr, } /// Tests whether a conversion according to N2844 is valid. -TryCastResult -TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, - bool CStyle, CastKind &Kind, CXXCastPath &BasePath, - unsigned &msg) { +TryCastResult TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, + QualType DestType, bool CStyle, + CastKind &Kind, CXXCastPath &BasePath, + unsigned &msg) { // C++11 [expr.static.cast]p3: - // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to + // A glvalue of type "cv1 T1" can be cast to type "rvalue reference to // cv2 T2" if "cv2 T2" is reference-compatible with "cv1 T1". const RValueReferenceType *R = DestType->getAs<RValueReferenceType>(); if (!R) @@ -1157,15 +1160,18 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType, FromType = FromType.getUnqualifiedType(); ToType = ToType.getUnqualifiedType(); } - - if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(), - ToType, FromType, - DerivedToBase, ObjCConversion, - ObjCLifetimeConversion) - < Sema::Ref_Compatible_With_Added_Qualification) { - if (CStyle) + + Sema::ReferenceCompareResult RefResult = Self.CompareReferenceRelationship( + SrcExpr->getLocStart(), ToType, FromType, DerivedToBase, ObjCConversion, + ObjCLifetimeConversion); + if (RefResult != Sema::Ref_Compatible) { + if (CStyle || RefResult == Sema::Ref_Incompatible) return TC_NotApplicable; - msg = diag::err_bad_lvalue_to_rvalue_cast; + // Diagnose types which are reference-related but not compatible here since + // we can provide better diagnostics. In these cases forwarding to + // [expr.static.cast]p4 should never result in a well-formed cast. + msg = SrcExpr->isLValue() ? diag::err_bad_lvalue_to_rvalue_cast + : diag::err_bad_rvalue_to_rvalue_cast; return TC_Failed; } @@ -1511,6 +1517,9 @@ TryStaticImplicitCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, ? InitializationKind::CreateFunctionalCast(OpRange, ListInitialization) : InitializationKind::CreateCast(OpRange); Expr *SrcExprRaw = SrcExpr.get(); + // FIXME: Per DR242, we should check for an implicit conversion sequence + // or for a constructor that could be invoked by direct-initialization + // here, not for an initialization sequence. InitializationSequence InitSeq(Self, Entity, InitKind, SrcExprRaw); // At this point of CheckStaticCast, if the destination is a reference, @@ -1646,7 +1655,8 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr, if (NeedToMaterializeTemporary) // This is a const_cast from a class prvalue to an rvalue reference type. // Materialize a temporary to store the result of the conversion. - SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(), + SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcExpr.get()->getType(), + SrcExpr.get(), /*IsLValueReference*/ false); return TC_Success; @@ -1910,7 +1920,10 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, switch (SrcExpr.get()->getObjectKind()) { case OK_Ordinary: break; - case OK_BitField: inappropriate = "bit-field"; break; + case OK_BitField: + msg = diag::err_bad_cxx_cast_bitfield; + return TC_NotApplicable; + // FIXME: Use a specific diagnostic for the rest of these cases. case OK_VectorComponent: inappropriate = "vector element"; break; case OK_ObjCProperty: inappropriate = "property expression"; break; case OK_ObjCSubscript: inappropriate = "container subscripting expression"; @@ -2435,7 +2448,7 @@ void CastOperation::CheckCStyleCast() { return; } Self.Diag(OpRange.getBegin(), - diag::error_opencl_cast_non_zero_to_event_t) + diag::err_opencl_cast_non_zero_to_event_t) << CastInt.toString(10) << SrcExpr.get()->getSourceRange(); SrcExpr = ExprError(); return; @@ -2516,7 +2529,8 @@ void CastOperation::CheckCStyleCast() { } } - if (Self.getLangOpts().OpenCL && !Self.getOpenCLOptions().cl_khr_fp16) { + if (Self.getLangOpts().OpenCL && + !Self.getOpenCLOptions().isEnabled("cl_khr_fp16")) { if (DestType->isHalfType()) { Self.Diag(SrcExpr.get()->getLocStart(), diag::err_opencl_cast_to_half) << DestType << SrcExpr.get()->getSourceRange(); diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp index 7f7dbe8873d4e..9c902959233fd 100644 --- a/lib/Sema/SemaChecking.cpp +++ b/lib/Sema/SemaChecking.cpp @@ -12,7 +12,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" #include "clang/AST/DeclCXX.h" @@ -33,14 +32,14 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/Sema.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/Format.h" #include "llvm/Support/Locale.h" -#include "llvm/Support/ConvertUTF.h" #include "llvm/Support/raw_ostream.h" -#include <limits> using namespace clang; using namespace sema; @@ -316,8 +315,18 @@ static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { return checkOpenCLBlockArgs(S, BlockArg); } +/// Diagnose integer type and any valid implicit convertion to it. +static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, + const QualType &IntType); + static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, - unsigned Start, unsigned End); + unsigned Start, unsigned End) { + bool IllegalParams = false; + for (unsigned I = Start; I <= End; ++I) + IllegalParams |= checkOpenCLEnqueueIntType(S, TheCall->getArg(I), + S.Context.getSizeType()); + return IllegalParams; +} /// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all /// 'local void*' parameter of passed block. @@ -452,16 +461,20 @@ static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { Expr *Arg4 = TheCall->getArg(4); Expr *Arg5 = TheCall->getArg(5); - // Fith argument is always passed as pointers to clk_event_t. - if (!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { + // Fifth argument is always passed as a pointer to clk_event_t. + if (!Arg4->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNotNull) && + !Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) { S.Diag(TheCall->getArg(4)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) << S.Context.getPointerType(S.Context.OCLClkEventTy); return true; } - // Sixth argument is always passed as pointers to clk_event_t. - if (!(Arg5->getType()->isPointerType() && + // Sixth argument is always passed as a pointer to clk_event_t. + if (!Arg5->isNullPointerConstant(S.Context, + Expr::NPC_ValueDependentIsNotNull) && + !(Arg5->getType()->isPointerType() && Arg5->getType()->getPointeeType()->isClkEventT())) { S.Diag(TheCall->getArg(5)->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) @@ -792,6 +805,10 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, if (SemaBuiltinPrefetch(TheCall)) return ExprError(); break; + case Builtin::BI__builtin_alloca_with_align: + if (SemaBuiltinAllocaWithAlign(TheCall)) + return ExprError(); + break; case Builtin::BI__assume: case Builtin::BI__builtin_assume: if (SemaBuiltinAssume(TheCall)) @@ -1021,6 +1038,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, // check for the argument. if (SemaBuiltinRWPipe(*this, TheCall)) return ExprError(); + TheCall->setType(Context.IntTy); break; case Builtin::BIreserve_read_pipe: case Builtin::BIreserve_write_pipe: @@ -1048,6 +1066,7 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIget_pipe_max_packets: if (SemaBuiltinPipePackets(*this, TheCall)) return ExprError(); + TheCall->setType(Context.UnsignedIntTy); break; case Builtin::BIto_global: case Builtin::BIto_local: @@ -1064,6 +1083,13 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BIget_kernel_preferred_work_group_size_multiple: if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) return ExprError(); + break; + case Builtin::BI__builtin_os_log_format: + case Builtin::BI__builtin_os_log_format_buffer_size: + if (SemaBuiltinOSLogFormat(TheCall)) { + return ExprError(); + } + break; } // Since the target specific builtins for each arch overlap, only check those @@ -1757,51 +1783,237 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { return false; } -bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - int i = 0, l = 0, u = 0; +// Check if the rounding mode is legal. +bool Sema::CheckX86BuiltinRoundingOrSAE(unsigned BuiltinID, CallExpr *TheCall) { + // Indicates if this instruction has rounding control or just SAE. + bool HasRC = false; + + unsigned ArgNum = 0; switch (BuiltinID) { default: return false; - case X86::BI__builtin_cpu_supports: + case X86::BI__builtin_ia32_vcvttsd2si32: + case X86::BI__builtin_ia32_vcvttsd2si64: + case X86::BI__builtin_ia32_vcvttsd2usi32: + case X86::BI__builtin_ia32_vcvttsd2usi64: + case X86::BI__builtin_ia32_vcvttss2si32: + case X86::BI__builtin_ia32_vcvttss2si64: + case X86::BI__builtin_ia32_vcvttss2usi32: + case X86::BI__builtin_ia32_vcvttss2usi64: + ArgNum = 1; + break; + case X86::BI__builtin_ia32_cvtps2pd512_mask: + case X86::BI__builtin_ia32_cvttpd2dq512_mask: + case X86::BI__builtin_ia32_cvttpd2qq512_mask: + case X86::BI__builtin_ia32_cvttpd2udq512_mask: + case X86::BI__builtin_ia32_cvttpd2uqq512_mask: + case X86::BI__builtin_ia32_cvttps2dq512_mask: + case X86::BI__builtin_ia32_cvttps2qq512_mask: + case X86::BI__builtin_ia32_cvttps2udq512_mask: + case X86::BI__builtin_ia32_cvttps2uqq512_mask: + case X86::BI__builtin_ia32_exp2pd_mask: + case X86::BI__builtin_ia32_exp2ps_mask: + case X86::BI__builtin_ia32_getexppd512_mask: + case X86::BI__builtin_ia32_getexpps512_mask: + case X86::BI__builtin_ia32_rcp28pd_mask: + case X86::BI__builtin_ia32_rcp28ps_mask: + case X86::BI__builtin_ia32_rsqrt28pd_mask: + case X86::BI__builtin_ia32_rsqrt28ps_mask: + case X86::BI__builtin_ia32_vcomisd: + case X86::BI__builtin_ia32_vcomiss: + case X86::BI__builtin_ia32_vcvtph2ps512_mask: + ArgNum = 3; + break; + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpps512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + case X86::BI__builtin_ia32_cvtss2sd_round_mask: + case X86::BI__builtin_ia32_getexpsd128_round_mask: + case X86::BI__builtin_ia32_getexpss128_round_mask: + case X86::BI__builtin_ia32_maxpd512_mask: + case X86::BI__builtin_ia32_maxps512_mask: + case X86::BI__builtin_ia32_maxsd_round_mask: + case X86::BI__builtin_ia32_maxss_round_mask: + case X86::BI__builtin_ia32_minpd512_mask: + case X86::BI__builtin_ia32_minps512_mask: + case X86::BI__builtin_ia32_minsd_round_mask: + case X86::BI__builtin_ia32_minss_round_mask: + case X86::BI__builtin_ia32_rcp28sd_round_mask: + case X86::BI__builtin_ia32_rcp28ss_round_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rsqrt28sd_round_mask: + case X86::BI__builtin_ia32_rsqrt28ss_round_mask: + ArgNum = 4; + break; + case X86::BI__builtin_ia32_fixupimmpd512_mask: + case X86::BI__builtin_ia32_fixupimmpd512_maskz: + case X86::BI__builtin_ia32_fixupimmps512_mask: + case X86::BI__builtin_ia32_fixupimmps512_maskz: + case X86::BI__builtin_ia32_fixupimmsd_mask: + case X86::BI__builtin_ia32_fixupimmsd_maskz: + case X86::BI__builtin_ia32_fixupimmss_mask: + case X86::BI__builtin_ia32_fixupimmss_maskz: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_rangesd128_round_mask: + case X86::BI__builtin_ia32_rangess128_round_mask: + case X86::BI__builtin_ia32_reducesd_mask: + case X86::BI__builtin_ia32_reducess_mask: + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + ArgNum = 5; + break; + case X86::BI__builtin_ia32_vcvtsd2si64: + case X86::BI__builtin_ia32_vcvtsd2si32: + case X86::BI__builtin_ia32_vcvtsd2usi32: + case X86::BI__builtin_ia32_vcvtsd2usi64: + case X86::BI__builtin_ia32_vcvtss2si32: + case X86::BI__builtin_ia32_vcvtss2si64: + case X86::BI__builtin_ia32_vcvtss2usi32: + case X86::BI__builtin_ia32_vcvtss2usi64: + ArgNum = 1; + HasRC = true; + break; + case X86::BI__builtin_ia32_cvtsi2sd64: + case X86::BI__builtin_ia32_cvtsi2ss32: + case X86::BI__builtin_ia32_cvtsi2ss64: + case X86::BI__builtin_ia32_cvtusi2sd64: + case X86::BI__builtin_ia32_cvtusi2ss32: + case X86::BI__builtin_ia32_cvtusi2ss64: + ArgNum = 2; + HasRC = true; + break; + case X86::BI__builtin_ia32_cvtdq2ps512_mask: + case X86::BI__builtin_ia32_cvtudq2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2ps512_mask: + case X86::BI__builtin_ia32_cvtpd2qq512_mask: + case X86::BI__builtin_ia32_cvtpd2uqq512_mask: + case X86::BI__builtin_ia32_cvtps2qq512_mask: + case X86::BI__builtin_ia32_cvtps2uqq512_mask: + case X86::BI__builtin_ia32_cvtqq2pd512_mask: + case X86::BI__builtin_ia32_cvtqq2ps512_mask: + case X86::BI__builtin_ia32_cvtuqq2pd512_mask: + case X86::BI__builtin_ia32_cvtuqq2ps512_mask: + case X86::BI__builtin_ia32_sqrtpd512_mask: + case X86::BI__builtin_ia32_sqrtps512_mask: + ArgNum = 3; + HasRC = true; + break; + case X86::BI__builtin_ia32_addpd512_mask: + case X86::BI__builtin_ia32_addps512_mask: + case X86::BI__builtin_ia32_divpd512_mask: + case X86::BI__builtin_ia32_divps512_mask: + case X86::BI__builtin_ia32_mulpd512_mask: + case X86::BI__builtin_ia32_mulps512_mask: + case X86::BI__builtin_ia32_subpd512_mask: + case X86::BI__builtin_ia32_subps512_mask: + case X86::BI__builtin_ia32_addss_round_mask: + case X86::BI__builtin_ia32_addsd_round_mask: + case X86::BI__builtin_ia32_divss_round_mask: + case X86::BI__builtin_ia32_divsd_round_mask: + case X86::BI__builtin_ia32_mulss_round_mask: + case X86::BI__builtin_ia32_mulsd_round_mask: + case X86::BI__builtin_ia32_subss_round_mask: + case X86::BI__builtin_ia32_subsd_round_mask: + case X86::BI__builtin_ia32_scalefpd512_mask: + case X86::BI__builtin_ia32_scalefps512_mask: + case X86::BI__builtin_ia32_scalefsd_round_mask: + case X86::BI__builtin_ia32_scalefss_round_mask: + case X86::BI__builtin_ia32_getmantpd512_mask: + case X86::BI__builtin_ia32_getmantps512_mask: + case X86::BI__builtin_ia32_cvtsd2ss_round_mask: + case X86::BI__builtin_ia32_sqrtsd_round_mask: + case X86::BI__builtin_ia32_sqrtss_round_mask: + case X86::BI__builtin_ia32_vfmaddpd512_mask: + case X86::BI__builtin_ia32_vfmaddpd512_mask3: + case X86::BI__builtin_ia32_vfmaddpd512_maskz: + case X86::BI__builtin_ia32_vfmaddps512_mask: + case X86::BI__builtin_ia32_vfmaddps512_mask3: + case X86::BI__builtin_ia32_vfmaddps512_maskz: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask: + case X86::BI__builtin_ia32_vfmaddsubpd512_mask3: + case X86::BI__builtin_ia32_vfmaddsubpd512_maskz: + case X86::BI__builtin_ia32_vfmaddsubps512_mask: + case X86::BI__builtin_ia32_vfmaddsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddsubps512_maskz: + case X86::BI__builtin_ia32_vfmsubpd512_mask3: + case X86::BI__builtin_ia32_vfmsubps512_mask3: + case X86::BI__builtin_ia32_vfmsubaddpd512_mask3: + case X86::BI__builtin_ia32_vfmsubaddps512_mask3: + case X86::BI__builtin_ia32_vfnmaddpd512_mask: + case X86::BI__builtin_ia32_vfnmaddps512_mask: + case X86::BI__builtin_ia32_vfnmsubpd512_mask: + case X86::BI__builtin_ia32_vfnmsubpd512_mask3: + case X86::BI__builtin_ia32_vfnmsubps512_mask: + case X86::BI__builtin_ia32_vfnmsubps512_mask3: + case X86::BI__builtin_ia32_vfmaddsd3_mask: + case X86::BI__builtin_ia32_vfmaddsd3_maskz: + case X86::BI__builtin_ia32_vfmaddsd3_mask3: + case X86::BI__builtin_ia32_vfmaddss3_mask: + case X86::BI__builtin_ia32_vfmaddss3_maskz: + case X86::BI__builtin_ia32_vfmaddss3_mask3: + ArgNum = 4; + HasRC = true; + break; + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + ArgNum = 5; + HasRC = true; + break; + } + + llvm::APSInt Result; + + // 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. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + // Make sure rounding mode is either ROUND_CUR_DIRECTION or ROUND_NO_EXC bit + // is set. If the intrinsic has rounding control(bits 1:0), make sure its only + // combined with ROUND_NO_EXC. + if (Result == 4/*ROUND_CUR_DIRECTION*/ || + Result == 8/*ROUND_NO_EXC*/ || + (HasRC && Result.getZExtValue() >= 8 && Result.getZExtValue() <= 11)) + return false; + + return Diag(TheCall->getLocStart(), diag::err_x86_builtin_invalid_rounding) + << Arg->getSourceRange(); +} + +bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { + if (BuiltinID == X86::BI__builtin_cpu_supports) return SemaBuiltinCpuSupports(*this, TheCall); - case X86::BI__builtin_ms_va_start: + + if (BuiltinID == X86::BI__builtin_ms_va_start) return SemaBuiltinMSVAStart(TheCall); - case X86::BI__builtin_ia32_extractf64x4_mask: - case X86::BI__builtin_ia32_extracti64x4_mask: - case X86::BI__builtin_ia32_extractf32x8_mask: - case X86::BI__builtin_ia32_extracti32x8_mask: - case X86::BI__builtin_ia32_extractf64x2_256_mask: - case X86::BI__builtin_ia32_extracti64x2_256_mask: - case X86::BI__builtin_ia32_extractf32x4_256_mask: - case X86::BI__builtin_ia32_extracti32x4_256_mask: - i = 1; l = 0; u = 1; - break; + + // If the intrinsic has rounding or SAE make sure its valid. + if (CheckX86BuiltinRoundingOrSAE(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; + switch (BuiltinID) { + default: + return false; case X86::BI_mm_prefetch: - case X86::BI__builtin_ia32_extractf32x4_mask: - case X86::BI__builtin_ia32_extracti32x4_mask: - case X86::BI__builtin_ia32_extractf64x2_512_mask: - case X86::BI__builtin_ia32_extracti64x2_512_mask: i = 1; l = 0; u = 3; break; - case X86::BI__builtin_ia32_insertf32x8_mask: - case X86::BI__builtin_ia32_inserti32x8_mask: - case X86::BI__builtin_ia32_insertf64x4_mask: - case X86::BI__builtin_ia32_inserti64x4_mask: - case X86::BI__builtin_ia32_insertf64x2_256_mask: - case X86::BI__builtin_ia32_inserti64x2_256_mask: - case X86::BI__builtin_ia32_insertf32x4_256_mask: - case X86::BI__builtin_ia32_inserti32x4_256_mask: - i = 2; l = 0; u = 1; - break; case X86::BI__builtin_ia32_sha1rnds4: case X86::BI__builtin_ia32_shuf_f32x4_256_mask: case X86::BI__builtin_ia32_shuf_f64x2_256_mask: case X86::BI__builtin_ia32_shuf_i32x4_256_mask: case X86::BI__builtin_ia32_shuf_i64x2_256_mask: - case X86::BI__builtin_ia32_insertf64x2_512_mask: - case X86::BI__builtin_ia32_inserti64x2_512_mask: - case X86::BI__builtin_ia32_insertf32x4_mask: - case X86::BI__builtin_ia32_inserti32x4_mask: i = 2; l = 0; u = 3; break; case X86::BI__builtin_ia32_vpermil2pd: @@ -1909,33 +2121,6 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_prord256_mask: case X86::BI__builtin_ia32_prorq128_mask: case X86::BI__builtin_ia32_prorq256_mask: - case X86::BI__builtin_ia32_psllwi512_mask: - case X86::BI__builtin_ia32_psllwi128_mask: - case X86::BI__builtin_ia32_psllwi256_mask: - case X86::BI__builtin_ia32_psrldi128_mask: - case X86::BI__builtin_ia32_psrldi256_mask: - case X86::BI__builtin_ia32_psrldi512_mask: - case X86::BI__builtin_ia32_psrlqi128_mask: - case X86::BI__builtin_ia32_psrlqi256_mask: - case X86::BI__builtin_ia32_psrlqi512_mask: - case X86::BI__builtin_ia32_psrawi512_mask: - case X86::BI__builtin_ia32_psrawi128_mask: - case X86::BI__builtin_ia32_psrawi256_mask: - case X86::BI__builtin_ia32_psrlwi512_mask: - case X86::BI__builtin_ia32_psrlwi128_mask: - case X86::BI__builtin_ia32_psrlwi256_mask: - case X86::BI__builtin_ia32_psradi128_mask: - case X86::BI__builtin_ia32_psradi256_mask: - case X86::BI__builtin_ia32_psradi512_mask: - case X86::BI__builtin_ia32_psraqi128_mask: - case X86::BI__builtin_ia32_psraqi256_mask: - case X86::BI__builtin_ia32_psraqi512_mask: - case X86::BI__builtin_ia32_pslldi128_mask: - case X86::BI__builtin_ia32_pslldi256_mask: - case X86::BI__builtin_ia32_pslldi512_mask: - case X86::BI__builtin_ia32_psllqi128_mask: - case X86::BI__builtin_ia32_psllqi256_mask: - case X86::BI__builtin_ia32_psllqi512_mask: case X86::BI__builtin_ia32_fpclasspd128_mask: case X86::BI__builtin_ia32_fpclasspd256_mask: case X86::BI__builtin_ia32_fpclassps128_mask: @@ -1969,15 +2154,7 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { break; case X86::BI__builtin_ia32_palignr128: case X86::BI__builtin_ia32_palignr256: - case X86::BI__builtin_ia32_palignr128_mask: - case X86::BI__builtin_ia32_palignr256_mask: case X86::BI__builtin_ia32_palignr512_mask: - case X86::BI__builtin_ia32_alignq512_mask: - case X86::BI__builtin_ia32_alignd512_mask: - case X86::BI__builtin_ia32_alignd128_mask: - case X86::BI__builtin_ia32_alignd256_mask: - case X86::BI__builtin_ia32_alignq128_mask: - case X86::BI__builtin_ia32_alignq256_mask: case X86::BI__builtin_ia32_vcomisd: case X86::BI__builtin_ia32_vcomiss: case X86::BI__builtin_ia32_shuf_f32x4_mask: @@ -2271,7 +2448,9 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto, // Refuse POD arguments that weren't caught by the format string // checks above. - if (CallType != VariadicDoesNotApply) { + auto *FD = dyn_cast_or_null<FunctionDecl>(FDecl); + if (CallType != VariadicDoesNotApply && + (!FD || FD->getBuiltinID() != Builtin::BI__noop)) { unsigned NumParams = Proto ? Proto->getNumParams() : FDecl && isa<FunctionDecl>(FDecl) ? cast<FunctionDecl>(FDecl)->getNumParams() @@ -2340,7 +2519,9 @@ bool Sema::CheckFunctionCall(FunctionDecl *FDecl, CallExpr *TheCall, if (!FnInfo) return false; - CheckAbsoluteValueFunction(TheCall, FDecl, FnInfo); + CheckAbsoluteValueFunction(TheCall, FDecl); + CheckMaxUnsignedZero(TheCall, FDecl); + if (getLangOpts().ObjC1) DiagnoseCStringFormatDirectiveInCFAPI(*this, FDecl, Args, NumArgs); @@ -2691,6 +2872,9 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Ty = Context.getPointerDiffType(); else { Expr *ValArg = TheCall->getArg(i); + // Treat this argument as _Nonnull as we want to show a warning if + // NULL is passed into it. + CheckNonNullArgument(*this, ValArg, DRE->getLocStart()); unsigned AS = 0; // Keep address space of non-atomic pointer type. if (const PointerType *PtrTy = @@ -3267,21 +3451,46 @@ bool Sema::CheckObjCString(Expr *Arg) { if (Literal->containsNonAsciiOrNull()) { StringRef String = Literal->getString(); unsigned NumBytes = String.size(); - SmallVector<UTF16, 128> ToBuf(NumBytes); - const UTF8 *FromPtr = (const UTF8 *)String.data(); - UTF16 *ToPtr = &ToBuf[0]; - - ConversionResult Result = ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, - &ToPtr, ToPtr + NumBytes, - strictConversion); + SmallVector<llvm::UTF16, 128> ToBuf(NumBytes); + const llvm::UTF8 *FromPtr = (const llvm::UTF8 *)String.data(); + llvm::UTF16 *ToPtr = &ToBuf[0]; + + llvm::ConversionResult Result = + llvm::ConvertUTF8toUTF16(&FromPtr, FromPtr + NumBytes, &ToPtr, + ToPtr + NumBytes, llvm::strictConversion); // Check for conversion failure. - if (Result != conversionOK) + if (Result != llvm::conversionOK) Diag(Arg->getLocStart(), diag::warn_cfstring_truncated) << Arg->getSourceRange(); } return false; } +/// CheckObjCString - Checks that the format string argument to the os_log() +/// and os_trace() functions is correct, and converts it to const char *. +ExprResult Sema::CheckOSLogFormatStringArg(Expr *Arg) { + Arg = Arg->IgnoreParenCasts(); + auto *Literal = dyn_cast<StringLiteral>(Arg); + if (!Literal) { + if (auto *ObjcLiteral = dyn_cast<ObjCStringLiteral>(Arg)) { + Literal = ObjcLiteral->getString(); + } + } + + if (!Literal || (!Literal->isAscii() && !Literal->isUTF8())) { + return ExprError( + Diag(Arg->getLocStart(), diag::err_os_log_format_not_string_constant) + << Arg->getSourceRange()); + } + + ExprResult Result(Literal); + QualType ResultTy = Context.getPointerType(Context.CharTy.withConst()); + InitializedEntity Entity = + InitializedEntity::InitializeParameter(Context, ResultTy, false); + Result = PerformCopyInitialization(Entity, SourceLocation(), Result); + return Result; +} + /// Check the arguments to '__builtin_va_start' or '__builtin_ms_va_start' /// for validity. Emit an error and return true on failure; return false /// on success. @@ -3357,8 +3566,17 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { Diag(TheCall->getArg(1)->getLocStart(), diag::warn_second_arg_of_va_start_not_last_named_param); else if (IsCRegister || Type->isReferenceType() || - Type->isPromotableIntegerType() || - Type->isSpecificBuiltinType(BuiltinType::Float)) { + Type->isSpecificBuiltinType(BuiltinType::Float) || [=] { + // Promotable integers are UB, but enumerations need a bit of + // extra checking to see what their promotable type actually is. + if (!Type->isPromotableIntegerType()) + return false; + if (!Type->isEnumeralType()) + return true; + const EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); + return !(ED && + Context.typesAreCompatible(ED->getPromotionType(), Type)); + }()) { unsigned Reason = 0; if (Type->isReferenceType()) Reason = 1; else if (IsCRegister) Reason = 2; @@ -3532,14 +3750,18 @@ bool Sema::SemaBuiltinFPClassification(CallExpr *TheCall, unsigned NumArgs) { diag::err_typecheck_call_invalid_unary_fp) << OrigArg->getType() << OrigArg->getSourceRange(); - // If this is an implicit conversion from float -> double, remove it. + // If this is an implicit conversion from float -> float or double, remove it. if (ImplicitCastExpr *Cast = dyn_cast<ImplicitCastExpr>(OrigArg)) { - Expr *CastArg = Cast->getSubExpr(); - if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { - assert(Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) && - "promotion from float to double is the only expected cast here"); - Cast->setSubExpr(nullptr); - TheCall->setArg(NumArgs-1, CastArg); + // Only remove standard FloatCasts, leaving other casts inplace + if (Cast->getCastKind() == CK_FloatingCast) { + Expr *CastArg = Cast->getSubExpr(); + if (CastArg->getType()->isSpecificBuiltinType(BuiltinType::Float)) { + assert((Cast->getType()->isSpecificBuiltinType(BuiltinType::Double) || + Cast->getType()->isSpecificBuiltinType(BuiltinType::Float)) && + "promotion from float to either float or double is the only expected cast here"); + Cast->setSubExpr(nullptr); + TheCall->setArg(NumArgs-1, CastArg); + } } } @@ -3696,6 +3918,42 @@ bool Sema::SemaBuiltinAssume(CallExpr *TheCall) { return false; } +/// Handle __builtin_alloca_with_align. This is declared +/// as (size_t, size_t) where the second size_t must be a power of 2 greater +/// than 8. +bool Sema::SemaBuiltinAllocaWithAlign(CallExpr *TheCall) { + // The alignment must be a constant integer. + Expr *Arg = TheCall->getArg(1); + + // We can't check the value of a dependent argument. + if (!Arg->isTypeDependent() && !Arg->isValueDependent()) { + if (const auto *UE = + dyn_cast<UnaryExprOrTypeTraitExpr>(Arg->IgnoreParenImpCasts())) + if (UE->getKind() == UETT_AlignOf) + Diag(TheCall->getLocStart(), diag::warn_alloca_align_alignof) + << Arg->getSourceRange(); + + llvm::APSInt Result = Arg->EvaluateKnownConstInt(Context); + + if (!Result.isPowerOf2()) + return Diag(TheCall->getLocStart(), + diag::err_alignment_not_power_of_two) + << Arg->getSourceRange(); + + if (Result < Context.getCharWidth()) + return Diag(TheCall->getLocStart(), diag::err_alignment_too_small) + << (unsigned)Context.getCharWidth() + << Arg->getSourceRange(); + + if (Result > INT32_MAX) + return Diag(TheCall->getLocStart(), diag::err_alignment_too_big) + << INT32_MAX + << Arg->getSourceRange(); + } + + return false; +} + /// Handle __builtin_assume_aligned. This is declared /// as (const void*, size_t, ...) and can take one optional constant int arg. bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { @@ -3734,6 +3992,86 @@ bool Sema::SemaBuiltinAssumeAligned(CallExpr *TheCall) { return false; } +bool Sema::SemaBuiltinOSLogFormat(CallExpr *TheCall) { + unsigned BuiltinID = + cast<FunctionDecl>(TheCall->getCalleeDecl())->getBuiltinID(); + bool IsSizeCall = BuiltinID == Builtin::BI__builtin_os_log_format_buffer_size; + + unsigned NumArgs = TheCall->getNumArgs(); + unsigned NumRequiredArgs = IsSizeCall ? 1 : 2; + if (NumArgs < NumRequiredArgs) { + return Diag(TheCall->getLocEnd(), diag::err_typecheck_call_too_few_args) + << 0 /* function call */ << NumRequiredArgs << NumArgs + << TheCall->getSourceRange(); + } + if (NumArgs >= NumRequiredArgs + 0x100) { + return Diag(TheCall->getLocEnd(), + diag::err_typecheck_call_too_many_args_at_most) + << 0 /* function call */ << (NumRequiredArgs + 0xff) << NumArgs + << TheCall->getSourceRange(); + } + unsigned i = 0; + + // For formatting call, check buffer arg. + if (!IsSizeCall) { + ExprResult Arg(TheCall->getArg(i)); + InitializedEntity Entity = InitializedEntity::InitializeParameter( + Context, Context.VoidPtrTy, false); + Arg = PerformCopyInitialization(Entity, SourceLocation(), Arg); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + i++; + } + + // Check string literal arg. + unsigned FormatIdx = i; + { + ExprResult Arg = CheckOSLogFormatStringArg(TheCall->getArg(i)); + if (Arg.isInvalid()) + return true; + TheCall->setArg(i, Arg.get()); + i++; + } + + // Make sure variadic args are scalar. + unsigned FirstDataArg = i; + while (i < NumArgs) { + ExprResult Arg = DefaultVariadicArgumentPromotion( + TheCall->getArg(i), VariadicFunction, nullptr); + if (Arg.isInvalid()) + return true; + CharUnits ArgSize = Context.getTypeSizeInChars(Arg.get()->getType()); + if (ArgSize.getQuantity() >= 0x100) { + return Diag(Arg.get()->getLocEnd(), diag::err_os_log_argument_too_big) + << i << (int)ArgSize.getQuantity() << 0xff + << TheCall->getSourceRange(); + } + TheCall->setArg(i, Arg.get()); + i++; + } + + // Check formatting specifiers. NOTE: We're only doing this for the non-size + // call to avoid duplicate diagnostics. + if (!IsSizeCall) { + llvm::SmallBitVector CheckedVarArgs(NumArgs, false); + ArrayRef<const Expr *> Args(TheCall->getArgs(), TheCall->getNumArgs()); + bool Success = CheckFormatArguments( + Args, /*HasVAListArg*/ false, FormatIdx, FirstDataArg, FST_OSLog, + VariadicFunction, TheCall->getLocStart(), SourceRange(), + CheckedVarArgs); + if (!Success) + return true; + } + + if (IsSizeCall) { + TheCall->setType(Context.getSizeType()); + } else { + TheCall->setType(Context.VoidPtrTy); + } + return false; +} + /// SemaBuiltinConstantArg - Handle a check if argument ArgNum of CallExpr /// TheCall is a constant expression. bool Sema::SemaBuiltinConstantArg(CallExpr *TheCall, int ArgNum, @@ -3861,7 +4199,7 @@ bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, SmallVector<int, 5> Ranges; if (FiveFields) - Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 7, 15, 15}); + Ranges.append({IsAArch64Builtin ? 1 : 15, 7, 15, 15, 7}); else Ranges.append({15, 7, 15}); @@ -3980,7 +4318,95 @@ enum StringLiteralCheckType { }; } // end anonymous namespace -static void CheckFormatString(Sema &S, const StringLiteral *FExpr, +static void sumOffsets(llvm::APSInt &Offset, llvm::APSInt Addend, + BinaryOperatorKind BinOpKind, + bool AddendIsRight) { + unsigned BitWidth = Offset.getBitWidth(); + unsigned AddendBitWidth = Addend.getBitWidth(); + // There might be negative interim results. + if (Addend.isUnsigned()) { + Addend = Addend.zext(++AddendBitWidth); + Addend.setIsSigned(true); + } + // Adjust the bit width of the APSInts. + if (AddendBitWidth > BitWidth) { + Offset = Offset.sext(AddendBitWidth); + BitWidth = AddendBitWidth; + } else if (BitWidth > AddendBitWidth) { + Addend = Addend.sext(BitWidth); + } + + bool Ov = false; + llvm::APSInt ResOffset = Offset; + if (BinOpKind == BO_Add) + ResOffset = Offset.sadd_ov(Addend, Ov); + else { + assert(AddendIsRight && BinOpKind == BO_Sub && + "operator must be add or sub with addend on the right"); + ResOffset = Offset.ssub_ov(Addend, Ov); + } + + // We add an offset to a pointer here so we should support an offset as big as + // possible. + if (Ov) { + assert(BitWidth <= UINT_MAX / 2 && "index (intermediate) result too big"); + Offset = Offset.sext(2 * BitWidth); + sumOffsets(Offset, Addend, BinOpKind, AddendIsRight); + return; + } + + Offset = ResOffset; +} + +namespace { +// This is a wrapper class around StringLiteral to support offsetted string +// literals as format strings. It takes the offset into account when returning +// the string and its length or the source locations to display notes correctly. +class FormatStringLiteral { + const StringLiteral *FExpr; + int64_t Offset; + + public: + FormatStringLiteral(const StringLiteral *fexpr, int64_t Offset = 0) + : FExpr(fexpr), Offset(Offset) {} + + StringRef getString() const { + return FExpr->getString().drop_front(Offset); + } + + unsigned getByteLength() const { + return FExpr->getByteLength() - getCharByteWidth() * Offset; + } + unsigned getLength() const { return FExpr->getLength() - Offset; } + unsigned getCharByteWidth() const { return FExpr->getCharByteWidth(); } + + StringLiteral::StringKind getKind() const { return FExpr->getKind(); } + + QualType getType() const { return FExpr->getType(); } + + bool isAscii() const { return FExpr->isAscii(); } + bool isWide() const { return FExpr->isWide(); } + bool isUTF8() const { return FExpr->isUTF8(); } + bool isUTF16() const { return FExpr->isUTF16(); } + bool isUTF32() const { return FExpr->isUTF32(); } + bool isPascal() const { return FExpr->isPascal(); } + + SourceLocation getLocationOfByte( + unsigned ByteNo, const SourceManager &SM, const LangOptions &Features, + const TargetInfo &Target, unsigned *StartToken = nullptr, + unsigned *StartTokenByteOffset = nullptr) const { + return FExpr->getLocationOfByte(ByteNo + Offset, SM, Features, Target, + StartToken, StartTokenByteOffset); + } + + SourceLocation getLocStart() const LLVM_READONLY { + return FExpr->getLocStart().getLocWithOffset(Offset); + } + SourceLocation getLocEnd() const LLVM_READONLY { return FExpr->getLocEnd(); } +}; +} // end anonymous namespace + +static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, @@ -4001,8 +4427,11 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, llvm::SmallBitVector &CheckedVarArgs, - UncoveredArgHandler &UncoveredArg) { + UncoveredArgHandler &UncoveredArg, + llvm::APSInt Offset) { tryAgain: + assert(Offset.isSigned() && "invalid offset"); + if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; @@ -4036,6 +4465,10 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, CheckLeft = false; } + // We need to maintain the offsets for the right and the left hand side + // separately to check if every possible indexed expression is a valid + // string literal. They might have different offsets for different string + // literals in the end. StringLiteralCheckType Left; if (!CheckLeft) Left = SLCT_UncheckedLiteral; @@ -4043,16 +4476,17 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg); - if (Left == SLCT_NotALiteral || !CheckRight) + CheckedVarArgs, UncoveredArg, Offset); + if (Left == SLCT_NotALiteral || !CheckRight) { return Left; + } } StringLiteralCheckType Right = checkFormatStringExpr(S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg); + UncoveredArg, Offset); return (CheckLeft && Left < Right) ? Left : Right; } @@ -4105,8 +4539,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Init, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*InFunctionCall*/false, CheckedVarArgs, - UncoveredArg); + /*InFunctionCall*/ false, CheckedVarArgs, + UncoveredArg, Offset); } } @@ -4161,7 +4595,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs, UncoveredArg); + CheckedVarArgs, UncoveredArg, Offset); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || @@ -4171,13 +4605,27 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, CheckedVarArgs, - UncoveredArg); + UncoveredArg, Offset); } } } return SLCT_NotALiteral; } + case Stmt::ObjCMessageExprClass: { + const auto *ME = cast<ObjCMessageExpr>(E); + if (const auto *ND = ME->getMethodDecl()) { + if (const auto *FA = ND->getAttr<FormatArgAttr>()) { + unsigned ArgIndex = FA->getFormatIdx(); + const Expr *Arg = ME->getArg(ArgIndex - 1); + return checkFormatStringExpr( + S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, + CallType, InFunctionCall, CheckedVarArgs, UncoveredArg, Offset); + } + } + + return SLCT_NotALiteral; + } case Stmt::ObjCStringLiteralClass: case Stmt::StringLiteralClass: { const StringLiteral *StrE = nullptr; @@ -4188,7 +4636,13 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, StrE = cast<StringLiteral>(E); if (StrE) { - CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx, + if (Offset.isNegative() || Offset > StrE->getLength()) { + // TODO: It would be better to have an explicit warning for out of + // bounds literals. + return SLCT_NotALiteral; + } + FormatStringLiteral FStr(StrE, Offset.sextOrTrunc(64).getSExtValue()); + CheckFormatString(S, &FStr, E, Args, HasVAListArg, format_idx, firstDataArg, Type, InFunctionCall, CallType, CheckedVarArgs, UncoveredArg); return SLCT_CheckedLiteral; @@ -4196,6 +4650,50 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return SLCT_NotALiteral; } + case Stmt::BinaryOperatorClass: { + llvm::APSInt LResult; + llvm::APSInt RResult; + + const BinaryOperator *BinOp = cast<BinaryOperator>(E); + + // A string literal + an int offset is still a string literal. + if (BinOp->isAdditiveOp()) { + bool LIsInt = BinOp->getLHS()->EvaluateAsInt(LResult, S.Context); + bool RIsInt = BinOp->getRHS()->EvaluateAsInt(RResult, S.Context); + + if (LIsInt != RIsInt) { + BinaryOperatorKind BinOpKind = BinOp->getOpcode(); + + if (LIsInt) { + if (BinOpKind == BO_Add) { + sumOffsets(Offset, LResult, BinOpKind, RIsInt); + E = BinOp->getRHS(); + goto tryAgain; + } + } else { + sumOffsets(Offset, RResult, BinOpKind, RIsInt); + E = BinOp->getLHS(); + goto tryAgain; + } + } + } + + return SLCT_NotALiteral; + } + case Stmt::UnaryOperatorClass: { + const UnaryOperator *UnaOp = cast<UnaryOperator>(E); + auto ASE = dyn_cast<ArraySubscriptExpr>(UnaOp->getSubExpr()); + if (UnaOp->getOpcode() == clang::UO_AddrOf && ASE) { + llvm::APSInt IndexResult; + if (ASE->getRHS()->EvaluateAsInt(IndexResult, S.Context)) { + sumOffsets(Offset, IndexResult, BO_Add, /*RHS is int*/ true); + E = ASE->getBase(); + goto tryAgain; + } + } + + return SLCT_NotALiteral; + } default: return SLCT_NotALiteral; @@ -4204,15 +4702,16 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, Sema::FormatStringType Sema::GetFormatStringType(const FormatAttr *Format) { return llvm::StringSwitch<FormatStringType>(Format->getType()->getName()) - .Case("scanf", FST_Scanf) - .Cases("printf", "printf0", FST_Printf) - .Cases("NSString", "CFString", FST_NSString) - .Case("strftime", FST_Strftime) - .Case("strfmon", FST_Strfmon) - .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) - .Case("freebsd_kprintf", FST_FreeBSDKPrintf) - .Case("os_trace", FST_OSTrace) - .Default(FST_Unknown); + .Case("scanf", FST_Scanf) + .Cases("printf", "printf0", FST_Printf) + .Cases("NSString", "CFString", FST_NSString) + .Case("strftime", FST_Strftime) + .Case("strfmon", FST_Strfmon) + .Cases("kprintf", "cmn_err", "vcmn_err", "zcmn_err", FST_Kprintf) + .Case("freebsd_kprintf", FST_FreeBSDKPrintf) + .Case("os_trace", FST_OSLog) + .Case("os_log", FST_OSLog) + .Default(FST_Unknown); } /// CheckFormatArguments - Check calls to printf and scanf (and similar @@ -4262,8 +4761,9 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, StringLiteralCheckType CT = checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*IsFunctionCall*/true, CheckedVarArgs, - UncoveredArg); + /*IsFunctionCall*/ true, CheckedVarArgs, + UncoveredArg, + /*no string offset*/ llvm::APSInt(64, false) = 0); // Generate a diagnostic where an uncovered argument is detected. if (UncoveredArg.hasUncoveredArg()) { @@ -4319,8 +4819,9 @@ namespace { class CheckFormatHandler : public analyze_format_string::FormatStringHandler { protected: Sema &S; - const StringLiteral *FExpr; + const FormatStringLiteral *FExpr; const Expr *OrigFormatExpr; + const Sema::FormatStringType FSType; const unsigned FirstDataArg; const unsigned NumDataArgs; const char *Beg; // Start of format string. @@ -4336,21 +4837,20 @@ protected: UncoveredArgHandler &UncoveredArg; public: - CheckFormatHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, + CheckFormatHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, + const Sema::FormatStringType type, unsigned firstDataArg, unsigned numDataArgs, const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, - unsigned formatIdx, bool inFunctionCall, - Sema::VariadicCallType callType, + ArrayRef<const Expr *> Args, unsigned formatIdx, + bool inFunctionCall, Sema::VariadicCallType callType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), - FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), - Beg(beg), HasVAListArg(hasVAListArg), - Args(Args), FormatIdx(formatIdx), - usesPositionalArgs(false), atFirstArg(true), - inFunctionCall(inFunctionCall), CallType(callType), - CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { + : S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr), FSType(type), + FirstDataArg(firstDataArg), NumDataArgs(numDataArgs), Beg(beg), + HasVAListArg(hasVAListArg), Args(Args), FormatIdx(formatIdx), + usesPositionalArgs(false), atFirstArg(true), + inFunctionCall(inFunctionCall), CallType(callType), + CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } @@ -4436,7 +4936,8 @@ getSpecifierRange(const char *startSpecifier, unsigned specifierLen) { } SourceLocation CheckFormatHandler::getLocationOfByte(const char *x) { - return S.getLocationOfStringLiteralByte(FExpr, x - Beg); + return FExpr->getLocationOfByte(x - Beg, S.getSourceManager(), + S.getLangOpts(), S.Context.getTargetInfo()); } void CheckFormatHandler::HandleIncompleteSpecifier(const char *startSpecifier, @@ -4647,16 +5148,16 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, // hex value. std::string CodePointStr; if (!llvm::sys::locale::isPrint(*csStart)) { - UTF32 CodePoint; - const UTF8 **B = reinterpret_cast<const UTF8 **>(&csStart); - const UTF8 *E = - reinterpret_cast<const UTF8 *>(csStart + csLen); - ConversionResult Result = - llvm::convertUTF8Sequence(B, E, &CodePoint, strictConversion); - - if (Result != conversionOK) { + llvm::UTF32 CodePoint; + const llvm::UTF8 **B = reinterpret_cast<const llvm::UTF8 **>(&csStart); + const llvm::UTF8 *E = + reinterpret_cast<const llvm::UTF8 *>(csStart + csLen); + llvm::ConversionResult Result = + llvm::convertUTF8Sequence(B, E, &CodePoint, llvm::strictConversion); + + if (Result != llvm::conversionOK) { unsigned char FirstChar = *csStart; - CodePoint = (UTF32)FirstChar; + CodePoint = (llvm::UTF32)FirstChar; } llvm::raw_string_ostream OS(CodePointStr); @@ -4772,24 +5273,28 @@ void CheckFormatHandler::EmitFormatDiagnostic( namespace { class CheckPrintfHandler : public CheckFormatHandler { - bool ObjCContext; - public: - CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, - unsigned numDataArgs, bool isObjC, - const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, + CheckPrintfHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, + const Sema::FormatStringType type, unsigned firstDataArg, + unsigned numDataArgs, bool isObjC, const char *beg, + bool hasVAListArg, ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, - numDataArgs, beg, hasVAListArg, Args, - formatIdx, inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg), - ObjCContext(isObjC) - {} + : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, + numDataArgs, beg, hasVAListArg, Args, formatIdx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg) {} + + bool isObjCContext() const { return FSType == Sema::FST_NSString; } + + /// Returns true if '%@' specifiers are allowed in the format string. + bool allowsObjCArg() const { + return FSType == Sema::FST_NSString || FSType == Sema::FST_OSLog || + FSType == Sema::FST_OSTrace; + } bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -5143,11 +5648,54 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier // Check for using an Objective-C specific conversion specifier // in a non-ObjC literal. - if (!ObjCContext && CS.isObjCArg()) { + if (!allowsObjCArg() && CS.isObjCArg()) { + return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, + specifierLen); + } + + // %P can only be used with os_log. + if (FSType != Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::PArg) { return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, specifierLen); } + // %n is not allowed with os_log. + if (FSType == Sema::FST_OSLog && CS.getKind() == ConversionSpecifier::nArg) { + EmitFormatDiagnostic(S.PDiag(diag::warn_os_log_format_narg), + getLocationOfByte(CS.getStart()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + + return true; + } + + // Only scalars are allowed for os_trace. + if (FSType == Sema::FST_OSTrace && + (CS.getKind() == ConversionSpecifier::PArg || + CS.getKind() == ConversionSpecifier::sArg || + CS.getKind() == ConversionSpecifier::ObjCObjArg)) { + return HandleInvalidPrintfConversionSpecifier(FS, startSpecifier, + specifierLen); + } + + // Check for use of public/private annotation outside of os_log(). + if (FSType != Sema::FST_OSLog) { + if (FS.isPublic().isSet()) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) + << "public", + getLocationOfByte(FS.isPublic().getPosition()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + if (FS.isPrivate().isSet()) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_annotation) + << "private", + getLocationOfByte(FS.isPrivate().getPosition()), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + } + // Check for invalid use of field width if (!FS.hasValidFieldWidth()) { HandleInvalidAmount(FS, FS.getFieldWidth(), /* field width */ 0, @@ -5160,6 +5708,15 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier startSpecifier, specifierLen); } + // Precision is mandatory for %P specifier. + if (CS.getKind() == ConversionSpecifier::PArg && + FS.getPrecision().getHowSpecified() == OptionalAmount::NotSpecified) { + EmitFormatDiagnostic(S.PDiag(diag::warn_format_P_no_precision), + getLocationOfByte(startSpecifier), + /*IsStringLocation*/ false, + getSpecifierRange(startSpecifier, specifierLen)); + } + // Check each flag does not conflict with any other component. if (!FS.hasValidThousandsGroupingPrefix()) HandleFlag(FS, FS.hasThousandsGrouping(), startSpecifier, specifierLen); @@ -5309,8 +5866,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, using namespace analyze_printf; // Now type check the data expression that matches the // format specifier. - const analyze_printf::ArgType &AT = FS.getArgType(S.Context, - ObjCContext); + const analyze_printf::ArgType &AT = FS.getArgType(S.Context, isObjCContext()); if (!AT.isValid()) return true; @@ -5365,7 +5921,7 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // If the argument is an integer of some kind, believe the %C and suggest // a cast instead of changing the conversion specifier. QualType IntendedTy = ExprTy; - if (ObjCContext && + if (isObjCContext() && FS.getConversionSpecifier().getKind() == ConversionSpecifier::CArg) { if (ExprTy->isIntegralOrUnscopedEnumerationType() && !ExprTy->isCharType()) { @@ -5406,8 +5962,8 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, // We may be able to offer a FixItHint if it is a supported type. PrintfSpecifier fixedFS = FS; - bool success = fixedFS.fixType(IntendedTy, S.getLangOpts(), - S.Context, ObjCContext); + bool success = + fixedFS.fixType(IntendedTy, S.getLangOpts(), S.Context, isObjCContext()); if (success) { // Get the fix string from the fixed format specifier @@ -5562,20 +6118,19 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, namespace { class CheckScanfHandler : public CheckFormatHandler { public: - CheckScanfHandler(Sema &s, const StringLiteral *fexpr, - const Expr *origFormatExpr, unsigned firstDataArg, - unsigned numDataArgs, const char *beg, bool hasVAListArg, - ArrayRef<const Expr *> Args, - unsigned formatIdx, bool inFunctionCall, - Sema::VariadicCallType CallType, + CheckScanfHandler(Sema &s, const FormatStringLiteral *fexpr, + const Expr *origFormatExpr, Sema::FormatStringType type, + unsigned firstDataArg, unsigned numDataArgs, + const char *beg, bool hasVAListArg, + ArrayRef<const Expr *> Args, unsigned formatIdx, + bool inFunctionCall, Sema::VariadicCallType CallType, llvm::SmallBitVector &CheckedVarArgs, UncoveredArgHandler &UncoveredArg) - : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, - numDataArgs, beg, hasVAListArg, - Args, formatIdx, inFunctionCall, CallType, - CheckedVarArgs, UncoveredArg) - {} - + : CheckFormatHandler(s, fexpr, origFormatExpr, type, firstDataArg, + numDataArgs, beg, hasVAListArg, Args, formatIdx, + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg) {} + bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) override; @@ -5733,7 +6288,7 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } -static void CheckFormatString(Sema &S, const StringLiteral *FExpr, +static void CheckFormatString(Sema &S, const FormatStringLiteral *FExpr, const Expr *OrigFormatExpr, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, @@ -5785,13 +6340,13 @@ static void CheckFormatString(Sema &S, const StringLiteral *FExpr, } if (Type == Sema::FST_Printf || Type == Sema::FST_NSString || - Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) { - CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, - numDataArgs, (Type == Sema::FST_NSString || - Type == Sema::FST_OSTrace), - Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg); + Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSLog || + Type == Sema::FST_OSTrace) { + CheckPrintfHandler H( + S, FExpr, OrigFormatExpr, Type, firstDataArg, numDataArgs, + (Type == Sema::FST_NSString || Type == Sema::FST_OSTrace), Str, + HasVAListArg, Args, format_idx, inFunctionCall, CallType, + CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, S.getLangOpts(), @@ -5799,10 +6354,9 @@ static void CheckFormatString(Sema &S, const StringLiteral *FExpr, Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); } else if (Type == Sema::FST_Scanf) { - CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, - Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs, - UncoveredArg); + CheckScanfHandler H(S, FExpr, OrigFormatExpr, Type, firstDataArg, + numDataArgs, Str, HasVAListArg, Args, format_idx, + inFunctionCall, CallType, CheckedVarArgs, UncoveredArg); if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, S.getLangOpts(), @@ -6118,23 +6672,14 @@ static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, << FunctionName; } -static bool IsFunctionStdAbs(const FunctionDecl *FDecl) { +template <std::size_t StrLen> +static bool IsStdFunction(const FunctionDecl *FDecl, + const char (&Str)[StrLen]) { if (!FDecl) return false; - - if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr("abs")) - return false; - - const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(FDecl->getDeclContext()); - - while (ND && ND->isInlineNamespace()) { - ND = dyn_cast<NamespaceDecl>(ND->getDeclContext()); - } - - if (!ND || !ND->getIdentifier() || !ND->getIdentifier()->isStr("std")) + if (!FDecl->getIdentifier() || !FDecl->getIdentifier()->isStr(Str)) return false; - - if (!isa<TranslationUnitDecl>(ND->getDeclContext())) + if (!FDecl->isInStdNamespace()) return false; return true; @@ -6142,13 +6687,12 @@ static bool IsFunctionStdAbs(const FunctionDecl *FDecl) { // Warn when using the wrong abs() function. void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, - const FunctionDecl *FDecl, - IdentifierInfo *FnInfo) { + const FunctionDecl *FDecl) { if (Call->getNumArgs() != 1) return; unsigned AbsKind = getAbsoluteValueFunctionKind(FDecl); - bool IsStdAbs = IsFunctionStdAbs(FDecl); + bool IsStdAbs = IsStdFunction(FDecl, "abs"); if (AbsKind == 0 && !IsStdAbs) return; @@ -6221,6 +6765,69 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); } +//===--- CHECK: Warn on use of std::max and unsigned zero. r---------------===// +void Sema::CheckMaxUnsignedZero(const CallExpr *Call, + const FunctionDecl *FDecl) { + if (!Call || !FDecl) return; + + // Ignore template specializations and macros. + if (!ActiveTemplateInstantiations.empty()) return; + if (Call->getExprLoc().isMacroID()) return; + + // Only care about the one template argument, two function parameter std::max + if (Call->getNumArgs() != 2) return; + if (!IsStdFunction(FDecl, "max")) return; + const auto * ArgList = FDecl->getTemplateSpecializationArgs(); + if (!ArgList) return; + if (ArgList->size() != 1) return; + + // Check that template type argument is unsigned integer. + const auto& TA = ArgList->get(0); + if (TA.getKind() != TemplateArgument::Type) return; + QualType ArgType = TA.getAsType(); + if (!ArgType->isUnsignedIntegerType()) return; + + // See if either argument is a literal zero. + auto IsLiteralZeroArg = [](const Expr* E) -> bool { + const auto *MTE = dyn_cast<MaterializeTemporaryExpr>(E); + if (!MTE) return false; + const auto *Num = dyn_cast<IntegerLiteral>(MTE->GetTemporaryExpr()); + if (!Num) return false; + if (Num->getValue() != 0) return false; + return true; + }; + + const Expr *FirstArg = Call->getArg(0); + const Expr *SecondArg = Call->getArg(1); + const bool IsFirstArgZero = IsLiteralZeroArg(FirstArg); + const bool IsSecondArgZero = IsLiteralZeroArg(SecondArg); + + // Only warn when exactly one argument is zero. + if (IsFirstArgZero == IsSecondArgZero) return; + + SourceRange FirstRange = FirstArg->getSourceRange(); + SourceRange SecondRange = SecondArg->getSourceRange(); + + SourceRange ZeroRange = IsFirstArgZero ? FirstRange : SecondRange; + + Diag(Call->getExprLoc(), diag::warn_max_unsigned_zero) + << IsFirstArgZero << Call->getCallee()->getSourceRange() << ZeroRange; + + // Deduce what parts to remove so that "std::max(0u, foo)" becomes "(foo)". + SourceRange RemovalRange; + if (IsFirstArgZero) { + RemovalRange = SourceRange(FirstRange.getBegin(), + SecondRange.getBegin().getLocWithOffset(-1)); + } else { + RemovalRange = SourceRange(getLocForEndOfToken(FirstRange.getEnd()), + SecondRange.getEnd()); + } + + Diag(Call->getExprLoc(), diag::note_remove_max_call) + << FixItHint::CreateRemoval(Call->getCallee()->getSourceRange()) + << FixItHint::CreateRemoval(RemovalRange); +} + //===--- CHECK: Standard memory functions ---------------------------------===// /// \brief Takes the expression passed to the size_t parameter of functions @@ -6320,13 +6927,15 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, // It is possible to have a non-standard definition of memset. Validate // we have enough arguments, and if not, abort further checking. - unsigned ExpectedNumArgs = (BId == Builtin::BIstrndup ? 2 : 3); + unsigned ExpectedNumArgs = + (BId == Builtin::BIstrndup || BId == Builtin::BIbzero ? 2 : 3); if (Call->getNumArgs() < ExpectedNumArgs) return; - unsigned LastArg = (BId == Builtin::BImemset || + unsigned LastArg = (BId == Builtin::BImemset || BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); - unsigned LenArg = (BId == Builtin::BIstrndup ? 1 : 2); + unsigned LenArg = + (BId == Builtin::BIbzero || BId == Builtin::BIstrndup ? 1 : 2); const Expr *LenExpr = Call->getArg(LenArg)->IgnoreParenImpCasts(); if (CheckMemorySizeofForComparison(*this, LenExpr, FnName, @@ -6338,6 +6947,13 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, const Expr *SizeOfArg = getSizeOfExprArg(LenExpr); llvm::FoldingSetNodeID SizeOfArgID; + // Although widely used, 'bzero' is not a standard function. Be more strict + // with the argument types before allowing diagnostics and only allow the + // form bzero(ptr, sizeof(...)). + QualType FirstArgTy = Call->getArg(0)->IgnoreParenImpCasts()->getType(); + if (BId == Builtin::BIbzero && !FirstArgTy->getAs<PointerType>()) + return; + for (unsigned ArgIdx = 0; ArgIdx != LastArg; ++ArgIdx) { const Expr *Dest = Call->getArg(ArgIdx)->IgnoreParenImpCasts(); SourceRange ArgRange = Call->getArg(ArgIdx)->getSourceRange(); @@ -7960,6 +8576,24 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, return false; // White-list bool bitfields. + QualType BitfieldType = Bitfield->getType(); + if (BitfieldType->isBooleanType()) + return false; + + if (BitfieldType->isEnumeralType()) { + EnumDecl *BitfieldEnumDecl = BitfieldType->getAs<EnumType>()->getDecl(); + // If the underlying enum type was not explicitly specified as an unsigned + // type and the enum contain only positive values, MSVC++ will cause an + // inconsistency by storing this as a signed type. + if (S.getLangOpts().CPlusPlus11 && + !BitfieldEnumDecl->getIntegerTypeSourceInfo() && + BitfieldEnumDecl->getNumPositiveBits() > 0 && + BitfieldEnumDecl->getNumNegativeBits() == 0) { + S.Diag(InitLoc, diag::warn_no_underlying_type_specified_for_enum_bitfield) + << BitfieldEnumDecl->getNameAsString(); + } + } + if (Bitfield->getType()->isBooleanType()) return false; @@ -7979,18 +8613,17 @@ bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, unsigned OriginalWidth = Value.getBitWidth(); unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); - if (Value.isSigned() && Value.isNegative()) + if (!Value.isSigned() || Value.isNegative()) if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) - if (UO->getOpcode() == UO_Minus) - if (isa<IntegerLiteral>(UO->getSubExpr())) - OriginalWidth = Value.getMinSignedBits(); + if (UO->getOpcode() == UO_Minus || UO->getOpcode() == UO_Not) + OriginalWidth = Value.getMinSignedBits(); if (OriginalWidth <= FieldWidth) return false; // Compute the value which the bitfield will contain. llvm::APSInt TruncatedValue = Value.trunc(FieldWidth); - TruncatedValue.setIsSigned(Bitfield->getType()->isSignedIntegerType()); + TruncatedValue.setIsSigned(BitfieldType->isSignedIntegerType()); // Check whether the stored value is equal to the original value. TruncatedValue = TruncatedValue.extend(OriginalWidth); @@ -8515,6 +9148,8 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, DiagnoseNullConversion(S, E, T, CC); + S.DiscardMisalignedMemberAddress(Target, E); + if (!Source->isIntegerType() || !Target->isIntegerType()) return; @@ -8776,25 +9411,19 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) { } // end anonymous namespace -static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, - unsigned Start, unsigned End) { - bool IllegalParams = false; - for (unsigned I = Start; I <= End; ++I) { - QualType Ty = TheCall->getArg(I)->getType(); - // Taking into account implicit conversions, - // allow any integer within 32 bits range - if (!Ty->isIntegerType() || - S.Context.getTypeSizeInChars(Ty).getQuantity() > 4) { - S.Diag(TheCall->getArg(I)->getLocStart(), - diag::err_opencl_enqueue_kernel_invalid_local_size_type); - IllegalParams = true; - } - // Potentially emit standard warnings for implicit conversions if enabled - // using -Wconversion. - CheckImplicitConversion(S, TheCall->getArg(I), S.Context.UnsignedIntTy, - TheCall->getArg(I)->getLocStart()); +/// Diagnose integer type and any valid implicit convertion to it. +static bool checkOpenCLEnqueueIntType(Sema &S, Expr *E, const QualType &IntT) { + // Taking into account implicit conversions, + // allow any integer. + if (!E->getType()->isIntegerType()) { + S.Diag(E->getLocStart(), + diag::err_opencl_enqueue_kernel_invalid_local_size_type); + return true; } - return IllegalParams; + // Potentially emit standard warnings for implicit conversions if enabled + // using -Wconversion. + CheckImplicitConversion(S, E, IntT, E->getLocStart()); + return false; } // Helper function for Sema::DiagnoseAlwaysNonNullPointer. @@ -9585,6 +10214,7 @@ void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); + DiagnoseMisalignedMembers(); } void Sema::CheckBitFieldInitialization(SourceLocation InitLoc, @@ -9695,6 +10325,19 @@ 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()); + + if (const auto *ME = dyn_cast<MemberExpr>(E)) + return Context.getDeclAlign(ME->getMemberDecl()); + + return TypeAlign; +} + /// CheckCastAlign - Implements -Wcast-align, which warns when a /// pointer cast increases the alignment requirements. void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { @@ -9729,6 +10372,15 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { 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); + } + if (SrcAlign >= DestAlign) return; Diag(TRange.getBegin(), diag::warn_cast_align) @@ -11130,3 +11782,151 @@ void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, << ArgumentExpr->getSourceRange() << TypeTagExpr->getSourceRange(); } + +void Sema::AddPotentialMisalignedMembers(Expr *E, RecordDecl *RD, ValueDecl *MD, + CharUnits Alignment) { + MisalignedMembers.emplace_back(E, RD, MD, Alignment); +} + +void Sema::DiagnoseMisalignedMembers() { + for (MisalignedMember &m : MisalignedMembers) { + const NamedDecl *ND = m.RD; + if (ND->getName().empty()) { + if (const TypedefNameDecl *TD = m.RD->getTypedefNameForAnonDecl()) + ND = TD; + } + Diag(m.E->getLocStart(), diag::warn_taking_address_of_packed_member) + << m.MD << ND << m.E->getSourceRange(); + } + MisalignedMembers.clear(); +} + +void Sema::DiscardMisalignedMemberAddress(const Type *T, Expr *E) { + E = E->IgnoreParens(); + if (!T->isPointerType() && !T->isIntegerType()) + return; + if (isa<UnaryOperator>(E) && + cast<UnaryOperator>(E)->getOpcode() == UO_AddrOf) { + auto *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); + if (isa<MemberExpr>(Op)) { + auto MA = std::find(MisalignedMembers.begin(), MisalignedMembers.end(), + MisalignedMember(Op)); + if (MA != MisalignedMembers.end() && + (T->isIntegerType() || + (T->isPointerType() && + Context.getTypeAlignInChars(T->getPointeeType()) <= MA->Alignment))) + MisalignedMembers.erase(MA); + } + } +} + +void Sema::RefersToMemberWithReducedAlignment( + Expr *E, + llvm::function_ref<void(Expr *, RecordDecl *, FieldDecl *, CharUnits)> + Action) { + const auto *ME = dyn_cast<MemberExpr>(E); + if (!ME) + return; + + // For a chain of MemberExpr like "a.b.c.d" this list + // will keep FieldDecl's like [d, c, b]. + SmallVector<FieldDecl *, 4> ReverseMemberChain; + const MemberExpr *TopME = nullptr; + bool AnyIsPacked = false; + do { + QualType BaseType = ME->getBase()->getType(); + if (ME->isArrow()) + BaseType = BaseType->getPointeeType(); + RecordDecl *RD = BaseType->getAs<RecordType>()->getDecl(); + + ValueDecl *MD = ME->getMemberDecl(); + auto *FD = dyn_cast<FieldDecl>(MD); + // We do not care about non-data members. + if (!FD || FD->isInvalidDecl()) + return; + + AnyIsPacked = + AnyIsPacked || (RD->hasAttr<PackedAttr>() || MD->hasAttr<PackedAttr>()); + ReverseMemberChain.push_back(FD); + + TopME = ME; + ME = dyn_cast<MemberExpr>(ME->getBase()->IgnoreParens()); + } while (ME); + assert(TopME && "We did not compute a topmost MemberExpr!"); + + // Not the scope of this diagnostic. + if (!AnyIsPacked) + return; + + const Expr *TopBase = TopME->getBase()->IgnoreParenImpCasts(); + const auto *DRE = dyn_cast<DeclRefExpr>(TopBase); + // TODO: The innermost base of the member expression may be too complicated. + // For now, just disregard these cases. This is left for future + // improvement. + if (!DRE && !isa<CXXThisExpr>(TopBase)) + return; + + // Alignment expected by the whole expression. + CharUnits ExpectedAlignment = Context.getTypeAlignInChars(E->getType()); + + // No need to do anything else with this case. + if (ExpectedAlignment.isOne()) + return; + + // Synthesize offset of the whole access. + CharUnits Offset; + for (auto I = ReverseMemberChain.rbegin(); I != ReverseMemberChain.rend(); + I++) { + Offset += Context.toCharUnitsFromBits(Context.getFieldOffset(*I)); + } + + // Compute the CompleteObjectAlignment as the alignment of the whole chain. + CharUnits CompleteObjectAlignment = Context.getTypeAlignInChars( + ReverseMemberChain.back()->getParent()->getTypeForDecl()); + + // The base expression of the innermost MemberExpr may give + // stronger guarantees than the class containing the member. + if (DRE && !TopME->isArrow()) { + const ValueDecl *VD = DRE->getDecl(); + if (!VD->getType()->isReferenceType()) + CompleteObjectAlignment = + std::max(CompleteObjectAlignment, Context.getDeclAlign(VD)); + } + + // Check if the synthesized offset fulfills the alignment. + if (Offset % ExpectedAlignment != 0 || + // It may fulfill the offset it but the effective alignment may still be + // lower than the expected expression alignment. + CompleteObjectAlignment < ExpectedAlignment) { + // If this happens, we want to determine a sensible culprit of this. + // Intuitively, watching the chain of member expressions from right to + // left, we start with the required alignment (as required by the field + // type) but some packed attribute in that chain has reduced the alignment. + // It may happen that another packed structure increases it again. But if + // we are here such increase has not been enough. So pointing the first + // FieldDecl that either is packed or else its RecordDecl is, + // seems reasonable. + FieldDecl *FD = nullptr; + CharUnits Alignment; + for (FieldDecl *FDI : ReverseMemberChain) { + if (FDI->hasAttr<PackedAttr>() || + FDI->getParent()->hasAttr<PackedAttr>()) { + FD = FDI; + Alignment = std::min( + Context.getTypeAlignInChars(FD->getType()), + Context.getTypeAlignInChars(FD->getParent()->getTypeForDecl())); + break; + } + } + assert(FD && "We did not find a packed FieldDecl!"); + Action(E, FD->getParent(), FD, Alignment); + } +} + +void Sema::CheckAddressOfPackedMember(Expr *rhs) { + using namespace std::placeholders; + RefersToMemberWithReducedAlignment( + rhs, std::bind(&Sema::AddPotentialMisalignedMembers, std::ref(*this), _1, + _2, _3, _4)); +} + diff --git a/lib/Sema/SemaCodeComplete.cpp b/lib/Sema/SemaCodeComplete.cpp index 36babc4bc0cd6..d76bde5746774 100644 --- a/lib/Sema/SemaCodeComplete.cpp +++ b/lib/Sema/SemaCodeComplete.cpp @@ -2162,6 +2162,60 @@ static std::string formatObjCParamQualifiers(unsigned ObjCQuals, return Result; } +/// \brief Tries to find the most appropriate type location for an Objective-C +/// block placeholder. +/// +/// This function ignores things like typedefs and qualifiers in order to +/// present the most relevant and accurate block placeholders in code completion +/// results. +static void findTypeLocationForBlockDecl(const TypeSourceInfo *TSInfo, + FunctionTypeLoc &Block, + FunctionProtoTypeLoc &BlockProto, + bool SuppressBlock = false) { + if (!TSInfo) + return; + TypeLoc TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); + while (true) { + // Look through typedefs. + if (!SuppressBlock) { + if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) { + if (TypeSourceInfo *InnerTSInfo = + TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) { + TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); + continue; + } + } + + // Look through qualified types + if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) { + TL = QualifiedTL.getUnqualifiedLoc(); + continue; + } + + if (AttributedTypeLoc AttrTL = TL.getAs<AttributedTypeLoc>()) { + TL = AttrTL.getModifiedLoc(); + continue; + } + } + + // Try to get the function prototype behind the block pointer type, + // then we're done. + if (BlockPointerTypeLoc BlockPtr = TL.getAs<BlockPointerTypeLoc>()) { + TL = BlockPtr.getPointeeLoc().IgnoreParens(); + Block = TL.getAs<FunctionTypeLoc>(); + BlockProto = TL.getAs<FunctionProtoTypeLoc>(); + } + break; + } +} + +static std::string +formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, + FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, + bool SuppressBlockName = false, + bool SuppressBlock = false, + Optional<ArrayRef<QualType>> ObjCSubsts = None); + static std::string FormatFunctionParameter(const PrintingPolicy &Policy, const ParmVarDecl *Param, bool SuppressName = false, @@ -2192,47 +2246,13 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, } return Result; } - + // The argument for a block pointer parameter is a block literal with // the appropriate type. FunctionTypeLoc Block; FunctionProtoTypeLoc BlockProto; - TypeLoc TL; - if (TypeSourceInfo *TSInfo = Param->getTypeSourceInfo()) { - TL = TSInfo->getTypeLoc().getUnqualifiedLoc(); - while (true) { - // Look through typedefs. - if (!SuppressBlock) { - if (TypedefTypeLoc TypedefTL = TL.getAs<TypedefTypeLoc>()) { - if (TypeSourceInfo *InnerTSInfo = - TypedefTL.getTypedefNameDecl()->getTypeSourceInfo()) { - TL = InnerTSInfo->getTypeLoc().getUnqualifiedLoc(); - continue; - } - } - - // Look through qualified types - if (QualifiedTypeLoc QualifiedTL = TL.getAs<QualifiedTypeLoc>()) { - TL = QualifiedTL.getUnqualifiedLoc(); - continue; - } - - if (AttributedTypeLoc AttrTL = TL.getAs<AttributedTypeLoc>()) { - TL = AttrTL.getModifiedLoc(); - continue; - } - } - - // Try to get the function prototype behind the block pointer type, - // then we're done. - if (BlockPointerTypeLoc BlockPtr = TL.getAs<BlockPointerTypeLoc>()) { - TL = BlockPtr.getPointeeLoc().IgnoreParens(); - Block = TL.getAs<FunctionTypeLoc>(); - BlockProto = TL.getAs<FunctionProtoTypeLoc>(); - } - break; - } - } + findTypeLocationForBlockDecl(Param->getTypeSourceInfo(), Block, BlockProto, + SuppressBlock); if (!Block) { // We were unable to find a FunctionProtoTypeLoc with parameter names @@ -2244,9 +2264,13 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, QualType Type = Param->getType().getUnqualifiedType(); if (ObjCMethodParam) { - Result = "(" + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), - Type); - Result += Type.getAsString(Policy) + Result + ")"; + Result = Type.getAsString(Policy); + std::string Quals = + formatObjCParamQualifiers(Param->getObjCDeclQualifier(), Type); + if (!Quals.empty()) + Result = "(" + Quals + " " + Result + ")"; + if (Result.back() != ')') + Result += " "; if (Param->getIdentifier()) Result += Param->getIdentifier()->getName(); } else { @@ -2255,15 +2279,34 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, return Result; } - + // We have the function prototype behind the block pointer type, as it was // written in the source. + return formatBlockPlaceholder(Policy, Param, Block, BlockProto, + /*SuppressBlockName=*/false, SuppressBlock, + ObjCSubsts); +} + +/// \brief Returns a placeholder string that corresponds to an Objective-C block +/// declaration. +/// +/// \param BlockDecl A declaration with an Objective-C block type. +/// +/// \param Block The most relevant type location for that block type. +/// +/// \param SuppressBlockName Determines wether or not the name of the block +/// declaration is included in the resulting string. +static std::string +formatBlockPlaceholder(const PrintingPolicy &Policy, const NamedDecl *BlockDecl, + FunctionTypeLoc &Block, FunctionProtoTypeLoc &BlockProto, + bool SuppressBlockName, bool SuppressBlock, + Optional<ArrayRef<QualType>> ObjCSubsts) { std::string Result; QualType ResultType = Block.getTypePtr()->getReturnType(); if (ObjCSubsts) - ResultType = ResultType.substObjCTypeArgs(Param->getASTContext(), - *ObjCSubsts, - ObjCSubstitutionContext::Result); + ResultType = + ResultType.substObjCTypeArgs(BlockDecl->getASTContext(), *ObjCSubsts, + ObjCSubstitutionContext::Result); if (!ResultType->isVoidType() || SuppressBlock) ResultType.getAsStringInternal(Result, Policy); @@ -2281,31 +2324,30 @@ static std::string FormatFunctionParameter(const PrintingPolicy &Policy, Params += ", "; Params += FormatFunctionParameter(Policy, Block.getParam(I), /*SuppressName=*/false, - /*SuppressBlock=*/true, - ObjCSubsts); + /*SuppressBlock=*/true, ObjCSubsts); if (I == N - 1 && BlockProto.getTypePtr()->isVariadic()) Params += ", ..."; } Params += ")"; } - + if (SuppressBlock) { // Format as a parameter. Result = Result + " (^"; - if (Param->getIdentifier()) - Result += Param->getIdentifier()->getName(); + if (!SuppressBlockName && BlockDecl->getIdentifier()) + Result += BlockDecl->getIdentifier()->getName(); Result += ")"; Result += Params; } else { // Format as a block literal argument. Result = '^' + Result; Result += Params; - - if (Param->getIdentifier()) - Result += Param->getIdentifier()->getName(); + + if (!SuppressBlockName && BlockDecl->getIdentifier()) + Result += BlockDecl->getIdentifier()->getName(); } - + return Result; } @@ -3062,6 +3104,7 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { return CXCursor_ClassTemplatePartialSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; case Decl::StaticAssert: return CXCursor_StaticAssert; + case Decl::Friend: return CXCursor_FriendDecl; case Decl::TranslationUnit: return CXCursor_TranslationUnit; case Decl::Using: @@ -3573,82 +3616,204 @@ static ObjCContainerDecl *getContainerDef(ObjCContainerDecl *Container) { return Container; } -static void AddObjCProperties(const CodeCompletionContext &CCContext, - ObjCContainerDecl *Container, - bool AllowCategories, - bool AllowNullaryMethods, - DeclContext *CurContext, - AddedPropertiesSet &AddedProperties, - ResultBuilder &Results) { +/// \brief Adds a block invocation code completion result for the given block +/// declaration \p BD. +static void AddObjCBlockCall(ASTContext &Context, const PrintingPolicy &Policy, + CodeCompletionBuilder &Builder, + const NamedDecl *BD, + const FunctionTypeLoc &BlockLoc, + const FunctionProtoTypeLoc &BlockProtoLoc) { + Builder.AddResultTypeChunk( + GetCompletionTypeString(BlockLoc.getReturnLoc().getType(), Context, + Policy, Builder.getAllocator())); + + AddTypedNameChunk(Context, Policy, BD, Builder); + Builder.AddChunk(CodeCompletionString::CK_LeftParen); + + if (BlockProtoLoc && BlockProtoLoc.getTypePtr()->isVariadic()) { + Builder.AddPlaceholderChunk("..."); + } else { + for (unsigned I = 0, N = BlockLoc.getNumParams(); I != N; ++I) { + if (I) + Builder.AddChunk(CodeCompletionString::CK_Comma); + + // Format the placeholder string. + std::string PlaceholderStr = + FormatFunctionParameter(Policy, BlockLoc.getParam(I)); + + if (I == N - 1 && BlockProtoLoc && + BlockProtoLoc.getTypePtr()->isVariadic()) + PlaceholderStr += ", ..."; + + // Add the placeholder string. + Builder.AddPlaceholderChunk( + Builder.getAllocator().CopyString(PlaceholderStr)); + } + } + + Builder.AddChunk(CodeCompletionString::CK_RightParen); +} + +static void AddObjCProperties( + const CodeCompletionContext &CCContext, ObjCContainerDecl *Container, + bool AllowCategories, bool AllowNullaryMethods, DeclContext *CurContext, + AddedPropertiesSet &AddedProperties, ResultBuilder &Results, + bool IsBaseExprStatement = false, bool IsClassProperty = false) { typedef CodeCompletionResult Result; // Retrieve the definition. Container = getContainerDef(Container); // Add properties in this container. - for (const auto *P : Container->instance_properties()) - if (AddedProperties.insert(P->getIdentifier()).second) + const auto AddProperty = [&](const ObjCPropertyDecl *P) { + if (!AddedProperties.insert(P->getIdentifier()).second) + return; + + // FIXME: Provide block invocation completion for non-statement + // expressions. + if (!P->getType().getTypePtr()->isBlockPointerType() || + !IsBaseExprStatement) { + Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr), + CurContext); + return; + } + + // Block setter and invocation completion is provided only when we are able + // to find the FunctionProtoTypeLoc with parameter names for the block. + FunctionTypeLoc BlockLoc; + FunctionProtoTypeLoc BlockProtoLoc; + findTypeLocationForBlockDecl(P->getTypeSourceInfo(), BlockLoc, + BlockProtoLoc); + if (!BlockLoc) { Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr), CurContext); + return; + } - // Add nullary methods + // The default completion result for block properties should be the block + // invocation completion when the base expression is a statement. + CodeCompletionBuilder Builder(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + AddObjCBlockCall(Container->getASTContext(), + getCompletionPrintingPolicy(Results.getSema()), Builder, P, + BlockLoc, BlockProtoLoc); + Results.MaybeAddResult( + Result(Builder.TakeString(), P, Results.getBasePriority(P)), + CurContext); + + // Provide additional block setter completion iff the base expression is a + // statement and the block property is mutable. + if (!P->isReadOnly()) { + CodeCompletionBuilder Builder(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + AddResultTypeChunk(Container->getASTContext(), + getCompletionPrintingPolicy(Results.getSema()), P, + CCContext.getBaseType(), Builder); + Builder.AddTypedTextChunk( + Results.getAllocator().CopyString(P->getName())); + Builder.AddChunk(CodeCompletionString::CK_Equal); + + std::string PlaceholderStr = formatBlockPlaceholder( + getCompletionPrintingPolicy(Results.getSema()), P, BlockLoc, + BlockProtoLoc, /*SuppressBlockName=*/true); + // Add the placeholder string. + Builder.AddPlaceholderChunk( + Builder.getAllocator().CopyString(PlaceholderStr)); + + Results.MaybeAddResult( + Result(Builder.TakeString(), P, + Results.getBasePriority(P) + CCD_BlockPropertySetter), + CurContext); + } + }; + + if (IsClassProperty) { + for (const auto *P : Container->class_properties()) + AddProperty(P); + } else { + for (const auto *P : Container->instance_properties()) + AddProperty(P); + } + + // Add nullary methods or implicit class properties if (AllowNullaryMethods) { ASTContext &Context = Container->getASTContext(); PrintingPolicy Policy = getCompletionPrintingPolicy(Results.getSema()); - for (auto *M : Container->methods()) { - if (M->getSelector().isUnarySelector()) - if (IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0)) - if (AddedProperties.insert(Name).second) { - CodeCompletionBuilder Builder(Results.getAllocator(), - Results.getCodeCompletionTUInfo()); - AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), - Builder); - Builder.AddTypedTextChunk( - Results.getAllocator().CopyString(Name->getName())); - - Results.MaybeAddResult(Result(Builder.TakeString(), M, - CCP_MemberDeclaration + CCD_MethodAsProperty), - CurContext); - } + // Adds a method result + const auto AddMethod = [&](const ObjCMethodDecl *M) { + IdentifierInfo *Name = M->getSelector().getIdentifierInfoForSlot(0); + if (!Name) + return; + if (!AddedProperties.insert(Name).second) + return; + CodeCompletionBuilder Builder(Results.getAllocator(), + Results.getCodeCompletionTUInfo()); + AddResultTypeChunk(Context, Policy, M, CCContext.getBaseType(), Builder); + Builder.AddTypedTextChunk( + Results.getAllocator().CopyString(Name->getName())); + Results.MaybeAddResult( + Result(Builder.TakeString(), M, + CCP_MemberDeclaration + CCD_MethodAsProperty), + CurContext); + }; + + if (IsClassProperty) { + for (const auto *M : Container->methods()) { + // Gather the class method that can be used as implicit property + // getters. Methods with arguments or methods that return void aren't + // added to the results as they can't be used as a getter. + if (!M->getSelector().isUnarySelector() || + M->getReturnType()->isVoidType() || M->isInstanceMethod()) + continue; + AddMethod(M); + } + } else { + for (auto *M : Container->methods()) { + if (M->getSelector().isUnarySelector()) + AddMethod(M); + } } } - // Add properties in referenced protocols. if (ObjCProtocolDecl *Protocol = dyn_cast<ObjCProtocolDecl>(Container)) { for (auto *P : Protocol->protocols()) AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, - CurContext, AddedProperties, Results); + CurContext, AddedProperties, Results, + IsBaseExprStatement, IsClassProperty); } else if (ObjCInterfaceDecl *IFace = dyn_cast<ObjCInterfaceDecl>(Container)){ if (AllowCategories) { // Look through categories. for (auto *Cat : IFace->known_categories()) AddObjCProperties(CCContext, Cat, AllowCategories, AllowNullaryMethods, - CurContext, AddedProperties, Results); + CurContext, AddedProperties, Results, + IsBaseExprStatement, IsClassProperty); } // Look through protocols. for (auto *I : IFace->all_referenced_protocols()) AddObjCProperties(CCContext, I, AllowCategories, AllowNullaryMethods, - CurContext, AddedProperties, Results); - + CurContext, AddedProperties, Results, + IsBaseExprStatement, IsClassProperty); + // Look in the superclass. if (IFace->getSuperClass()) AddObjCProperties(CCContext, IFace->getSuperClass(), AllowCategories, - AllowNullaryMethods, CurContext, - AddedProperties, Results); + AllowNullaryMethods, CurContext, AddedProperties, + Results, IsBaseExprStatement, IsClassProperty); } else if (const ObjCCategoryDecl *Category = dyn_cast<ObjCCategoryDecl>(Container)) { // Look through protocols. for (auto *P : Category->protocols()) AddObjCProperties(CCContext, P, AllowCategories, AllowNullaryMethods, - CurContext, AddedProperties, Results); + CurContext, AddedProperties, Results, + IsBaseExprStatement, IsClassProperty); } } void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, - SourceLocation OpLoc, - bool IsArrow) { + SourceLocation OpLoc, bool IsArrow, + bool IsBaseExprStatement) { if (!Base || !CodeCompleter) return; @@ -3720,22 +3885,24 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Results.AddResult(Result("template")); } } - } else if (!IsArrow && BaseType->getAsObjCInterfacePointerType()) { + } else if (!IsArrow && BaseType->isObjCObjectPointerType()) { // Objective-C property reference. AddedPropertiesSet AddedProperties; - - // Add property results based on our interface. - const ObjCObjectPointerType *ObjCPtr - = BaseType->getAsObjCInterfacePointerType(); - assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); - AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, - /*AllowNullaryMethods=*/true, CurContext, - AddedProperties, Results); - + + if (const ObjCObjectPointerType *ObjCPtr = + BaseType->getAsObjCInterfacePointerType()) { + // Add property results based on our interface. + assert(ObjCPtr && "Non-NULL pointer guaranteed above!"); + AddObjCProperties(CCContext, ObjCPtr->getInterfaceDecl(), true, + /*AllowNullaryMethods=*/true, CurContext, + AddedProperties, Results, IsBaseExprStatement); + } + // Add properties from the protocols in a qualified interface. - for (auto *I : ObjCPtr->quals()) + for (auto *I : BaseType->getAs<ObjCObjectPointerType>()->quals()) AddObjCProperties(CCContext, I, true, /*AllowNullaryMethods=*/true, - CurContext, AddedProperties, Results); + CurContext, AddedProperties, Results, + IsBaseExprStatement); } else if ((IsArrow && BaseType->isObjCObjectPointerType()) || (!IsArrow && BaseType->isObjCObjectType())) { // Objective-C instance variable access. @@ -3765,6 +3932,30 @@ void Sema::CodeCompleteMemberReferenceExpr(Scope *S, Expr *Base, Results.data(),Results.size()); } +void Sema::CodeCompleteObjCClassPropertyRefExpr(Scope *S, + IdentifierInfo &ClassName, + SourceLocation ClassNameLoc, + bool IsBaseExprStatement) { + IdentifierInfo *ClassNamePtr = &ClassName; + ObjCInterfaceDecl *IFace = getObjCInterfaceDecl(ClassNamePtr, ClassNameLoc); + if (!IFace) + return; + CodeCompletionContext CCContext( + CodeCompletionContext::CCC_ObjCPropertyAccess); + ResultBuilder Results(*this, CodeCompleter->getAllocator(), + CodeCompleter->getCodeCompletionTUInfo(), CCContext, + &ResultBuilder::IsMember); + Results.EnterNewScope(); + AddedPropertiesSet AddedProperties; + AddObjCProperties(CCContext, IFace, true, + /*AllowNullaryMethods=*/true, CurContext, AddedProperties, + Results, IsBaseExprStatement, + /*IsClassProperty=*/true); + Results.ExitScope(); + HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), + Results.data(), Results.size()); +} + void Sema::CodeCompleteTag(Scope *S, unsigned TagSpec) { if (!CodeCompleter) return; @@ -5952,7 +6143,7 @@ void Sema::CodeCompleteObjCProtocolReferences( CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); - if (CodeCompleter && CodeCompleter->includeGlobals()) { + if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); // Tell the result set to ignore all of the protocols we have @@ -5980,7 +6171,7 @@ void Sema::CodeCompleteObjCProtocolDecl(Scope *) { CodeCompleter->getCodeCompletionTUInfo(), CodeCompletionContext::CCC_ObjCProtocolName); - if (CodeCompleter && CodeCompleter->includeGlobals()) { + if (CodeCompleter->includeGlobals()) { Results.EnterNewScope(); // Add all protocols. @@ -7008,7 +7199,7 @@ static void AddObjCKeyValueCompletions(ObjCPropertyDecl *Property, .second) { if (ReturnType.isNull()) { Builder.AddChunk(CodeCompletionString::CK_LeftParen); - Builder.AddTextChunk("NSSet *"); + Builder.AddTextChunk("NSSet<NSString *> *"); Builder.AddChunk(CodeCompletionString::CK_RightParen); } diff --git a/lib/Sema/SemaCoroutine.cpp b/lib/Sema/SemaCoroutine.cpp index c8715fff41596..3109358df4645 100644 --- a/lib/Sema/SemaCoroutine.cpp +++ b/lib/Sema/SemaCoroutine.cpp @@ -26,15 +26,15 @@ using namespace sema; static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, SourceLocation Loc) { // FIXME: Cache std::coroutine_traits once we've found it. - NamespaceDecl *Std = S.getStdNamespace(); - if (!Std) { + NamespaceDecl *StdExp = S.lookupStdExperimentalNamespace(); + if (!StdExp) { S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); return QualType(); } LookupResult Result(S, &S.PP.getIdentifierTable().get("coroutine_traits"), Loc, Sema::LookupOrdinaryName); - if (!S.LookupQualifiedName(Result, Std)) { + if (!S.LookupQualifiedName(Result, StdExp)) { S.Diag(Loc, diag::err_implied_std_coroutine_traits_not_found); return QualType(); } @@ -78,7 +78,7 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, auto *Promise = R.getAsSingle<TypeDecl>(); if (!Promise) { S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_found) - << RD; + << RD; return QualType(); } @@ -86,75 +86,131 @@ static QualType lookupPromiseType(Sema &S, const FunctionProtoType *FnType, QualType PromiseType = S.Context.getTypeDeclType(Promise); if (!PromiseType->getAsCXXRecordDecl()) { // Use the fully-qualified name of the type. - auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, Std); + auto *NNS = NestedNameSpecifier::Create(S.Context, nullptr, StdExp); NNS = NestedNameSpecifier::Create(S.Context, NNS, false, CoroTrait.getTypePtr()); PromiseType = S.Context.getElaboratedType(ETK_None, NNS, PromiseType); S.Diag(Loc, diag::err_implied_std_coroutine_traits_promise_type_not_class) - << PromiseType; + << PromiseType; return QualType(); } return PromiseType; } -/// Check that this is a context in which a coroutine suspension can appear. -static FunctionScopeInfo * -checkCoroutineContext(Sema &S, SourceLocation Loc, StringRef Keyword) { +static bool isValidCoroutineContext(Sema &S, SourceLocation Loc, + StringRef Keyword) { // 'co_await' and 'co_yield' are not permitted in unevaluated operands. if (S.isUnevaluatedContext()) { S.Diag(Loc, diag::err_coroutine_unevaluated_context) << Keyword; - return nullptr; + return false; } // Any other usage must be within a function. - // FIXME: Reject a coroutine with a deduced return type. auto *FD = dyn_cast<FunctionDecl>(S.CurContext); if (!FD) { S.Diag(Loc, isa<ObjCMethodDecl>(S.CurContext) ? diag::err_coroutine_objc_method : diag::err_coroutine_outside_function) << Keyword; - } else if (isa<CXXConstructorDecl>(FD) || isa<CXXDestructorDecl>(FD)) { - // Coroutines TS [special]/6: - // A special member function shall not be a coroutine. - // - // FIXME: We assume that this really means that a coroutine cannot - // be a constructor or destructor. - S.Diag(Loc, diag::err_coroutine_ctor_dtor) - << isa<CXXDestructorDecl>(FD) << Keyword; - } else if (FD->isConstexpr()) { - S.Diag(Loc, diag::err_coroutine_constexpr) << Keyword; - } else if (FD->isVariadic()) { - S.Diag(Loc, diag::err_coroutine_varargs) << Keyword; - } else { - auto *ScopeInfo = S.getCurFunction(); - assert(ScopeInfo && "missing function scope for function"); - - // If we don't have a promise variable, build one now. - if (!ScopeInfo->CoroutinePromise) { - QualType T = - FD->getType()->isDependentType() - ? S.Context.DependentTy - : lookupPromiseType(S, FD->getType()->castAs<FunctionProtoType>(), - Loc); - if (T.isNull()) - return nullptr; - - // Create and default-initialize the promise. - ScopeInfo->CoroutinePromise = - VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(), - &S.PP.getIdentifierTable().get("__promise"), T, - S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None); - S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise); - if (!ScopeInfo->CoroutinePromise->isInvalidDecl()) - S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false); - } + return false; + } - return ScopeInfo; + // An enumeration for mapping the diagnostic type to the correct diagnostic + // selection index. + enum InvalidFuncDiag { + DiagCtor = 0, + DiagDtor, + DiagCopyAssign, + DiagMoveAssign, + DiagMain, + DiagConstexpr, + DiagAutoRet, + DiagVarargs, + }; + bool Diagnosed = false; + auto DiagInvalid = [&](InvalidFuncDiag ID) { + S.Diag(Loc, diag::err_coroutine_invalid_func_context) << ID << Keyword; + Diagnosed = true; + return false; + }; + + // Diagnose when a constructor, destructor, copy/move assignment operator, + // or the function 'main' are declared as a coroutine. + auto *MD = dyn_cast<CXXMethodDecl>(FD); + if (MD && isa<CXXConstructorDecl>(MD)) + return DiagInvalid(DiagCtor); + else if (MD && isa<CXXDestructorDecl>(MD)) + return DiagInvalid(DiagDtor); + else if (MD && MD->isCopyAssignmentOperator()) + return DiagInvalid(DiagCopyAssign); + else if (MD && MD->isMoveAssignmentOperator()) + return DiagInvalid(DiagMoveAssign); + else if (FD->isMain()) + return DiagInvalid(DiagMain); + + // Emit a diagnostics for each of the following conditions which is not met. + if (FD->isConstexpr()) + DiagInvalid(DiagConstexpr); + if (FD->getReturnType()->isUndeducedType()) + DiagInvalid(DiagAutoRet); + if (FD->isVariadic()) + DiagInvalid(DiagVarargs); + + return !Diagnosed; +} + +/// Check that this is a context in which a coroutine suspension can appear. +static FunctionScopeInfo *checkCoroutineContext(Sema &S, SourceLocation Loc, + StringRef Keyword) { + if (!isValidCoroutineContext(S, Loc, Keyword)) + return nullptr; + + assert(isa<FunctionDecl>(S.CurContext) && "not in a function scope"); + auto *FD = cast<FunctionDecl>(S.CurContext); + auto *ScopeInfo = S.getCurFunction(); + assert(ScopeInfo && "missing function scope for function"); + + // If we don't have a promise variable, build one now. + if (!ScopeInfo->CoroutinePromise) { + QualType T = FD->getType()->isDependentType() + ? S.Context.DependentTy + : lookupPromiseType( + S, FD->getType()->castAs<FunctionProtoType>(), Loc); + if (T.isNull()) + return nullptr; + + // Create and default-initialize the promise. + ScopeInfo->CoroutinePromise = + VarDecl::Create(S.Context, FD, FD->getLocation(), FD->getLocation(), + &S.PP.getIdentifierTable().get("__promise"), T, + S.Context.getTrivialTypeSourceInfo(T, Loc), SC_None); + S.CheckVariableDeclarationType(ScopeInfo->CoroutinePromise); + if (!ScopeInfo->CoroutinePromise->isInvalidDecl()) + S.ActOnUninitializedDecl(ScopeInfo->CoroutinePromise, false); } - return nullptr; + return ScopeInfo; +} + +static Expr *buildBuiltinCall(Sema &S, SourceLocation Loc, Builtin::ID Id, + MutableArrayRef<Expr *> CallArgs) { + StringRef Name = S.Context.BuiltinInfo.getName(Id); + LookupResult R(S, &S.Context.Idents.get(Name), Loc, Sema::LookupOrdinaryName); + S.LookupName(R, S.TUScope, /*AllowBuiltinCreation=*/true); + + auto *BuiltInDecl = R.getAsSingle<FunctionDecl>(); + assert(BuiltInDecl && "failed to find builtin declaration"); + + ExprResult DeclRef = + S.BuildDeclRefExpr(BuiltInDecl, BuiltInDecl->getType(), VK_LValue, Loc); + assert(DeclRef.isUsable() && "Builtin reference cannot fail"); + + ExprResult Call = + S.ActOnCallExpr(/*Scope=*/nullptr, DeclRef.get(), Loc, CallArgs, Loc); + + assert(!Call.isInvalid() && "Call to builtin cannot fail!"); + return Call.get(); } /// Build a call to 'operator co_await' if there is a suitable operator for @@ -199,7 +255,7 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc, const StringRef Funcs[] = {"await_ready", "await_suspend", "await_resume"}; for (size_t I = 0, N = llvm::array_lengthof(Funcs); I != N; ++I) { Expr *Operand = new (S.Context) OpaqueValueExpr( - Loc, E->getType(), VK_LValue, E->getObjectKind(), E); + Loc, E->getType(), VK_LValue, E->getObjectKind(), E); // FIXME: Pass coroutine handle to await_suspend. ExprResult Result = buildMemberCall(S, Operand, Loc, Funcs[I], None); @@ -213,6 +269,11 @@ static ReadySuspendResumeResult buildCoawaitCalls(Sema &S, SourceLocation Loc, } ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_await"); + if (!Coroutine) { + CorrectDelayedTyposInExpr(E); + return ExprError(); + } if (E->getType()->isPlaceholderType()) { ExprResult R = CheckPlaceholderExpr(E); if (R.isInvalid()) return ExprError(); @@ -222,6 +283,7 @@ ExprResult Sema::ActOnCoawaitExpr(Scope *S, SourceLocation Loc, Expr *E) { ExprResult Awaitable = buildOperatorCoawaitCall(*this, S, Loc, E); if (Awaitable.isInvalid()) return ExprError(); + return BuildCoawaitExpr(Loc, Awaitable.get()); } ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { @@ -275,8 +337,10 @@ static ExprResult buildPromiseCall(Sema &S, FunctionScopeInfo *Coroutine, ExprResult Sema::ActOnCoyieldExpr(Scope *S, SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_yield"); - if (!Coroutine) + if (!Coroutine) { + CorrectDelayedTyposInExpr(E); return ExprError(); + } // Build yield_value call. ExprResult Awaitable = @@ -325,8 +389,14 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { } StmtResult Sema::ActOnCoreturnStmt(SourceLocation Loc, Expr *E) { + auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); + if (!Coroutine) { + CorrectDelayedTyposInExpr(E); + return StmtError(); + } return BuildCoreturnStmt(Loc, E); } + StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { auto *Coroutine = checkCoroutineContext(*this, Loc, "co_return"); if (!Coroutine) @@ -343,7 +413,7 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { // of scope, we should treat the operand as an xvalue for this overload // resolution. ExprResult PC; - if (E && !E->getType()->isVoidType()) { + if (E && (isa<InitListExpr>(E) || !E->getType()->isVoidType())) { PC = buildPromiseCall(*this, Coroutine, Loc, "return_value", E); } else { E = MakeFullDiscardedValueExpr(E).get(); @@ -359,6 +429,141 @@ StmtResult Sema::BuildCoreturnStmt(SourceLocation Loc, Expr *E) { return Res; } +static ExprResult buildStdCurrentExceptionCall(Sema &S, SourceLocation Loc) { + NamespaceDecl *Std = S.getStdNamespace(); + if (!Std) { + S.Diag(Loc, diag::err_implied_std_current_exception_not_found); + return ExprError(); + } + LookupResult Result(S, &S.PP.getIdentifierTable().get("current_exception"), + Loc, Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) { + S.Diag(Loc, diag::err_implied_std_current_exception_not_found); + return ExprError(); + } + + // FIXME The STL is free to provide more than one overload. + FunctionDecl *FD = Result.getAsSingle<FunctionDecl>(); + if (!FD) { + S.Diag(Loc, diag::err_malformed_std_current_exception); + return ExprError(); + } + ExprResult Res = S.BuildDeclRefExpr(FD, FD->getType(), VK_LValue, Loc); + Res = S.ActOnCallExpr(/*Scope*/ nullptr, Res.get(), Loc, None, Loc); + if (Res.isInvalid()) { + S.Diag(Loc, diag::err_malformed_std_current_exception); + return ExprError(); + } + return Res; +} + +// Find an appropriate delete for the promise. +static FunctionDecl *findDeleteForPromise(Sema &S, SourceLocation Loc, + QualType PromiseType) { + FunctionDecl *OperatorDelete = nullptr; + + DeclarationName DeleteName = + S.Context.DeclarationNames.getCXXOperatorName(OO_Delete); + + auto *PointeeRD = PromiseType->getAsCXXRecordDecl(); + assert(PointeeRD && "PromiseType must be a CxxRecordDecl type"); + + if (S.FindDeallocationFunction(Loc, PointeeRD, DeleteName, OperatorDelete)) + return nullptr; + + if (!OperatorDelete) { + // Look for a global declaration. + const bool CanProvideSize = S.isCompleteType(Loc, PromiseType); + const bool Overaligned = false; + OperatorDelete = S.FindUsualDeallocationFunction(Loc, CanProvideSize, + Overaligned, DeleteName); + } + S.MarkFunctionReferenced(Loc, OperatorDelete); + return OperatorDelete; +} + +// Builds allocation and deallocation for the coroutine. Returns false on +// failure. +static bool buildAllocationAndDeallocation(Sema &S, SourceLocation Loc, + FunctionScopeInfo *Fn, + Expr *&Allocation, + Stmt *&Deallocation) { + TypeSourceInfo *TInfo = Fn->CoroutinePromise->getTypeSourceInfo(); + QualType PromiseType = TInfo->getType(); + if (PromiseType->isDependentType()) + return true; + + if (S.RequireCompleteType(Loc, PromiseType, diag::err_incomplete_type)) + return false; + + // FIXME: Add support for get_return_object_on_allocation failure. + // FIXME: Add support for stateful allocators. + + FunctionDecl *OperatorNew = nullptr; + FunctionDecl *OperatorDelete = nullptr; + FunctionDecl *UnusedResult = nullptr; + bool PassAlignment = false; + + S.FindAllocationFunctions(Loc, SourceRange(), + /*UseGlobal*/ false, PromiseType, + /*isArray*/ false, PassAlignment, + /*PlacementArgs*/ None, OperatorNew, UnusedResult); + + OperatorDelete = findDeleteForPromise(S, Loc, PromiseType); + + if (!OperatorDelete || !OperatorNew) + return false; + + Expr *FramePtr = + buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_frame, {}); + + Expr *FrameSize = + buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_size, {}); + + // Make new call. + + ExprResult NewRef = + S.BuildDeclRefExpr(OperatorNew, OperatorNew->getType(), VK_LValue, Loc); + if (NewRef.isInvalid()) + return false; + + ExprResult NewExpr = + S.ActOnCallExpr(S.getCurScope(), NewRef.get(), Loc, FrameSize, Loc); + if (NewExpr.isInvalid()) + return false; + + Allocation = NewExpr.get(); + + // Make delete call. + + QualType OpDeleteQualType = OperatorDelete->getType(); + + ExprResult DeleteRef = + S.BuildDeclRefExpr(OperatorDelete, OpDeleteQualType, VK_LValue, Loc); + if (DeleteRef.isInvalid()) + return false; + + Expr *CoroFree = + buildBuiltinCall(S, Loc, Builtin::BI__builtin_coro_free, {FramePtr}); + + SmallVector<Expr *, 2> DeleteArgs{CoroFree}; + + // Check if we need to pass the size. + const auto *OpDeleteType = + OpDeleteQualType.getTypePtr()->getAs<FunctionProtoType>(); + if (OpDeleteType->getNumParams() > 1) + DeleteArgs.push_back(FrameSize); + + ExprResult DeleteExpr = + S.ActOnCallExpr(S.getCurScope(), DeleteRef.get(), Loc, DeleteArgs, Loc); + if (DeleteExpr.isInvalid()) + return false; + + Deallocation = DeleteExpr.get(); + + return true; +} + void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { FunctionScopeInfo *Fn = getCurFunction(); assert(Fn && !Fn->CoroutineStmts.empty() && "not a coroutine"); @@ -369,8 +574,8 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { Diag(Fn->FirstReturnLoc, diag::err_return_in_coroutine); auto *First = Fn->CoroutineStmts[0]; Diag(First->getLocStart(), diag::note_declared_coroutine_here) - << (isa<CoawaitExpr>(First) ? 0 : - isa<CoyieldExpr>(First) ? 1 : 2); + << (isa<CoawaitExpr>(First) ? 0 : + isa<CoyieldExpr>(First) ? 1 : 2); } bool AnyCoawaits = false; @@ -413,15 +618,69 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { if (FinalSuspend.isInvalid()) return FD->setInvalidDecl(); - // FIXME: Perform analysis of set_exception call. + // Form and check allocation and deallocation calls. + Expr *Allocation = nullptr; + Stmt *Deallocation = nullptr; + if (!buildAllocationAndDeallocation(*this, Loc, Fn, Allocation, Deallocation)) + return FD->setInvalidDecl(); - // FIXME: Try to form 'p.return_void();' expression statement to handle // control flowing off the end of the coroutine. + // Also try to form 'p.set_exception(std::current_exception());' to handle + // uncaught exceptions. + ExprResult SetException; + StmtResult Fallthrough; + if (Fn->CoroutinePromise && + !Fn->CoroutinePromise->getType()->isDependentType()) { + CXXRecordDecl *RD = Fn->CoroutinePromise->getType()->getAsCXXRecordDecl(); + assert(RD && "Type should have already been checked"); + // [dcl.fct.def.coroutine]/4 + // The unqualified-ids 'return_void' and 'return_value' are looked up in + // the scope of class P. If both are found, the program is ill-formed. + DeclarationName RVoidDN = PP.getIdentifierInfo("return_void"); + LookupResult RVoidResult(*this, RVoidDN, Loc, Sema::LookupMemberName); + const bool HasRVoid = LookupQualifiedName(RVoidResult, RD); + + DeclarationName RValueDN = PP.getIdentifierInfo("return_value"); + LookupResult RValueResult(*this, RValueDN, Loc, Sema::LookupMemberName); + const bool HasRValue = LookupQualifiedName(RValueResult, RD); + + if (HasRVoid && HasRValue) { + // FIXME Improve this diagnostic + Diag(FD->getLocation(), diag::err_coroutine_promise_return_ill_formed) + << RD; + return FD->setInvalidDecl(); + } else if (HasRVoid) { + // If the unqualified-id return_void is found, flowing off the end of a + // coroutine is equivalent to a co_return with no operand. Otherwise, + // flowing off the end of a coroutine results in undefined behavior. + Fallthrough = BuildCoreturnStmt(FD->getLocation(), nullptr); + Fallthrough = ActOnFinishFullStmt(Fallthrough.get()); + if (Fallthrough.isInvalid()) + return FD->setInvalidDecl(); + } + + // [dcl.fct.def.coroutine]/3 + // The unqualified-id set_exception is found in the scope of P by class + // member access lookup (3.4.5). + DeclarationName SetExDN = PP.getIdentifierInfo("set_exception"); + LookupResult SetExResult(*this, SetExDN, Loc, Sema::LookupMemberName); + if (LookupQualifiedName(SetExResult, RD)) { + // Form the call 'p.set_exception(std::current_exception())' + SetException = buildStdCurrentExceptionCall(*this, Loc); + if (SetException.isInvalid()) + return FD->setInvalidDecl(); + Expr *E = SetException.get(); + SetException = buildPromiseCall(*this, Fn, Loc, "set_exception", E); + SetException = ActOnFinishFullExpr(SetException.get(), Loc); + if (SetException.isInvalid()) + return FD->setInvalidDecl(); + } + } // Build implicit 'p.get_return_object()' expression and form initialization // of return type from it. ExprResult ReturnObject = - buildPromiseCall(*this, Fn, Loc, "get_return_object", None); + buildPromiseCall(*this, Fn, Loc, "get_return_object", None); if (ReturnObject.isInvalid()) return FD->setInvalidDecl(); QualType RetType = FD->getReturnType(); @@ -443,6 +702,6 @@ void Sema::CheckCompletedCoroutineBody(FunctionDecl *FD, Stmt *&Body) { // Build body for the coroutine wrapper statement. Body = new (Context) CoroutineBodyStmt( Body, PromiseStmt.get(), InitialSuspend.get(), FinalSuspend.get(), - /*SetException*/nullptr, /*Fallthrough*/nullptr, + SetException.get(), Fallthrough.get(), Allocation, Deallocation, ReturnObject.get(), ParamMoves); } diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 41719d4e7b08f..c32757565dd10 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -41,6 +40,7 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/Triple.h" @@ -780,8 +780,8 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, ObjCMethodDecl *CurMethod = getCurMethodDecl(); if (NextToken.is(tok::coloncolon)) { - BuildCXXNestedNameSpecifier(S, *Name, NameLoc, NextToken.getLocation(), - QualType(), false, SS, nullptr, false); + NestedNameSpecInfo IdInfo(Name, NameLoc, NextToken.getLocation()); + BuildCXXNestedNameSpecifier(S, IdInfo, false, SS, nullptr, false); } LookupResult Result(*this, Name, NameLoc, LookupOrdinaryName); @@ -1522,7 +1522,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { // White-list anything with an __attribute__((unused)) type. - QualType Ty = VD->getType(); + const auto *Ty = VD->getType().getTypePtr(); // Only look at the outermost level of typedef. if (const TypedefType *TT = Ty->getAs<TypedefType>()) { @@ -1535,6 +1535,10 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (Ty->isIncompleteType() || Ty->isDependentType()) return false; + // Look at the element type to ensure that the warning behaviour is + // consistent for both scalars and arrays. + Ty = Ty->getBaseElementTypeUnsafe(); + if (const TagType *TT = Ty->getAs<TagType>()) { const TagDecl *Tag = TT->getDecl(); if (Tag->hasAttr<UnusedAttr>()) @@ -1791,7 +1795,9 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, return nullptr; } - if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) { + if (!ForRedeclaration && + (Context.BuiltinInfo.isPredefinedLibFunction(ID) || + Context.BuiltinInfo.isHeaderDependentFunction(ID))) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.getName(ID) << R; if (Context.BuiltinInfo.getHeaderName(ID) && @@ -2246,6 +2252,13 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) { static bool mergeDeclAttribute(Sema &S, NamedDecl *D, const InheritableAttr *Attr, Sema::AvailabilityMergeKind AMK) { + // This function copies an attribute Attr from a previous declaration to the + // new declaration D if the new declaration doesn't itself have that attribute + // yet or if that attribute allows duplicates. + // If you're adding a new attribute that requires logic different from + // "use explicit attribute on decl if present, else use attribute from + // previous decl", for example if the attribute needs to be consistent + // between redeclarations, you need to call a custom merge function here. InheritableAttr *NewAttr = nullptr; unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr)) @@ -2283,7 +2296,13 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, NewAttr = S.mergeAlwaysInlineAttr(D, AA->getRange(), &S.Context.Idents.get(AA->getSpelling()), AttrSpellingListIndex); - else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr)) + else if (S.getLangOpts().CUDA && isa<FunctionDecl>(D) && + (isa<CUDAHostAttr>(Attr) || isa<CUDADeviceAttr>(Attr) || + isa<CUDAGlobalAttr>(Attr))) { + // CUDA target attributes are part of function signature for + // overloading purposes and must not be merged. + return false; + } else if (const auto *MA = dyn_cast<MinSizeAttr>(Attr)) NewAttr = S.mergeMinSizeAttr(D, MA->getRange(), AttrSpellingListIndex); else if (const auto *OA = dyn_cast<OptimizeNoneAttr>(Attr)) NewAttr = S.mergeOptimizeNoneAttr(D, OA->getRange(), AttrSpellingListIndex); @@ -2304,6 +2323,9 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, (AMK == Sema::AMK_Override || AMK == Sema::AMK_ProtocolImplementation)) NewAttr = nullptr; + else if (const auto *UA = dyn_cast<UuidAttr>(Attr)) + NewAttr = S.mergeUuidAttr(D, UA->getRange(), AttrSpellingListIndex, + UA->getGuid()); else if (Attr->duplicatesAllowed() || !DeclHasAttr(D, Attr)) NewAttr = cast<InheritableAttr>(Attr->clone(S.Context)); @@ -2915,10 +2937,20 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, } if (getLangOpts().CPlusPlus) { - // (C++98 13.1p2): + // C++1z [over.load]p2 // Certain function declarations cannot be overloaded: - // -- Function declarations that differ only in the return type - // cannot be overloaded. + // -- Function declarations that differ only in the return type, + // the exception specification, or both cannot be overloaded. + + // Check the exception specifications match. This may recompute the type of + // both Old and New if it resolved exception specifications, so grab the + // types again after this. Because this updates the type, we do this before + // any of the other checks below, which may update the "de facto" NewQType + // but do not necessarily update the type of New. + if (CheckEquivalentExceptionSpec(Old, New)) + return true; + OldQType = Context.getCanonicalType(Old->getType()); + NewQType = Context.getCanonicalType(New->getType()); // Go back to the type source info to compare the declared return types, // per C++1y [dcl.type.auto]p13: @@ -2933,10 +2965,10 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, (New->getTypeSourceInfo() ? New->getTypeSourceInfo()->getType()->castAs<FunctionType>() : NewType)->getReturnType(); - QualType ResQT; if (!Context.hasSameType(OldDeclaredReturnType, NewDeclaredReturnType) && !((NewQType->isDependentType() || OldQType->isDependentType()) && New->isLocalExternDecl())) { + QualType ResQT; if (NewDeclaredReturnType->isObjCObjectPointerType() && OldDeclaredReturnType->isObjCObjectPointerType()) ResQT = Context.mergeObjCGCQualifiers(NewQType, OldQType); @@ -3074,7 +3106,7 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, // noreturn should now match unless the old type info didn't have it. QualType OldQTypeForComparison = OldQType; if (!OldTypeInfo.getNoReturn() && NewTypeInfo.getNoReturn()) { - assert(OldQType == QualType(OldType, 0)); + auto *OldType = OldQType->castAs<FunctionProtoType>(); const FunctionType *OldTypeForComparison = Context.adjustFunctionType(OldType, OldTypeInfo.withNoReturn(true)); OldQTypeForComparison = QualType(OldTypeForComparison, 0); @@ -3367,11 +3399,11 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, // We are merging a variable declaration New into Old. If it has an array // bound, and that bound differs from Old's bound, we should diagnose the // mismatch. - if (!NewArray->isIncompleteArrayType()) { + if (!NewArray->isIncompleteArrayType() && !NewArray->isDependentType()) { for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD; PrevVD = PrevVD->getPreviousDecl()) { const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType()); - if (PrevVDTy->isIncompleteArrayType()) + if (PrevVDTy->isIncompleteArrayType() || PrevVDTy->isDependentType()) continue; if (!Context.hasSameType(NewArray, PrevVDTy)) @@ -3657,29 +3689,16 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { } // C++ doesn't have tentative definitions, so go right ahead and check here. - VarDecl *Def; if (getLangOpts().CPlusPlus && - New->isThisDeclarationADefinition() == VarDecl::Definition && - (Def = Old->getDefinition())) { - NamedDecl *Hidden = nullptr; - if (!hasVisibleDefinition(Def, &Hidden) && - (New->getFormalLinkage() == InternalLinkage || - New->getDescribedVarTemplate() || - New->getNumTemplateParameterLists() || - New->getDeclContext()->isDependentContext())) { - // The previous definition is hidden, and multiple definitions are - // permitted (in separate TUs). Form another definition of it. - } else if (Old->isStaticDataMember() && - Old->getCanonicalDecl()->isInline() && - Old->getCanonicalDecl()->isConstexpr()) { + New->isThisDeclarationADefinition() == VarDecl::Definition) { + if (Old->isStaticDataMember() && Old->getCanonicalDecl()->isInline() && + Old->getCanonicalDecl()->isConstexpr()) { // This definition won't be a definition any more once it's been merged. Diag(New->getLocation(), diag::warn_deprecated_redundant_constexpr_static_def); - } else { - Diag(New->getLocation(), diag::err_redefinition) << New; - Diag(Def->getLocation(), diag::note_previous_definition); - New->setInvalidDecl(); - return; + } else if (VarDecl *Def = Old->getDefinition()) { + if (checkVarDeclRedefinition(Def, New)) + return; } } @@ -3708,6 +3727,32 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setImplicitlyInline(); } +/// We've just determined that \p Old and \p New both appear to be definitions +/// of the same variable. Either diagnose or fix the problem. +bool Sema::checkVarDeclRedefinition(VarDecl *Old, VarDecl *New) { + if (!hasVisibleDefinition(Old) && + (New->getFormalLinkage() == InternalLinkage || + New->isInline() || + New->getDescribedVarTemplate() || + New->getNumTemplateParameterLists() || + New->getDeclContext()->isDependentContext())) { + // The previous definition is hidden, and multiple definitions are + // permitted (in separate TUs). Demote this to a declaration. + New->demoteThisDefinitionToDeclaration(); + + // Make the canonical definition visible. + if (auto *OldTD = Old->getDescribedVarTemplate()) + makeMergedDefinitionVisible(OldTD, New->getLocation()); + makeMergedDefinitionVisible(Old, New->getLocation()); + return false; + } else { + Diag(New->getLocation(), diag::err_redefinition) << New; + Diag(Old->getLocation(), diag::note_previous_definition); + New->setInvalidDecl(); + return true; + } +} + /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. Decl * @@ -4793,6 +4838,9 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { Dcl && Dcl->getDeclContext()->isFileContext()) Dcl->setTopLevelDeclInObjCContainer(); + if (getLangOpts().OpenCL) + setCurrentOpenCLExtensionForDecl(Dcl); + return Dcl; } @@ -4921,7 +4969,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // All of these full declarators require an identifier. If it doesn't have // one, the ParsedFreeStandingDeclSpec action should be used. - if (!Name) { + if (D.isDecompositionDeclarator()) { + return ActOnDecompositionDeclarator(S, D, TemplateParamLists); + } else if (!Name) { if (!D.isInvalidType()) // Reject this if we think it is valid. Diag(D.getDeclSpec().getLocStart(), diag::err_declarator_need_ident) @@ -5595,6 +5645,9 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, bool IsSpecialization, bool IsDefinition) { + if (OldDecl->isInvalidDecl()) + return; + if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); if (!IsSpecialization) @@ -5715,23 +5768,7 @@ static bool isFunctionDefinitionDiscarded(Sema &S, FunctionDecl *FD) { return false; // Okay, go ahead and call the relatively-more-expensive function. - -#ifndef NDEBUG - // AST quite reasonably asserts that it's working on a function - // definition. We don't really have a way to tell it that we're - // currently defining the function, so just lie to it in +Asserts - // builds. This is an awful hack. - FD->setLazyBody(1); -#endif - - bool isC99Inline = - S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; - -#ifndef NDEBUG - FD->setLazyBody(0); -#endif - - return isC99Inline; + return S.Context.GetGVALinkageForFunction(FD) == GVA_AvailableExternally; } /// Determine whether a variable is extern "C" prior to attaching @@ -5845,40 +5882,55 @@ static bool isDeclExternC(const Decl *D) { llvm_unreachable("Unknown type of decl!"); } -NamedDecl * -Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, - TypeSourceInfo *TInfo, LookupResult &Previous, - MultiTemplateParamsArg TemplateParamLists, - bool &AddToScope) { +NamedDecl *Sema::ActOnVariableDeclarator( + Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, + LookupResult &Previous, MultiTemplateParamsArg TemplateParamLists, + bool &AddToScope, ArrayRef<BindingDecl *> Bindings) { QualType R = TInfo->getType(); DeclarationName Name = GetNameForDeclarator(D).getName(); - // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument. - // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function - // argument. - if (getLangOpts().OpenCL && (R->isImageType() || R->isPipeType())) { - Diag(D.getIdentifierLoc(), - diag::err_opencl_type_can_only_be_used_as_function_parameter) - << R; - D.setInvalidType(); + IdentifierInfo *II = Name.getAsIdentifierInfo(); + + if (D.isDecompositionDeclarator()) { + AddToScope = false; + // Take the name of the first declarator as our name for diagnostic + // purposes. + auto &Decomp = D.getDecompositionDeclarator(); + if (!Decomp.bindings().empty()) { + II = Decomp.bindings()[0].Name; + Name = II; + } + } else if (!II) { + Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) + << Name; return nullptr; } - DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); - StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); - - // dllimport globals without explicit storage class are treated as extern. We - // have to change the storage class this early to get the right DeclContext. - if (SC == SC_None && !DC->isRecord() && - hasParsedAttr(S, D, AttributeList::AT_DLLImport) && - !hasParsedAttr(S, D, AttributeList::AT_DLLExport)) - SC = SC_Extern; + if (getLangOpts().OpenCL) { + // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument. + // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function + // argument. + if (R->isImageType() || R->isPipeType()) { + Diag(D.getIdentifierLoc(), + diag::err_opencl_type_can_only_be_used_as_function_parameter) + << R; + D.setInvalidType(); + return nullptr; + } - DeclContext *OriginalDC = DC; - bool IsLocalExternDecl = SC == SC_Extern && - adjustContextForLocalExternDecl(DC); + // OpenCL v1.2 s6.9.r: + // The event type cannot be used to declare a program scope variable. + // OpenCL v2.0 s6.9.q: + // The clk_event_t and reserve_id_t types cannot be declared in program scope. + if (NULL == S->getParent()) { + if (R->isReserveIDT() || R->isClkEventT() || R->isEventT()) { + Diag(D.getIdentifierLoc(), + diag::err_invalid_type_for_program_scope_var) << R; + D.setInvalidType(); + return nullptr; + } + } - if (getLangOpts().OpenCL) { // OpenCL v1.0 s6.8.a.3: Pointers to functions are not allowed. QualType NR = R; while (NR->isPointerType()) { @@ -5890,7 +5942,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NR = NR->getPointeeType(); } - if (!getOpenCLOptions().cl_khr_fp16) { + if (!getOpenCLOptions().isEnabled("cl_khr_fp16")) { // OpenCL v1.2 s6.1.1.1: reject declaring variables of the half and // half array type (unless the cl_khr_fp16 extension is enabled). if (Context.getBaseElementType(R)->isHalfType()) { @@ -5898,8 +5950,40 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, D.setInvalidType(); } } + + // OpenCL v1.2 s6.9.b p4: + // The sampler type cannot be used with the __local and __global address + // space qualifiers. + if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local || + R.getAddressSpace() == LangAS::opencl_global)) { + Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); + } + + // OpenCL v1.2 s6.9.r: + // The event type cannot be used with the __local, __constant and __global + // address space qualifiers. + if (R->isEventT()) { + if (R.getAddressSpace()) { + Diag(D.getLocStart(), diag::err_event_t_addr_space_qual); + D.setInvalidType(); + } + } } + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); + StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); + + // dllimport globals without explicit storage class are treated as extern. We + // have to change the storage class this early to get the right DeclContext. + if (SC == SC_None && !DC->isRecord() && + hasParsedAttr(S, D, AttributeList::AT_DLLImport) && + !hasParsedAttr(S, D, AttributeList::AT_DLLExport)) + SC = SC_Extern; + + DeclContext *OriginalDC = DC; + bool IsLocalExternDecl = SC == SC_Extern && + adjustContextForLocalExternDecl(DC); + if (SCSpec == DeclSpec::SCS_mutable) { // mutable can only appear on non-static class members, so it's always // an error here @@ -5920,13 +6004,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); } - IdentifierInfo *II = Name.getAsIdentifierInfo(); - if (!II) { - Diag(D.getIdentifierLoc(), diag::err_bad_variable_name) - << Name; - return nullptr; - } - DiagnoseFunctionSpecifiers(D.getDeclSpec()); if (!DC->isRecord() && S->getFnParent() == nullptr) { @@ -5939,32 +6016,6 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } } - if (getLangOpts().OpenCL) { - // OpenCL v1.2 s6.9.b p4: - // The sampler type cannot be used with the __local and __global address - // space qualifiers. - if (R->isSamplerT() && (R.getAddressSpace() == LangAS::opencl_local || - R.getAddressSpace() == LangAS::opencl_global)) { - Diag(D.getIdentifierLoc(), diag::err_wrong_sampler_addressspace); - } - - // OpenCL 1.2 spec, p6.9 r: - // The event type cannot be used to declare a program scope variable. - // The event type cannot be used with the __local, __constant and __global - // address space qualifiers. - if (R->isEventT()) { - if (S->getParent() == nullptr) { - Diag(D.getLocStart(), diag::err_event_t_global_var); - D.setInvalidType(); - } - - if (R.getAddressSpace()) { - Diag(D.getLocStart(), diag::err_event_t_addr_space_qual); - D.setInvalidType(); - } - } - } - bool IsExplicitSpecialization = false; bool IsVariableTemplateSpecialization = false; bool IsPartialSpecialization = false; @@ -6095,6 +6146,10 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, return nullptr; NewVD = cast<VarDecl>(Res.get()); AddToScope = false; + } else if (D.isDecompositionDeclarator()) { + NewVD = DecompositionDecl::Create(Context, DC, D.getLocStart(), + D.getIdentifierLoc(), R, TInfo, SC, + Bindings); } else NewVD = VarDecl::Create(Context, DC, D.getLocStart(), D.getIdentifierLoc(), II, R, TInfo, SC); @@ -6200,8 +6255,13 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (NewTemplate) NewTemplate->setLexicalDeclContext(CurContext); - if (IsLocalExternDecl) - NewVD->setLocalExternDecl(); + if (IsLocalExternDecl) { + if (D.isDecompositionDeclarator()) + for (auto *B : Bindings) + B->setLocalExternDecl(); + else + NewVD->setLocalExternDecl(); + } bool EmitTLSUnsupportedError = false; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) { @@ -6273,6 +6333,8 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setModulePrivate(); if (NewTemplate) NewTemplate->setModulePrivate(); + for (auto *B : Bindings) + B->setModulePrivate(); } } @@ -6480,7 +6542,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // Special handling of variable named 'main'. - if (Name.isIdentifier() && Name.getAsIdentifierInfo()->isStr("main") && + if (Name.getAsIdentifierInfo() && Name.getAsIdentifierInfo()->isStr("main") && NewVD->getDeclContext()->getRedeclContext()->isTranslationUnit() && !getLangOpts().Freestanding && !NewVD->getDescribedVarTemplate()) { @@ -6522,6 +6584,17 @@ static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl, return OldDC->isFileContext() ? SDK_Global : SDK_Local; } +/// Return the location of the capture if the given lambda captures the given +/// variable \p VD, or an invalid source location otherwise. +static SourceLocation getCaptureLocation(const LambdaScopeInfo *LSI, + const VarDecl *VD) { + for (const LambdaScopeInfo::Capture &Capture : LSI->Captures) { + if (Capture.isVariableCapture() && Capture.getVariable() == VD) + return Capture.getLocation(); + } + return SourceLocation(); +} + /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// @@ -6580,6 +6653,29 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { DeclContext *OldDC = ShadowedDecl->getDeclContext(); + unsigned WarningDiag = diag::warn_decl_shadow; + SourceLocation CaptureLoc; + if (isa<VarDecl>(ShadowedDecl) && NewDC && isa<CXXMethodDecl>(NewDC)) { + if (const auto *RD = dyn_cast<CXXRecordDecl>(NewDC->getParent())) { + if (RD->isLambda() && OldDC->Encloses(NewDC->getLexicalParent())) { + if (RD->getLambdaCaptureDefault() == LCD_None) { + // Try to avoid warnings for lambdas with an explicit capture list. + const auto *LSI = cast<LambdaScopeInfo>(getCurFunction()); + // Warn only when the lambda captures the shadowed decl explicitly. + CaptureLoc = getCaptureLocation(LSI, cast<VarDecl>(ShadowedDecl)); + if (CaptureLoc.isInvalid()) + WarningDiag = diag::warn_decl_shadow_uncaptured_local; + } else { + // Remember that this was shadowed so we can avoid the warning if the + // shadowed decl isn't captured and the warning settings allow it. + cast<LambdaScopeInfo>(getCurFunction()) + ->ShadowingDecls.push_back({D, cast<VarDecl>(ShadowedDecl)}); + return; + } + } + } + } + // Only warn about certain kinds of shadowing for class members. if (NewDC && NewDC->isRecord()) { // In particular, don't warn about shadowing non-class members. @@ -6601,10 +6697,33 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); - Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; + Diag(R.getNameLoc(), WarningDiag) << Name << Kind << OldDC; + if (!CaptureLoc.isInvalid()) + Diag(CaptureLoc, diag::note_var_explicitly_captured_here) + << Name << /*explicitly*/ 1; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } +/// Diagnose shadowing for variables shadowed in the lambda record \p LambdaRD +/// when these variables are captured by the lambda. +void Sema::DiagnoseShadowingLambdaDecls(const LambdaScopeInfo *LSI) { + for (const auto &Shadow : LSI->ShadowingDecls) { + const VarDecl *ShadowedDecl = Shadow.ShadowedDecl; + // Try to avoid the warning when the shadowed decl isn't captured. + SourceLocation CaptureLoc = getCaptureLocation(LSI, ShadowedDecl); + const DeclContext *OldDC = ShadowedDecl->getDeclContext(); + Diag(Shadow.VD->getLocation(), CaptureLoc.isInvalid() + ? diag::warn_decl_shadow_uncaptured_local + : diag::warn_decl_shadow) + << Shadow.VD->getDeclName() + << computeShadowedDeclKind(ShadowedDecl, OldDC) << OldDC; + if (!CaptureLoc.isInvalid()) + Diag(CaptureLoc, diag::note_var_explicitly_captured_here) + << Shadow.VD->getDeclName() << /*explicitly*/ 0; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); + } +} + /// \brief Check -Wshadow without the advantage of a previous lookup. void Sema::CheckShadow(Scope *S, VarDecl *D) { if (Diags.isIgnored(diag::warn_decl_shadow, D->getLocation())) @@ -6793,7 +6912,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { // OpenCL v1.2 s6.8 - The static qualifier is valid only in program // scope. if (getLangOpts().OpenCLVersion == 120 && - !getOpenCLOptions().cl_clang_storage_class_specifiers && + !getOpenCLOptions().isEnabled("cl_clang_storage_class_specifiers") && NewVD->isStaticLocal()) { Diag(NewVD->getLocation(), diag::err_static_function_scope); NewVD->setInvalidDecl(); @@ -6821,17 +6940,6 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { NewVD->setInvalidDecl(); return; } - // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported. - // TODO: this check is not enough as it doesn't diagnose the typedef - const BlockPointerType *BlkTy = T->getAs<BlockPointerType>(); - const FunctionProtoType *FTy = - BlkTy->getPointeeType()->getAs<FunctionProtoType>(); - if (FTy && FTy->isVariadic()) { - Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic) - << T << NewVD->getSourceRange(); - NewVD->setInvalidDecl(); - return; - } } // OpenCL v1.2 s6.5 - All program scope variables must be declared in the // __constant address space. @@ -7481,18 +7589,20 @@ enum OpenCLParamType { ValidKernelParam, PtrPtrKernelParam, PtrKernelParam, - PrivatePtrKernelParam, + InvalidAddrSpacePtrKernelParam, InvalidKernelParam, RecordKernelParam }; -static OpenCLParamType getOpenCLKernelParameterType(QualType PT) { +static OpenCLParamType getOpenCLKernelParameterType(Sema &S, QualType PT) { if (PT->isPointerType()) { QualType PointeeType = PT->getPointeeType(); if (PointeeType->isPointerType()) return PtrPtrKernelParam; - return PointeeType.getAddressSpace() == 0 ? PrivatePtrKernelParam - : PtrKernelParam; + if (PointeeType.getAddressSpace() == LangAS::opencl_generic || + PointeeType.getAddressSpace() == 0) + return InvalidAddrSpacePtrKernelParam; + return PtrKernelParam; } // TODO: Forbid the other integer types (size_t, ptrdiff_t...) when they can @@ -7507,7 +7617,10 @@ static OpenCLParamType getOpenCLKernelParameterType(QualType PT) { if (PT->isEventT()) return InvalidKernelParam; - if (PT->isHalfType()) + // OpenCL extension spec v1.2 s9.5: + // This extension adds support for half scalar and vector types as built-in + // types that can be used for arithmetic operations, conversions etc. + if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16") && PT->isHalfType()) return InvalidKernelParam; if (PT->isRecordType()) @@ -7528,7 +7641,7 @@ static void checkIsValidOpenCLKernelParameter( if (ValidTypes.count(PT.getTypePtr())) return; - switch (getOpenCLKernelParameterType(PT)) { + switch (getOpenCLKernelParameterType(S, PT)) { case PtrPtrKernelParam: // OpenCL v1.2 s6.9.a: // A kernel function argument cannot be declared as a @@ -7537,11 +7650,12 @@ static void checkIsValidOpenCLKernelParameter( D.setInvalidType(); return; - case PrivatePtrKernelParam: - // OpenCL v1.2 s6.9.a: - // A kernel function argument cannot be declared as a - // pointer to the private address space. - S.Diag(Param->getLocation(), diag::err_opencl_private_ptr_kernel_param); + case InvalidAddrSpacePtrKernelParam: + // OpenCL v1.0 s6.5: + // __kernel function arguments declared to be a pointer of a type can point + // to one of the following address spaces only : __global, __local or + // __constant. + S.Diag(Param->getLocation(), diag::err_kernel_arg_address_space); D.setInvalidType(); return; @@ -7555,7 +7669,10 @@ static void checkIsValidOpenCLKernelParameter( // OpenCL v1.2 s6.8 n: // A kernel function argument cannot be declared // of event_t type. - S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; + // Do not diagnose half type since it is diagnosed as invalid argument + // type for any function elsewhere. + if (!PT->isHalfType()) + S.Diag(Param->getLocation(), diag::err_bad_kernel_param_type) << PT; D.setInvalidType(); return; @@ -7611,7 +7728,7 @@ static void checkIsValidOpenCLKernelParameter( if (ValidTypes.count(QT.getTypePtr())) continue; - OpenCLParamType ParamType = getOpenCLKernelParameterType(QT); + OpenCLParamType ParamType = getOpenCLKernelParameterType(S, QT); if (ParamType == ValidKernelParam) continue; @@ -7625,7 +7742,7 @@ static void checkIsValidOpenCLKernelParameter( // do not allow OpenCL objects to be passed as elements of the struct or // union. if (ParamType == PtrKernelParam || ParamType == PtrPtrKernelParam || - ParamType == PrivatePtrKernelParam) { + ParamType == InvalidAddrSpacePtrKernelParam) { S.Diag(Param->getLocation(), diag::err_record_with_pointers_kernel_param) << PT->isUnionType() @@ -7657,6 +7774,28 @@ static void checkIsValidOpenCLKernelParameter( } while (!VisitStack.empty()); } +/// Find the DeclContext in which a tag is implicitly declared if we see an +/// elaborated type specifier in the specified context, and lookup finds +/// nothing. +static DeclContext *getTagInjectionContext(DeclContext *DC) { + while (!DC->isFileContext() && !DC->isFunctionOrMethod()) + DC = DC->getParent(); + return DC; +} + +/// Find the Scope in which a tag is implicitly declared if we see an +/// elaborated type specifier in the specified context, and lookup finds +/// nothing. +static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { + while (S->isClassScope() || + (LangOpts.CPlusPlus && + S->isFunctionPrototypeScope()) || + ((S->getFlags() & Scope::DeclScope) == 0) || + (S->getEntity() && S->getEntity()->isTransparentContext())) + S = S->getParent(); + return S; +} + NamedDecl* Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TypeSourceInfo *TInfo, LookupResult &Previous, @@ -8111,8 +8250,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Copy the parameter declarations from the declarator D to the function // declaration NewFD, if they are available. First scavenge them into Params. SmallVector<ParmVarDecl*, 16> Params; - if (D.isFunctionDeclarator()) { - DeclaratorChunk::FunctionTypeInfo &FTI = D.getFunctionTypeInfo(); + unsigned FTIIdx; + if (D.isFunctionDeclarator(FTIIdx)) { + DeclaratorChunk::FunctionTypeInfo &FTI = D.getTypeObject(FTIIdx).Fun; // Check for C99 6.7.5.3p10 - foo(void) is a non-varargs // function that takes no arguments, not a function that takes a @@ -8130,6 +8270,41 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } } + + if (!getLangOpts().CPlusPlus) { + // In C, find all the tag declarations from the prototype and move them + // into the function DeclContext. Remove them from the surrounding tag + // injection context of the function, which is typically but not always + // the TU. + DeclContext *PrototypeTagContext = + getTagInjectionContext(NewFD->getLexicalDeclContext()); + for (NamedDecl *NonParmDecl : FTI.getDeclsInPrototype()) { + auto *TD = dyn_cast<TagDecl>(NonParmDecl); + + // We don't want to reparent enumerators. Look at their parent enum + // instead. + if (!TD) { + if (auto *ECD = dyn_cast<EnumConstantDecl>(NonParmDecl)) + TD = cast<EnumDecl>(ECD->getDeclContext()); + } + if (!TD) + continue; + DeclContext *TagDC = TD->getLexicalDeclContext(); + if (!TagDC->containsDecl(TD)) + continue; + TagDC->removeDecl(TD); + TD->setDeclContext(NewFD); + NewFD->addDecl(TD); + + // Preserve the lexical DeclContext if it is not the surrounding tag + // injection context of the FD. In this example, the semantic context of + // E will be f and the lexical context will be S, while both the + // semantic and lexical contexts of S will be f: + // void f(struct S { enum E { a } f; } s); + if (TagDC != PrototypeTagContext) + TD->setLexicalDeclContext(TagDC); + } + } } else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) { // When we're declaring a function with a typedef, typeof, etc as in the // following example, we'll need to synthesize (unnamed) @@ -8155,15 +8330,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Finally, we know we have the right number of parameters, install them. NewFD->setParams(Params); - // Find all anonymous symbols defined during the declaration of this function - // and add to NewFD. This lets us track decls such 'enum Y' in: - // - // void f(enum Y {AA} x) {} - // - // which would otherwise incorrectly end up in the translation unit scope. - NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope); - DeclsInPrototypeScope.clear(); - if (D.getDeclSpec().isNoreturnSpecified()) NewFD->addAttr( ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), @@ -8194,9 +8360,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // Handle attributes. ProcessDeclAttributes(S, NewFD, D); - if (getLangOpts().CUDA) - maybeAddCUDAHostDeviceAttrs(S, NewFD, Previous); - if (getLangOpts().OpenCL) { // OpenCL v1.1 s6.5: Using an address space qualifier in a function return // type declaration will generate a compilation error. @@ -8299,6 +8462,15 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateArgs.setRAngleLoc(D.getIdentifierLoc()); } + // We do not add HD attributes to specializations here because + // they may have different constexpr-ness compared to their + // templates and, after maybeAddCUDAHostDeviceAttrs() is applied, + // may end up with different effective targets. Instead, a + // specialization inherits its target attributes from its template + // in the CheckFunctionTemplateSpecialization() call below. + if (getLangOpts().CUDA & !isFunctionTemplateSpecialization) + maybeAddCUDAHostDeviceAttrs(NewFD, Previous); + // If it's a friend (and only if it's a friend), it's possible // that either the specialized function type or the specialized // template is dependent, and therefore matching will fail. In @@ -8376,7 +8548,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, ? cast<NamedDecl>(FunctionTemplate) : NewFD); - if (isFriend && D.isRedeclaration()) { + if (isFriend && NewFD->getPreviousDecl()) { AccessSpecifier Access = AS_public; if (!NewFD->isInvalidDecl()) Access = NewFD->getPreviousDecl()->getAccess(); @@ -8618,6 +8790,32 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, return NewFD; } +/// \brief Checks if the new declaration declared in dependent context must be +/// put in the same redeclaration chain as the specified declaration. +/// +/// \param D Declaration that is checked. +/// \param PrevDecl Previous declaration found with proper lookup method for the +/// same declaration name. +/// \returns True if D must be added to the redeclaration chain which PrevDecl +/// belongs to. +/// +bool Sema::shouldLinkDependentDeclWithPrevious(Decl *D, Decl *PrevDecl) { + // Any declarations should be put into redeclaration chains except for + // friend declaration in a dependent context that names a function in + // namespace scope. + // + // This allows to compile code like: + // + // void func(); + // template<typename T> class C1 { friend void func() { } }; + // template<typename T> class C2 { friend void func() { } }; + // + // This code snippet is a valid code unless both templates are instantiated. + return !(D->getLexicalDeclContext()->isDependentContext() && + D->getDeclContext()->isFileContext() && + D->getFriendObjectKind() != Decl::FOK_None); +} + /// \brief Perform semantic checking of a new function declaration. /// /// Performs semantic analysis of the new function declaration @@ -8801,11 +8999,12 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } else { - // This needs to happen first so that 'inline' propagates. - NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); - - if (isa<CXXMethodDecl>(NewFD)) - NewFD->setAccess(OldDecl->getAccess()); + if (shouldLinkDependentDeclWithPrevious(NewFD, OldDecl)) { + // This needs to happen first so that 'inline' propagates. + NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); + if (isa<CXXMethodDecl>(NewFD)) + NewFD->setAccess(OldDecl->getAccess()); + } } } @@ -8880,11 +9079,16 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, ASTContext::GetBuiltinTypeError Error; LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier()); QualType T = Context.GetBuiltinType(BuiltinID, Error); - if (!T.isNull() && !Context.hasSameType(T, NewFD->getType())) { + // If the type of the builtin differs only in its exception + // specification, that's OK. + // FIXME: If the types do differ in this way, it would be better to + // retain the 'noexcept' form of the type. + if (!T.isNull() && + !Context.hasSameFunctionTypeIgnoringExceptionSpec(T, + NewFD->getType())) // The type of this function differs from the type of the builtin, // so forget about the builtin entirely. Context.BuiltinInfo.forgetBuiltin(BuiltinID, Context.Idents); - } } // If this function is declared as being extern "C", then check to see if @@ -8900,6 +9104,45 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, !R->isObjCObjectPointerType()) Diag(NewFD->getLocation(), diag::warn_return_value_udt) << NewFD << R; } + + // C++1z [dcl.fct]p6: + // [...] whether the function has a non-throwing exception-specification + // [is] part of the function type + // + // This results in an ABI break between C++14 and C++17 for functions whose + // declared type includes an exception-specification in a parameter or + // return type. (Exception specifications on the function itself are OK in + // most cases, and exception specifications are not permitted in most other + // contexts where they could make it into a mangling.) + if (!getLangOpts().CPlusPlus1z && !NewFD->getPrimaryTemplate()) { + auto HasNoexcept = [&](QualType T) -> bool { + // Strip off declarator chunks that could be between us and a function + // type. We don't need to look far, exception specifications are very + // restricted prior to C++17. + if (auto *RT = T->getAs<ReferenceType>()) + T = RT->getPointeeType(); + else if (T->isAnyPointerType()) + T = T->getPointeeType(); + else if (auto *MPT = T->getAs<MemberPointerType>()) + T = MPT->getPointeeType(); + if (auto *FPT = T->getAs<FunctionProtoType>()) + if (FPT->isNothrow(Context)) + return true; + return false; + }; + + auto *FPT = NewFD->getType()->castAs<FunctionProtoType>(); + bool AnyNoexcept = HasNoexcept(FPT->getReturnType()); + for (QualType T : FPT->param_types()) + AnyNoexcept |= HasNoexcept(T); + if (AnyNoexcept) + Diag(NewFD->getLocation(), + diag::warn_cxx1z_compat_exception_spec_in_signature) + << NewFD; + } + + if (!Redeclaration && LangOpts.CUDA) + checkCUDATargetOverload(NewFD, Previous); } return Redeclaration; } @@ -9421,6 +9664,20 @@ namespace { } } // end anonymous namespace +namespace { + // Simple wrapper to add the name of a variable or (if no variable is + // available) a DeclarationName into a diagnostic. + struct VarDeclOrName { + VarDecl *VDecl; + DeclarationName Name; + + friend const Sema::SemaDiagnosticBuilder & + operator<<(const Sema::SemaDiagnosticBuilder &Diag, VarDeclOrName VN) { + return VN.VDecl ? Diag << VN.VDecl : Diag << VN.Name; + } + }; +} // end anonymous namespace + QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, TypeSourceInfo *TSI, @@ -9430,6 +9687,8 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, assert((!VDecl || !VDecl->isInitCapture()) && "init captures are expected to be deduced prior to initialization"); + VarDeclOrName VN{VDecl, Name}; + ArrayRef<Expr *> DeduceInits = Init; if (DirectInit) { if (auto *PL = dyn_cast<ParenListExpr>(Init)) @@ -9445,7 +9704,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, Diag(Init->getLocStart(), IsInitCapture ? diag::err_init_capture_no_expression : diag::err_auto_var_init_no_expression) - << Name << Type << Range; + << VN << Type << Range; return QualType(); } @@ -9453,7 +9712,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, Diag(DeduceInits[1]->getLocStart(), IsInitCapture ? diag::err_init_capture_multiple_expressions : diag::err_auto_var_init_multiple_expressions) - << Name << Type << Range; + << VN << Type << Range; return QualType(); } @@ -9462,7 +9721,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, Diag(Init->getLocStart(), IsInitCapture ? diag::err_init_capture_paren_braces : diag::err_auto_var_init_paren_braces) - << isa<InitListExpr>(Init) << Name << Type << Range; + << isa<InitListExpr>(Init) << VN << Type << Range; return QualType(); } @@ -9478,6 +9737,15 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DefaultedAnyToId = true; } + // C++ [dcl.decomp]p1: + // If the assignment-expression [...] has array type A and no ref-qualifier + // is present, e has type cv A + if (VDecl && isa<DecompositionDecl>(VDecl) && + Context.hasSameUnqualifiedType(Type, Context.getAutoDeductType()) && + DeduceInit->getType()->isConstantArrayType()) + return Context.getQualifiedType(DeduceInit->getType(), + Type.getQualifiers()); + QualType DeducedType; if (DeduceAutoType(TSI, DeduceInit, DeducedType) == DAR_Failed) { if (!IsInitCapture) @@ -9485,13 +9753,13 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, else if (isa<InitListExpr>(Init)) Diag(Range.getBegin(), diag::err_init_capture_deduction_failure_from_init_list) - << Name + << VN << (DeduceInit->getType().isNull() ? TSI->getType() : DeduceInit->getType()) << DeduceInit->getSourceRange(); else Diag(Range.getBegin(), diag::err_init_capture_deduction_failure) - << Name << TSI->getType() + << VN << TSI->getType() << (DeduceInit->getType().isNull() ? TSI->getType() : DeduceInit->getType()) << DeduceInit->getSourceRange(); @@ -9505,7 +9773,7 @@ QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, if (ActiveTemplateInstantiations.empty() && !DefaultedAnyToId && !IsInitCapture && !DeducedType.isNull() && DeducedType->isObjCIdType()) { SourceLocation Loc = TSI->getTypeLoc().getBeginLoc(); - Diag(Loc, diag::warn_auto_var_is_id) << Name << Range; + Diag(Loc, diag::warn_auto_var_is_id) << VN << Range; } return DeducedType; @@ -9614,25 +9882,15 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); } + // If adding the initializer will turn this declaration into a definition, + // and we already have a definition for this variable, diagnose or otherwise + // handle the situation. VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl && - (!VDecl->isStaticDataMember() || VDecl->isOutOfLine())) { - NamedDecl *Hidden = nullptr; - if (!hasVisibleDefinition(Def, &Hidden) && - (VDecl->getFormalLinkage() == InternalLinkage || - VDecl->getDescribedVarTemplate() || - VDecl->getNumTemplateParameterLists() || - VDecl->getDeclContext()->isDependentContext())) { - // The previous definition is hidden, and multiple definitions are - // permitted (in separate TUs). Form another definition of it. - } else { - Diag(VDecl->getLocation(), diag::err_redefinition) - << VDecl->getDeclName(); - Diag(Def->getLocation(), diag::note_previous_definition); - VDecl->setInvalidDecl(); - return; - } - } + (!VDecl->isStaticDataMember() || VDecl->isOutOfLine()) && + !VDecl->isThisDeclarationADemotedDefinition() && + checkVarDeclRedefinition(Def, VDecl)) + return; if (getLangOpts().CPlusPlus) { // C++ [class.static.data]p4 @@ -9692,6 +9950,18 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Perform the initialization. ParenListExpr *CXXDirectInit = dyn_cast<ParenListExpr>(Init); if (!VDecl->isInvalidDecl()) { + // Handle errors like: int a({0}) + if (CXXDirectInit && CXXDirectInit->getNumExprs() == 1 && + !canInitializeWithParenthesizedList(VDecl->getType())) + if (auto IList = dyn_cast<InitListExpr>(CXXDirectInit->getExpr(0))) { + Diag(VDecl->getLocation(), diag::err_list_init_in_parens) + << VDecl->getType() << CXXDirectInit->getSourceRange() + << FixItHint::CreateRemoval(CXXDirectInit->getLocStart()) + << FixItHint::CreateRemoval(CXXDirectInit->getLocEnd()); + Init = IList; + CXXDirectInit = nullptr; + } + InitializedEntity Entity = InitializedEntity::InitializeVariable(VDecl); InitializationKind Kind = DirectInit @@ -9909,10 +10179,17 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VDecl->setInvalidDecl(); } } else if (VDecl->isFileVarDecl()) { + // In C, extern is typically used to avoid tentative definitions when + // declaring variables in headers, but adding an intializer makes it a + // defintion. This is somewhat confusing, so GCC and Clang both warn on it. + // In C++, extern is often used to give implictly static const variables + // external linkage, so don't warn in that case. If selectany is present, + // this might be header code intended for C and C++ inclusion, so apply the + // C++ rules. if (VDecl->getStorageClass() == SC_Extern && - (!getLangOpts().CPlusPlus || - !(Context.getBaseElementType(VDecl->getType()).isConstQualified() || - VDecl->isExternC())) && + ((!getLangOpts().CPlusPlus && !VDecl->hasAttr<SelectAnyAttr>()) || + !Context.getBaseElementType(VDecl->getType()).isConstQualified()) && + !(getLangOpts().CPlusPlus && VDecl->isExternC()) && !isTemplateInstantiation(VDecl->getTemplateSpecializationKind())) Diag(VDecl->getLocation(), diag::warn_extern_init); @@ -9957,6 +10234,11 @@ void Sema::ActOnInitializerError(Decl *D) { VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD) return; + // Bindings are not usable if we can't make sense of the initializer. + if (auto *DD = dyn_cast<DecompositionDecl>(D)) + for (auto *BD : DD->bindings()) + BD->setInvalidDecl(); + // Auto types are meaningless if we can't make sense of the initializer. if (ParsingInitForAutoVars.count(D)) { D->setInvalidDecl(); @@ -9986,6 +10268,18 @@ void Sema::ActOnInitializerError(Decl *D) { // though. } +/// Checks if an object of the given type can be initialized with parenthesized +/// init-list. +/// +/// \param TargetType Type of object being initialized. +/// +/// The function is used to detect wrong initializations, such as 'int({0})'. +/// +bool Sema::canInitializeWithParenthesizedList(QualType TargetType) { + return TargetType->isDependentType() || TargetType->isRecordType() || + TargetType->getContainedAutoType(); +} + void Sema::ActOnUninitializedDecl(Decl *RealDecl, bool TypeMayContainAuto) { // If there is no declaration, there was an error parsing it. Just ignore it. @@ -9995,6 +10289,13 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, if (VarDecl *Var = dyn_cast<VarDecl>(RealDecl)) { QualType Type = Var->getType(); + // C++1z [dcl.dcl]p1 grammar implies that an initializer is mandatory. + if (isa<DecompositionDecl>(RealDecl)) { + Diag(Var->getLocation(), diag::err_decomp_decl_requires_init) << Var; + Var->setInvalidDecl(); + return; + } + // C++11 [dcl.spec.auto]p3 if (TypeMayContainAuto && Type->getContainedAutoType()) { Diag(Var->getLocation(), diag::err_auto_var_requires_init) @@ -10009,7 +10310,8 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // C++11 [dcl.constexpr]p1: The constexpr specifier shall be applied only to // the definition of a variable [...] or the declaration of a static data // member. - if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) { + if (Var->isConstexpr() && !Var->isThisDeclarationADefinition() && + !Var->isThisDeclarationADemotedDefinition()) { if (Var->isStaticDataMember()) { // C++1z removes the relevant rule; the in-class declaration is always // a definition there. @@ -10344,8 +10646,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::warn_missing_variable_declarations) << var; } + // Cache the result of checking for constant initialization. + Optional<bool> CacheHasConstInit; + const Expr *CacheCulprit; + auto checkConstInit = [&]() mutable { + if (!CacheHasConstInit) + CacheHasConstInit = var->getInit()->isConstantInitializer( + Context, var->getType()->isReferenceType(), &CacheCulprit); + return *CacheHasConstInit; + }; + if (var->getTLSKind() == VarDecl::TLS_Static) { - const Expr *Culprit; if (var->getType().isDestructedType()) { // GNU C++98 edits for __thread, [basic.start.term]p3: // The type of an object with thread storage duration shall not @@ -10353,17 +10664,17 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { Diag(var->getLocation(), diag::err_thread_nontrivial_dtor); if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); - } else if (getLangOpts().CPlusPlus && var->hasInit() && - !var->getInit()->isConstantInitializer( - Context, var->getType()->isReferenceType(), &Culprit)) { - // GNU C++98 edits for __thread, [basic.start.init]p4: - // An object of thread storage duration shall not require dynamic - // initialization. - // FIXME: Need strict checking here. - Diag(Culprit->getExprLoc(), diag::err_thread_dynamic_init) - << Culprit->getSourceRange(); - if (getLangOpts().CPlusPlus11) - Diag(var->getLocation(), diag::note_use_thread_local); + } else if (getLangOpts().CPlusPlus && var->hasInit()) { + if (!checkConstInit()) { + // GNU C++98 edits for __thread, [basic.start.init]p4: + // An object of thread storage duration shall not require dynamic + // initialization. + // FIXME: Need strict checking here. + Diag(CacheCulprit->getExprLoc(), diag::err_thread_dynamic_init) + << CacheCulprit->getSourceRange(); + if (getLangOpts().CPlusPlus11) + Diag(var->getLocation(), diag::note_use_thread_local); + } } } @@ -10400,7 +10711,16 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { } // All the following checks are C++ only. - if (!getLangOpts().CPlusPlus) return; + if (!getLangOpts().CPlusPlus) { + // If this variable must be emitted, add it as an initializer for the + // current module. + if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, var); + return; + } + + if (auto *DD = dyn_cast<DecompositionDecl>(var)) + CheckCompleteDecompositionDeclaration(DD); QualType type = var->getType(); if (type->isDependentType()) return; @@ -10434,18 +10754,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (!var->getDeclContext()->isDependentContext() && Init && !Init->isValueDependent()) { - if (IsGlobal && !var->isConstexpr() && - !getDiagnostics().isIgnored(diag::warn_global_constructor, - var->getLocation())) { - // Warn about globals which don't have a constant initializer. Don't - // warn about globals with a non-trivial destructor because we already - // warned about them. - CXXRecordDecl *RD = baseType->getAsCXXRecordDecl(); - if (!(RD && !RD->hasTrivialDestructor()) && - !Init->isConstantInitializer(Context, baseType->isReferenceType())) - Diag(var->getLocation(), diag::warn_global_constructor) - << Init->getSourceRange(); - } if (var->isConstexpr()) { SmallVector<PartialDiagnosticAt, 8> Notes; @@ -10469,11 +10777,45 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { // initialized by a constant expression if we check later. var->checkInitIsICE(); } + + // Don't emit further diagnostics about constexpr globals since they + // were just diagnosed. + if (!var->isConstexpr() && GlobalStorage && + var->hasAttr<RequireConstantInitAttr>()) { + // FIXME: Need strict checking in C++03 here. + bool DiagErr = getLangOpts().CPlusPlus11 + ? !var->checkInitIsICE() : !checkConstInit(); + if (DiagErr) { + auto attr = var->getAttr<RequireConstantInitAttr>(); + Diag(var->getLocation(), diag::err_require_constant_init_failed) + << Init->getSourceRange(); + Diag(attr->getLocation(), diag::note_declared_required_constant_init_here) + << attr->getRange(); + } + } + else if (!var->isConstexpr() && IsGlobal && + !getDiagnostics().isIgnored(diag::warn_global_constructor, + var->getLocation())) { + // Warn about globals which don't have a constant initializer. Don't + // warn about globals with a non-trivial destructor because we already + // warned about them. + CXXRecordDecl *RD = baseType->getAsCXXRecordDecl(); + if (!(RD && !RD->hasTrivialDestructor())) { + if (!checkConstInit()) + Diag(var->getLocation(), diag::warn_global_constructor) + << Init->getSourceRange(); + } + } } // Require the destructor. if (const RecordType *recordType = baseType->getAs<RecordType>()) FinalizeVarWithDestructor(var, recordType); + + // If this variable must be emitted, add it as an initializer for the current + // module. + if (Context.DeclMustBeEmitted(var) && !ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, var); } /// \brief Determines if a variable's alignment is dependent. @@ -10497,6 +10839,12 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { if (!VD) return; + if (auto *DD = dyn_cast<DecompositionDecl>(ThisDecl)) { + for (auto *BD : DD->bindings()) { + FinalizeDeclaration(BD); + } + } + checkAttributesAfterMerging(*this, *VD); // Perform TLS alignment check here after attributes attached to the variable @@ -10527,12 +10875,11 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { // CUDA E.2.9.4: Within the body of a __device__ or __global__ // function, only __shared__ variables may be declared with // static storage class. - if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice && - (FD->hasAttr<CUDADeviceAttr>() || FD->hasAttr<CUDAGlobalAttr>()) && - !VD->hasAttr<CUDASharedAttr>()) { - Diag(VD->getLocation(), diag::err_device_static_local_var); + if (getLangOpts().CUDA && !VD->hasAttr<CUDASharedAttr>() && + CUDADiagIfDeviceCode(VD->getLocation(), + diag::err_device_static_local_var) + << CurrentCUDATarget()) VD->setInvalidDecl(); - } } } @@ -10541,36 +10888,55 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { // 7.5). We must also apply the same checks to all __shared__ // variables whether they are local or not. CUDA also allows // constant initializers for __constant__ and __device__ variables. - if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { + if (getLangOpts().CUDA) { const Expr *Init = VD->getInit(); - if (Init && VD->hasGlobalStorage() && - (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || - VD->hasAttr<CUDASharedAttr>())) { - assert((!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>())); - bool AllowedInit = false; - if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) - AllowedInit = - isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); - // We'll allow constant initializers even if it's a non-empty - // 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()); - - // Also make sure that destructor, if there is one, is empty. - if (AllowedInit) - if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl()) + if (Init && VD->hasGlobalStorage()) { + if (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() || + VD->hasAttr<CUDASharedAttr>()) { + assert(!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()); + bool AllowedInit = false; + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) AllowedInit = - isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); - - if (!AllowedInit) { - Diag(VD->getLocation(), VD->hasAttr<CUDASharedAttr>() - ? diag::err_shared_var_init - : diag::err_dynamic_var_init) - << Init->getSourceRange(); - VD->setInvalidDecl(); + isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor()); + // We'll allow constant initializers even if it's a non-empty + // 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()); + + // Also make sure that destructor, if there is one, is empty. + if (AllowedInit) + if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl()) + AllowedInit = + isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor()); + + if (!AllowedInit) { + Diag(VD->getLocation(), VD->hasAttr<CUDASharedAttr>() + ? diag::err_shared_var_init + : diag::err_dynamic_var_init) + << Init->getSourceRange(); + VD->setInvalidDecl(); + } + } else { + // This is a host-side global variable. Check that the initializer is + // callable from the host side. + const FunctionDecl *InitFn = nullptr; + if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init)) { + InitFn = CE->getConstructor(); + } else if (const CallExpr *CE = dyn_cast<CallExpr>(Init)) { + InitFn = CE->getDirectCallee(); + } + if (InitFn) { + CUDAFunctionTarget InitFnTarget = IdentifyCUDATarget(InitFn); + if (InitFnTarget != CFT_Host && InitFnTarget != CFT_HostDevice) { + Diag(VD->getLocation(), diag::err_ref_bad_target_global_initializer) + << InitFnTarget << InitFn; + Diag(InitFn->getLocation(), diag::note_previous_decl) << InitFn; + VD->setInvalidDecl(); + } + } } } } @@ -10675,13 +11041,36 @@ Sema::DeclGroupPtrTy Sema::FinalizeDeclaratorGroup(Scope *S, const DeclSpec &DS, Decls.push_back(DS.getRepAsDecl()); DeclaratorDecl *FirstDeclaratorInGroup = nullptr; - for (unsigned i = 0, e = Group.size(); i != e; ++i) + DecompositionDecl *FirstDecompDeclaratorInGroup = nullptr; + bool DiagnosedMultipleDecomps = false; + + for (unsigned i = 0, e = Group.size(); i != e; ++i) { if (Decl *D = Group[i]) { - if (DeclaratorDecl *DD = dyn_cast<DeclaratorDecl>(D)) - if (!FirstDeclaratorInGroup) - FirstDeclaratorInGroup = DD; + auto *DD = dyn_cast<DeclaratorDecl>(D); + if (DD && !FirstDeclaratorInGroup) + FirstDeclaratorInGroup = DD; + + auto *Decomp = dyn_cast<DecompositionDecl>(D); + if (Decomp && !FirstDecompDeclaratorInGroup) + FirstDecompDeclaratorInGroup = Decomp; + + // A decomposition declaration cannot be combined with any other + // declaration in the same group. + auto *OtherDD = FirstDeclaratorInGroup; + if (OtherDD == FirstDecompDeclaratorInGroup) + OtherDD = DD; + if (OtherDD && FirstDecompDeclaratorInGroup && + OtherDD != FirstDecompDeclaratorInGroup && + !DiagnosedMultipleDecomps) { + Diag(FirstDecompDeclaratorInGroup->getLocation(), + diag::err_decomp_decl_not_alone) + << OtherDD->getSourceRange(); + DiagnosedMultipleDecomps = true; + } + Decls.push_back(D); } + } if (DeclSpec::isDeclRep(DS.getTypeSpecType())) { if (TagDecl *Tag = dyn_cast_or_null<TagDecl>(DS.getRepAsDecl())) { @@ -11168,9 +11557,8 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, SkipBody->ShouldSkip = true; if (auto *TD = Definition->getDescribedFunctionTemplate()) makeMergedDefinitionVisible(TD, FD->getLocation()); - else - makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition), - FD->getLocation()); + makeMergedDefinitionVisible(const_cast<FunctionDecl*>(Definition), + FD->getLocation()); return; } @@ -11256,6 +11644,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, return D; } + // Mark this function as "will have a body eventually". This lets users to + // call e.g. isInlineDefinitionExternallyVisible while we're still parsing + // this function. + FD->setWillHaveBody(); + // If we are instantiating a generic lambda call operator, push // a LambdaScopeInfo onto the function stack. But use the information // that's already been calculated (ActOnLambdaExpr) to prime the current @@ -11300,6 +11693,29 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, CheckParmsForFunctionDef(FD->parameters(), /*CheckParameterNames=*/true); + // Add non-parameter declarations already in the function to the current + // scope. + if (FnBodyScope) { + for (Decl *NPD : FD->decls()) { + auto *NonParmDecl = dyn_cast<NamedDecl>(NPD); + if (!NonParmDecl) + continue; + assert(!isa<ParmVarDecl>(NonParmDecl) && + "parameters should not be in newly created FD yet"); + + // If the decl has a name, make it accessible in the current scope. + if (NonParmDecl->getDeclName()) + PushOnScopeChains(NonParmDecl, FnBodyScope, /*AddToContext=*/false); + + // Similarly, dive into enums and fish their constants out, making them + // accessible in this scope. + if (auto *ED = dyn_cast<EnumDecl>(NonParmDecl)) { + for (auto *EI : ED->enumerators()) + PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); + } + } + } + // Introduce our parameters into the function scope for (auto Param : FD->parameters()) { Param->setOwningFunction(FD); @@ -11312,39 +11728,6 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, } } - // If we had any tags defined in the function prototype, - // introduce them into the function scope. - if (FnBodyScope) { - for (ArrayRef<NamedDecl *>::iterator - I = FD->getDeclsInPrototypeScope().begin(), - E = FD->getDeclsInPrototypeScope().end(); - I != E; ++I) { - NamedDecl *D = *I; - - // Some of these decls (like enums) may have been pinned to the - // translation unit for lack of a real context earlier. If so, remove - // from the translation unit and reattach to the current context. - if (D->getLexicalDeclContext() == Context.getTranslationUnitDecl()) { - // Is the decl actually in the context? - if (Context.getTranslationUnitDecl()->containsDecl(D)) - Context.getTranslationUnitDecl()->removeDecl(D); - // Either way, reassign the lexical decl context to our FunctionDecl. - D->setLexicalDeclContext(CurContext); - } - - // If the decl has a non-null name, make accessible in the current scope. - if (!D->getName().empty()) - PushOnScopeChains(D, FnBodyScope, /*AddToContext=*/false); - - // Similarly, dive into enums and fish their constants out, making them - // accessible in this scope. - if (auto *ED = dyn_cast<EnumDecl>(D)) { - for (auto *EI : ED->enumerators()) - PushOnScopeChains(EI, FnBodyScope, /*AddToContext=*/false); - } - } - } - // Ensure that the function's exception specification is instantiated. if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>()) ResolveExceptionSpec(D->getLocation(), FPT); @@ -11446,7 +11829,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, sema::AnalysisBasedWarnings::Policy WP = AnalysisWarnings.getDefaultPolicy(); sema::AnalysisBasedWarnings::Policy *ActivePolicy = nullptr; - if (getLangOpts().Coroutines && !getCurFunction()->CoroutineStmts.empty()) + if (getLangOpts().CoroutinesTS && !getCurFunction()->CoroutineStmts.empty()) CheckCompletedCoroutineBody(FD, Body); if (FD) { @@ -11555,6 +11938,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, << FixItHint::CreateInsertion(FTL.getRParenLoc(), "void"); } } + + // GNU warning -Wstrict-prototypes + // 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) { + TypeSourceInfo *TI = FD->getTypeSourceInfo(); + TypeLoc TL = TI->getTypeLoc(); + FunctionTypeLoc FTL = TL.castAs<FunctionTypeLoc>(); + Diag(FTL.getLParenLoc(), diag::warn_strict_prototypes) << 1; + } } if (auto *MD = dyn_cast<CXXMethodDecl>(FD)) { @@ -11637,6 +12035,9 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, return nullptr; } + if (Body && getCurFunction()->HasPotentialAvailabilityViolations) + DiagnoseUnguardedAvailabilityViolations(dcl); + assert(!getCurFunction()->ObjCShouldCallSuper && "This should only be set for ObjC methods, which should have been " "handled in the block above."); @@ -11683,6 +12084,21 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD && FD->hasAttr<NakedAttr>()) { for (const Stmt *S : Body->children()) { + // Allow local register variables without initializer as they don't + // require prologue. + bool RegisterVariables = false; + if (auto *DS = dyn_cast<DeclStmt>(S)) { + for (const auto *Decl : DS->decls()) { + if (const auto *Var = dyn_cast<VarDecl>(Decl)) { + RegisterVariables = + Var->hasAttr<AsmLabelAttr>() && !Var->hasInit(); + if (!RegisterVariables) + break; + } + } + } + if (RegisterVariables) + continue; if (!isa<AsmStmt>(S) && !isa<NullStmt>(S)) { Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function); Diag(FD->getAttr<NakedAttr>()->getLocation(), diag::note_attribute); @@ -11796,6 +12212,7 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, Loc, Loc, D), DS.getAttributes(), SourceLocation()); @@ -12069,6 +12486,31 @@ static bool isClassCompatTagKind(TagTypeKind Tag) return Tag == TTK_Struct || Tag == TTK_Class || Tag == TTK_Interface; } +Sema::NonTagKind Sema::getNonTagTypeDeclKind(const Decl *PrevDecl, + TagTypeKind TTK) { + if (isa<TypedefDecl>(PrevDecl)) + return NTK_Typedef; + else if (isa<TypeAliasDecl>(PrevDecl)) + return NTK_TypeAlias; + else if (isa<ClassTemplateDecl>(PrevDecl)) + return NTK_Template; + else if (isa<TypeAliasTemplateDecl>(PrevDecl)) + return NTK_TypeAliasTemplate; + else if (isa<TemplateTemplateParmDecl>(PrevDecl)) + return NTK_TemplateTemplateArgument; + switch (TTK) { + case TTK_Struct: + case TTK_Interface: + case TTK_Class: + return getLangOpts().CPlusPlus ? NTK_NonClass : NTK_NonStruct; + case TTK_Union: + return NTK_NonUnion; + case TTK_Enum: + return NTK_NonEnum; + } + llvm_unreachable("invalid TTK"); +} + /// \brief Determine whether a tag with a given kind is acceptable /// as a redeclaration of the given tag declaration. /// @@ -12226,28 +12668,6 @@ static bool isAcceptableTagRedeclContext(Sema &S, DeclContext *OldDC, return false; } -/// Find the DeclContext in which a tag is implicitly declared if we see an -/// elaborated type specifier in the specified context, and lookup finds -/// nothing. -static DeclContext *getTagInjectionContext(DeclContext *DC) { - while (!DC->isFileContext() && !DC->isFunctionOrMethod()) - DC = DC->getParent(); - return DC; -} - -/// Find the Scope in which a tag is implicitly declared if we see an -/// elaborated type specifier in the specified context, and lookup finds -/// nothing. -static Scope *getTagInjectionScope(Scope *S, const LangOptions &LangOpts) { - while (S->isClassScope() || - (LangOpts.CPlusPlus && - S->isFunctionPrototypeScope()) || - ((S->getFlags() & Scope::DeclScope) == 0) || - (S->getEntity() && S->getEntity()->isTransparentContext())) - S = S->getParent(); - return S; -} - /// \brief This is invoked when we see 'struct foo' or 'struct {'. In the /// former case, Name will be non-null. In the later case, Name will be null. /// TagSpec indicates what kind of tag this is. TUK indicates whether this is a @@ -12361,6 +12781,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclContext *SearchDC = CurContext; DeclContext *DC = CurContext; bool isStdBadAlloc = false; + bool isStdAlignValT = false; RedeclarationKind Redecl = ForRedeclaration; if (TUK == TUK_Friend || TUK == TUK_Reference) @@ -12515,15 +12936,20 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } if (getLangOpts().CPlusPlus && Name && DC && StdNamespace && - DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) { - // This is a declaration of or a reference to "std::bad_alloc". - isStdBadAlloc = true; + DC->Equals(getStdNamespace())) { + if (Name->isStr("bad_alloc")) { + // This is a declaration of or a reference to "std::bad_alloc". + isStdBadAlloc = true; - if (Previous.empty() && StdBadAlloc) { - // std::bad_alloc has been implicitly declared (but made invisible to - // name lookup). Fill in this implicit declaration as the previous + // If std::bad_alloc has been implicitly declared (but made invisible to + // name lookup), fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. - Previous.addDecl(getStdBadAlloc()); + if (Previous.empty() && StdBadAlloc) + Previous.addDecl(getStdBadAlloc()); + } else if (Name->isStr("align_val_t")) { + isStdAlignValT = true; + if (Previous.empty() && StdAlignValT) + Previous.addDecl(getStdAlignValT()); } } @@ -12843,11 +13269,9 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // (non-redeclaration) lookup. if ((TUK == TUK_Reference || TUK == TUK_Friend) && !Previous.isForRedeclaration()) { - unsigned Kind = 0; - if (isa<TypedefDecl>(PrevDecl)) Kind = 1; - else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2; - else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3; - Diag(NameLoc, diag::err_tag_reference_non_tag) << Kind; + NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); + Diag(NameLoc, diag::err_tag_reference_non_tag) << PrevDecl << NTK + << Kind; Diag(PrevDecl->getLocation(), diag::note_declared_at); Invalid = true; @@ -12858,11 +13282,8 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Diagnose implicit declarations introduced by elaborated types. } else if (TUK == TUK_Reference || TUK == TUK_Friend) { - unsigned Kind = 0; - if (isa<TypedefDecl>(PrevDecl)) Kind = 1; - else if (isa<TypeAliasDecl>(PrevDecl)) Kind = 2; - else if (isa<ClassTemplateDecl>(PrevDecl)) Kind = 3; - Diag(NameLoc, diag::err_tag_reference_conflict) << Kind; + NonTagKind NTK = getNonTagTypeDeclKind(PrevDecl, Kind); + Diag(NameLoc, diag::err_tag_reference_conflict) << NTK; Diag(PrevDecl->getLocation(), diag::note_previous_decl) << PrevDecl; Invalid = true; @@ -12915,6 +13336,10 @@ CreateNewDecl: New = EnumDecl::Create(Context, SearchDC, KWLoc, Loc, Name, cast_or_null<EnumDecl>(PrevDecl), ScopedEnum, ScopedEnumUsesClassTag, !EnumUnderlying.isNull()); + + if (isStdAlignValT && (!StdAlignValT || getStdAlignValT()->isImplicit())) + StdAlignValT = cast<EnumDecl>(New); + // If this is an undefined enum, warn. if (TUK != TUK_Definition && !Invalid) { TagDecl *Def; @@ -13047,7 +13472,6 @@ CreateNewDecl: } else if (!PrevDecl) { Diag(Loc, diag::warn_decl_in_param_list) << Context.getTagDeclType(New); } - DeclsInPrototypeScope.push_back(New); } if (Invalid) @@ -13112,7 +13536,14 @@ CreateNewDecl: OwnedDecl = true; // In C++, don't return an invalid declaration. We can't recover well from // the cases where we make the type anonymous. - return (Invalid && getLangOpts().CPlusPlus) ? nullptr : New; + if (Invalid && getLangOpts().CPlusPlus) { + if (New->isBeingDefined()) + if (auto RD = dyn_cast<RecordDecl>(New)) + RD->completeDefinition(); + return nullptr; + } else { + return New; + } } void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { @@ -13347,6 +13778,13 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, Declarator &D, Expr *BitWidth, InClassInitStyle InitStyle, AccessSpecifier AS) { + if (D.isDecompositionDeclarator()) { + const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); + Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) + << Decomp.getSourceRange(); + return nullptr; + } + IdentifierInfo *II = D.getIdentifier(); SourceLocation Loc = DeclStart; if (II) Loc = D.getIdentifierLoc(); @@ -14140,6 +14578,14 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, if (!Completed) Record->completeDefinition(); + // We may have deferred checking for a deleted destructor. Check now. + if (CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Record)) { + auto *Dtor = CXXRecord->getDestructor(); + if (Dtor && Dtor->isImplicit() && + ShouldDeleteSpecialMember(Dtor, CXXDestructor)) + SetDeclDeleted(Dtor, CXXRecord->getLocation()); + } + if (Record->hasAttrs()) { CheckAlignasUnderalignment(Record); @@ -15054,15 +15500,97 @@ static void checkModuleImportContext(Sema &S, Module *M, } else if (!M->IsExternC && ExternCLoc.isValid()) { S.Diag(ImportLoc, diag::ext_module_import_in_extern_c) << M->getFullModuleName(); - S.Diag(ExternCLoc, diag::note_module_import_in_extern_c); + S.Diag(ExternCLoc, diag::note_extern_c_begins_here); + } +} + +Sema::DeclGroupPtrTy Sema::ActOnModuleDecl(SourceLocation ModuleLoc, + ModuleDeclKind MDK, + ModuleIdPath Path) { + // 'module implementation' requires that we are not compiling a module of any + // kind. 'module' and 'module partition' require that we are compiling a + // module inteface (not a module map). + auto CMK = getLangOpts().getCompilingModule(); + if (MDK == ModuleDeclKind::Implementation + ? CMK != LangOptions::CMK_None + : CMK != LangOptions::CMK_ModuleInterface) { + Diag(ModuleLoc, diag::err_module_interface_implementation_mismatch) + << (unsigned)MDK; + return nullptr; + } + + // FIXME: Create a ModuleDecl and return it. + + // FIXME: Most of this work should be done by the preprocessor rather than + // here, in case we look ahead across something where the current + // module matters (eg a #include). + + // The dots in a module name in the Modules TS are a lie. Unlike Clang's + // hierarchical module map modules, the dots here are just another character + // that can appear in a module name. Flatten down to the actual module name. + std::string ModuleName; + for (auto &Piece : Path) { + if (!ModuleName.empty()) + ModuleName += "."; + ModuleName += Piece.first->getName(); + } + + // If a module name was explicitly specified on the command line, it must be + // correct. + if (!getLangOpts().CurrentModule.empty() && + getLangOpts().CurrentModule != ModuleName) { + Diag(Path.front().second, diag::err_current_module_name_mismatch) + << SourceRange(Path.front().second, Path.back().second) + << getLangOpts().CurrentModule; + return nullptr; + } + const_cast<LangOptions&>(getLangOpts()).CurrentModule = ModuleName; + + auto &Map = PP.getHeaderSearchInfo().getModuleMap(); + + switch (MDK) { + case ModuleDeclKind::Module: { + // FIXME: Check we're not in a submodule. + + // We can't have imported a definition of this module or parsed a module + // map defining it already. + if (auto *M = Map.findModule(ModuleName)) { + Diag(Path[0].second, diag::err_module_redefinition) << ModuleName; + if (M->DefinitionLoc.isValid()) + Diag(M->DefinitionLoc, diag::note_prev_module_definition); + else if (const auto *FE = M->getASTFile()) + Diag(M->DefinitionLoc, diag::note_prev_module_definition_from_ast_file) + << FE->getName(); + return nullptr; + } + + // Create a Module for the module that we're defining. + Module *Mod = Map.createModuleForInterfaceUnit(ModuleLoc, ModuleName); + assert(Mod && "module creation should not fail"); + + // Enter the semantic scope of the module. + ActOnModuleBegin(ModuleLoc, Mod); + return nullptr; + } + + case ModuleDeclKind::Partition: + // FIXME: Check we are in a submodule of the named module. + return nullptr; + + case ModuleDeclKind::Implementation: + std::pair<IdentifierInfo *, SourceLocation> ModuleNameLoc( + PP.getIdentifierInfo(ModuleName), Path[0].second); + + DeclResult Import = ActOnModuleImport(ModuleLoc, ModuleLoc, ModuleNameLoc); + if (Import.isInvalid()) + return nullptr; + return ConvertDeclToDeclGroup(Import.get()); } -} -void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) { - return checkModuleImportContext(*this, M, ImportLoc, CurContext); + llvm_unreachable("unexpected module decl kind"); } -DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, +DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc, SourceLocation ImportLoc, ModuleIdPath Path) { Module *Mod = @@ -15078,8 +15606,11 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, // FIXME: we should support importing a submodule within a different submodule // of the same top-level module. Until we do, make it an error rather than // silently ignoring the import. - if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule) - Diag(ImportLoc, getLangOpts().CompilingModule + // Import-from-implementation is valid in the Modules TS. FIXME: Should we + // warn on a redundant import of the current module? + if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule && + (getLangOpts().isCompilingModule() || !getLangOpts().ModulesTS)) + Diag(ImportLoc, getLangOpts().isCompilingModule() ? diag::err_module_self_import : diag::err_module_import_in_implementation) << Mod->getFullModuleName() << getLangOpts().CurrentModule; @@ -15096,17 +15627,21 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, IdentifierLocs.push_back(Path[I].second); } - ImportDecl *Import = ImportDecl::Create(Context, - Context.getTranslationUnitDecl(), - AtLoc.isValid()? AtLoc : ImportLoc, + TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); + ImportDecl *Import = ImportDecl::Create(Context, TU, StartLoc, Mod, IdentifierLocs); - Context.getTranslationUnitDecl()->addDecl(Import); + if (!ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, Import); + TU->addDecl(Import); return Import; } void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); + BuildModuleInclude(DirectiveLoc, Mod); +} +void Sema::BuildModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { // Determine whether we're in the #include buffer for a module. The #includes // in that buffer do not qualify as module imports; they're just an // implementation detail of us building the module. @@ -15116,13 +15651,7 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { TUKind == TU_Module && getSourceManager().isWrittenInMainFile(DirectiveLoc); - // Similarly, if we're in the implementation of a module, don't - // synthesize an illegal module import. FIXME: Why not? - bool ShouldAddImport = - !IsInModuleIncludes && - (getLangOpts().CompilingModule || - getLangOpts().CurrentModule.empty() || - getLangOpts().CurrentModule != Mod->getTopLevelModuleName()); + bool ShouldAddImport = !IsInModuleIncludes; // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. @@ -15131,6 +15660,8 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, DirectiveLoc, Mod, DirectiveLoc); + if (!ModuleScopes.empty()) + Context.addModuleInitializer(ModuleScopes.back().Module, ImportD); TU->addDecl(ImportD); Consumer.HandleImplicitImportDecl(ImportD); } @@ -15140,24 +15671,35 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { } void Sema::ActOnModuleBegin(SourceLocation DirectiveLoc, Module *Mod) { - checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext); + checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext, true); + ModuleScopes.push_back({}); + ModuleScopes.back().Module = Mod; if (getLangOpts().ModulesLocalVisibility) - VisibleModulesStack.push_back(std::move(VisibleModules)); + ModuleScopes.back().OuterVisibleModules = std::move(VisibleModules); + VisibleModules.setVisible(Mod, DirectiveLoc); } -void Sema::ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod) { - checkModuleImportContext(*this, Mod, DirectiveLoc, CurContext); - +void Sema::ActOnModuleEnd(SourceLocation EofLoc, Module *Mod) { if (getLangOpts().ModulesLocalVisibility) { - VisibleModules = std::move(VisibleModulesStack.back()); - VisibleModulesStack.pop_back(); - VisibleModules.setVisible(Mod, DirectiveLoc); + VisibleModules = std::move(ModuleScopes.back().OuterVisibleModules); // Leaving a module hides namespace names, so our visible namespace cache // is now out of date. VisibleNamespaceCache.clear(); } + + assert(!ModuleScopes.empty() && ModuleScopes.back().Module == Mod && + "left the wrong module scope"); + ModuleScopes.pop_back(); + + // We got to the end of processing a #include of a local module. Create an + // ImportDecl as we would for an imported module. + FileID File = getSourceManager().getFileID(EofLoc); + assert(File != getSourceManager().getMainFileID() && + "end of submodule in main source file"); + SourceLocation DirectiveLoc = getSourceManager().getIncludeLoc(File); + BuildModuleInclude(DirectiveLoc, Mod); } void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, @@ -15178,6 +15720,39 @@ void Sema::createImplicitModuleImportForErrorRecovery(SourceLocation Loc, VisibleModules.setVisible(Mod, Loc); } +/// We have parsed the start of an export declaration, including the '{' +/// (if present). +Decl *Sema::ActOnStartExportDecl(Scope *S, SourceLocation ExportLoc, + SourceLocation LBraceLoc) { + ExportDecl *D = ExportDecl::Create(Context, CurContext, ExportLoc); + + // C++ Modules TS draft: + // An export-declaration [...] shall not contain more than one + // export keyword. + // + // The intent here is that an export-declaration cannot appear within another + // export-declaration. + if (D->isExported()) + Diag(ExportLoc, diag::err_export_within_export); + + CurContext->addDecl(D); + PushDeclContext(S, D); + return D; +} + +/// Complete the definition of an export declaration. +Decl *Sema::ActOnFinishExportDecl(Scope *S, Decl *D, SourceLocation RBraceLoc) { + auto *ED = cast<ExportDecl>(D); + if (RBraceLoc.isValid()) + ED->setRBraceLoc(RBraceLoc); + + // FIXME: Diagnose export of internal-linkage declaration (including + // anonymous namespace). + + PopDeclContext(); + return D; +} + void Sema::ActOnPragmaRedefineExtname(IdentifierInfo* Name, IdentifierInfo* AliasName, SourceLocation PragmaLoc, @@ -15239,29 +15814,3 @@ void Sema::ActOnPragmaWeakAlias(IdentifierInfo* Name, Decl *Sema::getObjCDeclContext() const { return (dyn_cast_or_null<ObjCContainerDecl>(CurContext)); } - -AvailabilityResult Sema::getCurContextAvailability() const { - const Decl *D = cast_or_null<Decl>(getCurObjCLexicalContext()); - if (!D) - return AR_Available; - - // If we are within an Objective-C method, we should consult - // both the availability of the method as well as the - // enclosing class. If the class is (say) deprecated, - // the entire method is considered deprecated from the - // purpose of checking if the current context is deprecated. - if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { - AvailabilityResult R = MD->getAvailability(); - if (R != AR_Available) - return R; - D = MD->getClassInterface(); - } - // If we are within an Objective-c @implementation, it - // gets the same availability context as the @interface. - else if (const ObjCImplementationDecl *ID = - dyn_cast<ObjCImplementationDecl>(D)) { - D = ID->getClassInterface(); - } - // Recover from user error. - return D ? D->getAvailability() : AR_Available; -} diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index a5780a7d71fb0..f9b6a91a300fb 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -11,9 +11,9 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/DeclObjC.h" @@ -21,7 +21,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/Mangle.h" -#include "clang/AST/ASTMutationListener.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/CharInfo.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -31,6 +31,7 @@ #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" @@ -245,6 +246,28 @@ static bool checkUInt32Argument(Sema &S, const AttributeList &Attr, return true; } +/// \brief Wrapper around checkUInt32Argument, with an extra check to be sure +/// that the result will fit into a regular (signed) int. All args have the same +/// purpose as they do in checkUInt32Argument. +static bool checkPositiveIntArgument(Sema &S, const AttributeList &Attr, + const Expr *Expr, int &Val, + unsigned Idx = UINT_MAX) { + uint32_t UVal; + if (!checkUInt32Argument(S, Attr, Expr, UVal, Idx)) + return false; + + if (UVal > (uint32_t)std::numeric_limits<int>::max()) { + llvm::APSInt I(32); // for toString + I = UVal; + S.Diag(Expr->getExprLoc(), diag::err_ice_too_large) + << I.toString(10, false) << 32 << /* Unsigned */ 0; + return false; + } + + Val = UVal; + return true; +} + /// \brief Diagnose mutually exclusive attributes when present on a given /// declaration. Returns true if diagnosed. template <typename AttrTy> @@ -729,6 +752,69 @@ static void handleAssertExclusiveLockAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +/// \brief Checks to be sure that the given parameter number is inbounds, and is +/// an some integral type. Will emit appropriate diagnostics if this returns +/// false. +/// +/// FuncParamNo is expected to be from the user, so is base-1. AttrArgNo is used +/// to actually retrieve the argument, so it's base-0. +static bool checkParamIsIntegerType(Sema &S, const FunctionDecl *FD, + const AttributeList &Attr, + unsigned FuncParamNo, unsigned AttrArgNo) { + assert(Attr.isArgExpr(AttrArgNo) && "Expected expression argument"); + uint64_t Idx; + if (!checkFunctionOrMethodParameterIndex(S, FD, Attr, FuncParamNo, + Attr.getArgAsExpr(AttrArgNo), Idx)) + return false; + + const ParmVarDecl *Param = FD->getParamDecl(Idx); + if (!Param->getType()->isIntegerType() && !Param->getType()->isCharType()) { + SourceLocation SrcLoc = Attr.getArgAsExpr(AttrArgNo)->getLocStart(); + S.Diag(SrcLoc, diag::err_attribute_integers_only) + << Attr.getName() << Param->getSourceRange(); + return false; + } + return true; +} + +static void handleAllocSizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (!checkAttributeAtLeastNumArgs(S, Attr, 1) || + !checkAttributeAtMostNumArgs(S, Attr, 2)) + return; + + const auto *FD = cast<FunctionDecl>(D); + if (!FD->getReturnType()->isPointerType()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_return_pointers_only) + << Attr.getName(); + return; + } + + const Expr *SizeExpr = Attr.getArgAsExpr(0); + int SizeArgNo; + // Paramater indices are 1-indexed, hence Index=1 + if (!checkPositiveIntArgument(S, Attr, SizeExpr, SizeArgNo, /*Index=*/1)) + return; + + if (!checkParamIsIntegerType(S, FD, Attr, SizeArgNo, /*AttrArgNo=*/0)) + return; + + // Args are 1-indexed, so 0 implies that the arg was not present + int NumberArgNo = 0; + if (Attr.getNumArgs() == 2) { + const Expr *NumberExpr = Attr.getArgAsExpr(1); + // Paramater indices are 1-based, hence Index=2 + if (!checkPositiveIntArgument(S, Attr, NumberExpr, NumberArgNo, + /*Index=*/2)) + return; + + if (!checkParamIsIntegerType(S, FD, Attr, NumberArgNo, /*AttrArgNo=*/1)) + return; + } + + D->addAttr(::new (S.Context) AllocSizeAttr( + Attr.getRange(), S.Context, SizeArgNo, NumberArgNo, + Attr.getAttributeSpellingListIndex())); +} static bool checkTryLockFunAttrCommon(Sema &S, Decl *D, const AttributeList &Attr, @@ -824,8 +910,8 @@ static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(D), Diags)) { S.Diag(Attr.getLoc(), diag::err_enable_if_never_constant_expr); - for (int I = 0, N = Diags.size(); I != N; ++I) - S.Diag(Diags[I].first, Diags[I].second); + for (const PartialDiagnosticAt &PDiag : Diags) + S.Diag(PDiag.first, PDiag.second); return; } @@ -2803,20 +2889,21 @@ enum FormatAttrKind { /// types. static FormatAttrKind getFormatAttrKind(StringRef Format) { return llvm::StringSwitch<FormatAttrKind>(Format) - // Check for formats that get handled specially. - .Case("NSString", NSStringFormat) - .Case("CFString", CFStringFormat) - .Case("strftime", StrftimeFormat) + // Check for formats that get handled specially. + .Case("NSString", NSStringFormat) + .Case("CFString", CFStringFormat) + .Case("strftime", StrftimeFormat) - // Otherwise, check for supported formats. - .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat) - .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) - .Case("kprintf", SupportedFormat) // OpenBSD. - .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. - .Case("os_trace", SupportedFormat) + // Otherwise, check for supported formats. + .Cases("scanf", "printf", "printf0", "strfmon", SupportedFormat) + .Cases("cmn_err", "vcmn_err", "zcmn_err", SupportedFormat) + .Case("kprintf", SupportedFormat) // OpenBSD. + .Case("freebsd_kprintf", SupportedFormat) // FreeBSD. + .Case("os_trace", SupportedFormat) + .Case("os_log", SupportedFormat) - .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat) - .Default(InvalidFormat); + .Cases("gcc_diag", "gcc_cdiag", "gcc_cxxdiag", "gcc_tdiag", IgnoredFormat) + .Default(InvalidFormat); } /// Handle __attribute__((init_priority(priority))) attributes based on @@ -3043,10 +3130,14 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, return; } + if (FirstType->isIncompleteType()) + return; uint64_t FirstSize = S.Context.getTypeSize(FirstType); uint64_t FirstAlign = S.Context.getTypeAlign(FirstType); for (; Field != FieldEnd; ++Field) { QualType FieldType = Field->getType(); + if (FieldType->isIncompleteType()) + return; // FIXME: this isn't fully correct; we also need to test whether the // members of the union would all have the same calling convention as the // first member of the union. Checking just the size and alignment isn't @@ -3695,6 +3786,38 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D, D->addAttr(Optnone); } +static void handleConstantAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + auto *VD = cast<VarDecl>(D); + if (!VD->hasGlobalStorage()) { + S.Diag(Attr.getLoc(), diag::err_cuda_nonglobal_constant); + return; + } + D->addAttr(::new (S.Context) CUDAConstantAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + +static void handleSharedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, Attr.getRange(), + Attr.getName())) + return; + auto *VD = cast<VarDecl>(D); + // extern __shared__ is only allowed on arrays with no length (e.g. + // "int x[]"). + if (VD->hasExternalStorage() && !isa<IncompleteArrayType>(VD->getType())) { + S.Diag(Attr.getLoc(), diag::err_cuda_extern_shared) << VD; + return; + } + if (S.getLangOpts().CUDA && VD->hasLocalStorage() && + S.CUDADiagIfHostCode(Attr.getLoc(), diag::err_cuda_host_shared) + << S.CurrentCUDATarget()) + return; + D->addAttr(::new (S.Context) CUDASharedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, Attr.getRange(), Attr.getName()) || @@ -3801,6 +3924,10 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { SysVABIAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; + case AttributeList::AT_RegCall: + D->addAttr(::new (S.Context) RegCallAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; case AttributeList::AT_Pcs: { PcsAttr::PCSType PCS; switch (CC) { @@ -3862,6 +3989,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, case AttributeList::AT_Pascal: CC = CC_X86Pascal; break; case AttributeList::AT_SwiftCall: CC = CC_Swift; break; case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break; + case AttributeList::AT_RegCall: CC = CC_X86RegCall; break; case AttributeList::AT_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : CC_X86_64Win64; @@ -4603,6 +4731,19 @@ static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, // Microsoft specific attribute handlers. //===----------------------------------------------------------------------===// +UuidAttr *Sema::mergeUuidAttr(Decl *D, SourceRange Range, + unsigned AttrSpellingListIndex, StringRef Uuid) { + if (const auto *UA = D->getAttr<UuidAttr>()) { + if (UA->getGuid().equals_lower(Uuid)) + return nullptr; + Diag(UA->getLocation(), diag::err_mismatched_uuid); + Diag(Range.getBegin(), diag::note_previous_uuid); + D->dropAttr<UuidAttr>(); + } + + return ::new (Context) UuidAttr(Range, Context, Uuid, AttrSpellingListIndex); +} + static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!S.LangOpts.CPlusPlus) { S.Diag(Attr.getLoc(), diag::err_attribute_not_supported_in_lang) @@ -4610,12 +4751,6 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { return; } - if (!isa<CXXRecordDecl>(D)) { - S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attr.getName() << ExpectedClass; - return; - } - StringRef StrRef; SourceLocation LiteralLoc; if (!S.checkStringLiteralArgumentAttr(Attr, 0, StrRef, &LiteralLoc)) @@ -4644,8 +4779,10 @@ static void handleUuidAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } - D->addAttr(::new (S.Context) UuidAttr(Attr.getRange(), S.Context, StrRef, - Attr.getAttributeSpellingListIndex())); + UuidAttr *UA = S.mergeUuidAttr(D, Attr.getRange(), + Attr.getAttributeSpellingListIndex(), StrRef); + if (UA) + D->addAttr(UA); } static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -4925,29 +5062,85 @@ static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } -static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, +static void handleAMDGPUFlatWorkGroupSizeAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint32_t Min = 0; + Expr *MinExpr = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + return; + + uint32_t Max = 0; + Expr *MaxExpr = Attr.getArgAsExpr(1); + if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + return; + + if (Min == 0 && Max != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) + << Attr.getName() << 0; + return; + } + if (Min > Max) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) + << Attr.getName() << 1; + return; + } + + D->addAttr(::new (S.Context) + AMDGPUFlatWorkGroupSizeAttr(Attr.getLoc(), S.Context, Min, Max, + Attr.getAttributeSpellingListIndex())); +} + +static void handleAMDGPUWavesPerEUAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + uint32_t Min = 0; + Expr *MinExpr = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, MinExpr, Min)) + return; + + uint32_t Max = 0; + if (Attr.getNumArgs() == 2) { + Expr *MaxExpr = Attr.getArgAsExpr(1); + if (!checkUInt32Argument(S, Attr, MaxExpr, Max)) + return; + } + + if (Min == 0 && Max != 0) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) + << Attr.getName() << 0; + return; + } + if (Max != 0 && Min > Max) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_invalid) + << Attr.getName() << 1; + return; + } + + D->addAttr(::new (S.Context) + AMDGPUWavesPerEUAttr(Attr.getLoc(), S.Context, Min, Max, + Attr.getAttributeSpellingListIndex())); +} + +static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, const AttributeList &Attr) { - uint32_t NumRegs; - Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs)) + uint32_t NumSGPR = 0; + Expr *NumSGPRExpr = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, NumSGPRExpr, NumSGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, - NumRegs, + AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, NumSGPR, Attr.getAttributeSpellingListIndex())); } -static void handleAMDGPUNumSGPRAttr(Sema &S, Decl *D, +static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, const AttributeList &Attr) { - uint32_t NumRegs; - Expr *NumRegsExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); - if (!checkUInt32Argument(S, Attr, NumRegsExpr, NumRegs)) + uint32_t NumVGPR = 0; + Expr *NumVGPRExpr = Attr.getArgAsExpr(0); + if (!checkUInt32Argument(S, Attr, NumVGPRExpr, NumVGPR)) return; D->addAttr(::new (S.Context) - AMDGPUNumSGPRAttr(Attr.getLoc(), S.Context, - NumRegs, + AMDGPUNumVGPRAttr(Attr.getLoc(), S.Context, NumVGPR, Attr.getAttributeSpellingListIndex())); } @@ -5205,9 +5398,15 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); - D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str, - Replacement, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (S.Context) + DeprecatedAttr(Attr.getRange(), S.Context, Str, Replacement, + Attr.getAttributeSpellingListIndex())); +} + +static bool isGlobalVar(const Decl *D) { + if (const auto *S = dyn_cast<VarDecl>(D)) + return S->hasGlobalStorage(); + return false; } static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -5225,7 +5424,9 @@ static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (parseSanitizerValue(SanitizerName, /*AllowGroups=*/true) == 0) S.Diag(LiteralLoc, diag::warn_unknown_sanitizer_ignored) << SanitizerName; - + else if (isGlobalVar(D) && SanitizerName != "address") + S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; Sanitizers.push_back(SanitizerName); } @@ -5238,12 +5439,14 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef AttrName = Attr.getName()->getName(); normalizeName(AttrName); - StringRef SanitizerName = - llvm::StringSwitch<StringRef>(AttrName) - .Case("no_address_safety_analysis", "address") - .Case("no_sanitize_address", "address") - .Case("no_sanitize_thread", "thread") - .Case("no_sanitize_memory", "memory"); + StringRef SanitizerName = llvm::StringSwitch<StringRef>(AttrName) + .Case("no_address_safety_analysis", "address") + .Case("no_sanitize_address", "address") + .Case("no_sanitize_thread", "thread") + .Case("no_sanitize_memory", "memory"); + if (isGlobalVar(D) && SanitizerName != "address") + S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunction; D->addAttr(::new (S.Context) NoSanitizeAttr(Attr.getRange(), S.Context, &SanitizerName, 1, Attr.getAttributeSpellingListIndex())); @@ -5401,12 +5604,18 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoMips16: handleSimpleAttribute<NoMips16Attr>(S, D, Attr); break; - case AttributeList::AT_AMDGPUNumVGPR: - handleAMDGPUNumVGPRAttr(S, D, Attr); + case AttributeList::AT_AMDGPUFlatWorkGroupSize: + handleAMDGPUFlatWorkGroupSizeAttr(S, D, Attr); + break; + case AttributeList::AT_AMDGPUWavesPerEU: + handleAMDGPUWavesPerEUAttr(S, D, Attr); break; case AttributeList::AT_AMDGPUNumSGPR: handleAMDGPUNumSGPRAttr(S, D, Attr); break; + case AttributeList::AT_AMDGPUNumVGPR: + handleAMDGPUNumVGPRAttr(S, D, Attr); + break; case AttributeList::AT_IBAction: handleSimpleAttribute<IBActionAttr>(S, D, Attr); break; @@ -5428,6 +5637,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_AlignValue: handleAlignValueAttr(S, D, Attr); break; + case AttributeList::AT_AllocSize: + handleAllocSizeAttr(S, D, Attr); + break; case AttributeList::AT_AlwaysInline: handleAlwaysInlineAttr(S, D, Attr); break; @@ -5450,8 +5662,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleCommonAttr(S, D, Attr); break; case AttributeList::AT_CUDAConstant: - handleSimpleAttributeWithExclusions<CUDAConstantAttr, CUDASharedAttr>(S, D, - Attr); + handleConstantAttr(S, D, Attr); break; case AttributeList::AT_PassObjectSize: handlePassObjectSizeAttr(S, D, Attr); @@ -5561,8 +5772,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute<NoThrowAttr>(S, D, Attr); break; case AttributeList::AT_CUDAShared: - handleSimpleAttributeWithExclusions<CUDASharedAttr, CUDAConstantAttr>(S, D, - Attr); + handleSharedAttr(S, D, Attr); break; case AttributeList::AT_VecReturn: handleVecReturnAttr(S, D, Attr); @@ -5629,6 +5839,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; + case AttributeList::AT_RequireConstantInit: + handleSimpleAttribute<RequireConstantInitAttr>(S, D, Attr); + break; case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; @@ -5650,6 +5863,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_ObjCRootClass: handleSimpleAttribute<ObjCRootClassAttr>(S, D, Attr); break; + case AttributeList::AT_ObjCSubclassingRestricted: + handleSimpleAttribute<ObjCSubclassingRestrictedAttr>(S, D, Attr); + break; case AttributeList::AT_ObjCExplicitProtocolImpl: handleObjCSuppresProtocolAttr(S, D, Attr); break; @@ -5728,6 +5944,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NoDuplicate: handleSimpleAttribute<NoDuplicateAttr>(S, D, Attr); break; + case AttributeList::AT_Convergent: + handleSimpleAttribute<ConvergentAttr>(S, D, Attr); + break; case AttributeList::AT_NoInline: handleSimpleAttribute<NoInlineAttr>(S, D, Attr); break; @@ -5739,6 +5958,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FastCall: case AttributeList::AT_ThisCall: case AttributeList::AT_Pascal: + case AttributeList::AT_RegCall: case AttributeList::AT_SwiftCall: case AttributeList::AT_VectorCall: case AttributeList::AT_MSABI: @@ -5955,7 +6175,11 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, } else if (Attr *A = D->getAttr<VecTypeHintAttr>()) { Diag(D->getLocation(), diag::err_opencl_kernel_attr) << A; D->setInvalidDecl(); - } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + } else if (Attr *A = D->getAttr<AMDGPUFlatWorkGroupSizeAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); + } else if (Attr *A = D->getAttr<AMDGPUWavesPerEUAttr>()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) << A << ExpectedKernelFunction; D->setInvalidDecl(); @@ -5963,6 +6187,10 @@ void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) << A << ExpectedKernelFunction; D->setInvalidDecl(); + } else if (Attr *A = D->getAttr<AMDGPUNumVGPRAttr>()) { + Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) + << A << ExpectedKernelFunction; + D->setInvalidDecl(); } } } @@ -6194,30 +6422,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, diag.Triggered = true; } -static bool isDeclDeprecated(Decl *D) { - do { - if (D->isDeprecated()) - return true; - // A category implicitly has the availability of the interface. - if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - return Interface->isDeprecated(); - } while ((D = cast_or_null<Decl>(D->getDeclContext()))); - return false; -} - -static bool isDeclUnavailable(Decl *D) { - do { - if (D->isUnavailable()) - return true; - // A category implicitly has the availability of the interface. - if (const ObjCCategoryDecl *CatD = dyn_cast<ObjCCategoryDecl>(D)) - if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) - return Interface->isUnavailable(); - } while ((D = cast_or_null<Decl>(D->getDeclContext()))); - return false; -} - static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, const Decl *D) { // Check each AvailabilityAttr to find the one for this platform. @@ -6246,7 +6450,72 @@ static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, return nullptr; } -static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, +/// \brief 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) { + 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; + + if (C->isUnavailable()) + return true; + return false; + }; + + // FIXME: This is a temporary workaround! Some existing Apple headers depends + // on nested declarations in an @interface having the availability of the + // interface when they really shouldn't: they are members of the enclosing + // context, and can referenced from there. + if (S.OriginalLexicalContext && cast<Decl>(S.OriginalLexicalContext) != Ctx) { + auto *OrigCtx = cast<Decl>(S.OriginalLexicalContext); + if (CheckContext(OrigCtx)) + return false; + + // An implementation implicitly has the availability of the interface. + if (auto *CatOrImpl = dyn_cast<ObjCImplDecl>(OrigCtx)) { + if (const ObjCInterfaceDecl *Interface = CatOrImpl->getClassInterface()) + if (CheckContext(Interface)) + return false; + } + // A category implicitly has the availability of the interface. + else if (auto *CatD = dyn_cast<ObjCCategoryDecl>(OrigCtx)) + if (const ObjCInterfaceDecl *Interface = CatD->getClassInterface()) + if (CheckContext(Interface)) + return false; + } + + do { + if (CheckContext(Ctx)) + return false; + + // An implementation implicitly has the availability of the interface. + if (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 (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 void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, @@ -6262,11 +6531,15 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, // Matches diag::note_availability_specified_here. unsigned available_here_select_kind; - // Don't warn if our current context is deprecated or unavailable. + VersionTuple DeclVersion; + if (const AvailabilityAttr *AA = getAttrForPlatform(S.Context, D)) + DeclVersion = AA->getIntroduced(); + + if (!ShouldDiagnoseAvailabilityInContext(S, K, DeclVersion, Ctx)) + return; + switch (K) { - case Sema::AD_Deprecation: - if (isDeclDeprecated(Ctx) || isDeclUnavailable(Ctx)) - return; + case AR_Deprecated: diag = !ObjCPropertyAccess ? diag::warn_deprecated : diag::warn_property_method_deprecated; diag_message = diag::warn_deprecated_message; @@ -6275,9 +6548,7 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, available_here_select_kind = /* deprecated */ 2; break; - case Sema::AD_Unavailable: - if (isDeclUnavailable(Ctx)) - return; + case AR_Unavailable: diag = !ObjCPropertyAccess ? diag::err_unavailable : diag::err_property_method_unavailable; diag_message = diag::err_unavailable_message; @@ -6329,18 +6600,21 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, } break; - case Sema::AD_Partial: + case AR_NotYetIntroduced: diag = diag::warn_partial_availability; diag_message = diag::warn_partial_message; diag_fwdclass_message = diag::warn_partial_fwdclass_message; property_note_select = /* partial */ 2; available_here_select_kind = /* partial */ 3; break; + + case AR_Available: + llvm_unreachable("Warning for availability of available declaration?"); } CharSourceRange UseRange; StringRef Replacement; - if (K == Sema::AD_Deprecation) { + if (K == AR_Deprecated) { if (auto attr = D->getAttr<DeprecatedAttr>()) Replacement = attr->getReplacement(); if (auto attr = getAttrForPlatform(S.Context, D)) @@ -6393,21 +6667,20 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, S.Diag(D->getLocation(), diag_available_here) << D << available_here_select_kind; - if (K == Sema::AD_Partial) + if (K == AR_NotYetIntroduced) S.Diag(Loc, diag::note_partial_availability_silence) << D; } static void handleDelayedAvailabilityCheck(Sema &S, DelayedDiagnostic &DD, Decl *Ctx) { - assert(DD.Kind == DelayedDiagnostic::Deprecation || - DD.Kind == DelayedDiagnostic::Unavailable); - Sema::AvailabilityDiagnostic AD = DD.Kind == DelayedDiagnostic::Deprecation - ? Sema::AD_Deprecation - : Sema::AD_Unavailable; + assert(DD.Kind == DelayedDiagnostic::Availability && + "Expected an availability diagnostic here"); + DD.Triggered = true; DoEmitAvailabilityWarning( - S, AD, Ctx, DD.getDeprecationDecl(), DD.getDeprecationMessage(), DD.Loc, - DD.getUnknownObjCClass(), DD.getObjCProperty(), false); + S, DD.getAvailabilityResult(), Ctx, DD.getAvailabilityDecl(), + DD.getAvailabilityMessage(), DD.Loc, DD.getUnknownObjCClass(), + DD.getObjCProperty(), false); } void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { @@ -6437,8 +6710,7 @@ void Sema::PopParsingDeclaration(ParsingDeclState state, Decl *decl) { continue; switch (diag.Kind) { - case DelayedDiagnostic::Deprecation: - case DelayedDiagnostic::Unavailable: + case DelayedDiagnostic::Availability: // Don't bother giving deprecation/unavailable diagnostics if // the decl is invalid. if (!decl->isInvalidDecl()) @@ -6466,21 +6738,173 @@ void Sema::redelayDiagnostics(DelayedDiagnosticPool &pool) { curPool->steal(pool); } -void Sema::EmitAvailabilityWarning(AvailabilityDiagnostic AD, +void Sema::EmitAvailabilityWarning(AvailabilityResult AR, NamedDecl *D, StringRef Message, SourceLocation Loc, const ObjCInterfaceDecl *UnknownObjCClass, const ObjCPropertyDecl *ObjCProperty, bool ObjCPropertyAccess) { // Delay if we're currently parsing a declaration. - if (DelayedDiagnostics.shouldDelayDiagnostics() && AD != AD_Partial) { + if (DelayedDiagnostics.shouldDelayDiagnostics()) { DelayedDiagnostics.add(DelayedDiagnostic::makeAvailability( - AD, Loc, D, UnknownObjCClass, ObjCProperty, Message, + AR, Loc, D, UnknownObjCClass, ObjCProperty, Message, ObjCPropertyAccess)); return; } Decl *Ctx = cast<Decl>(getCurLexicalContext()); - DoEmitAvailabilityWarning(*this, AD, Ctx, D, Message, Loc, UnknownObjCClass, + DoEmitAvailabilityWarning(*this, AR, Ctx, D, Message, Loc, UnknownObjCClass, ObjCProperty, ObjCPropertyAccess); } + +namespace { + +/// \brief 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; + + void DiagnoseDeclAvailability(NamedDecl *D, SourceRange Range); + +public: + DiagnoseUnguardedAvailability(Sema &SemaRef, Decl *Ctx) + : SemaRef(SemaRef), Ctx(Ctx) { + AvailabilityStack.push_back( + SemaRef.Context.getTargetInfo().getPlatformMinVersion()); + } + + void IssueDiagnostics(Stmt *S) { TraverseStmt(S); } + + bool TraverseIfStmt(IfStmt *If); + + bool VisitObjCMessageExpr(ObjCMessageExpr *Msg) { + if (ObjCMethodDecl *D = Msg->getMethodDecl()) + DiagnoseDeclAvailability( + D, SourceRange(Msg->getSelectorStartLoc(), Msg->getLocEnd())); + return true; + } + + bool VisitDeclRefExpr(DeclRefExpr *DRE) { + DiagnoseDeclAvailability(DRE->getDecl(), + SourceRange(DRE->getLocStart(), DRE->getLocEnd())); + return true; + } + + bool VisitMemberExpr(MemberExpr *ME) { + DiagnoseDeclAvailability(ME->getMemberDecl(), + SourceRange(ME->getLocStart(), ME->getLocEnd())); + return true; + } + + bool VisitTypeLoc(TypeLoc Ty); +}; + +void DiagnoseUnguardedAvailability::DiagnoseDeclAvailability( + NamedDecl *D, SourceRange Range) { + + VersionTuple ContextVersion = AvailabilityStack.back(); + if (AvailabilityResult Result = + SemaRef.ShouldDiagnoseAvailabilityOfDecl(D, nullptr)) { + // All other diagnostic kinds have already been handled in + // DiagnoseAvailabilityOfDecl. + if (Result != AR_NotYetIntroduced) + return; + + const AvailabilityAttr *AA = getAttrForPlatform(SemaRef.getASTContext(), D); + VersionTuple Introduced = AA->getIntroduced(); + + if (ContextVersion >= 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)) + return; + + SemaRef.Diag(Range.getBegin(), diag::warn_unguarded_availability) + << Range << D + << AvailabilityAttr::getPrettyPlatformName( + SemaRef.getASTContext().getTargetInfo().getPlatformName()) + << Introduced.getAsString(); + + SemaRef.Diag(D->getLocation(), diag::note_availability_specified_here) + << D << /* partial */ 3; + + // FIXME: Replace this with a fixit diagnostic. + SemaRef.Diag(Range.getBegin(), diag::note_unguarded_available_silence) + << Range << D; + } +} + +bool DiagnoseUnguardedAvailability::VisitTypeLoc(TypeLoc Ty) { + const Type *TyPtr = Ty.getTypePtr(); + SourceRange Range{Ty.getBeginLoc(), Ty.getEndLoc()}; + + if (const TagType *TT = dyn_cast<TagType>(TyPtr)) { + TagDecl *TD = TT->getDecl(); + DiagnoseDeclAvailability(TD, Range); + + } else if (const TypedefType *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 Base::TraverseStmt(If->getThen()) && + Base::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(); + + assert(Body && "Need a body here!"); + + DiagnoseUnguardedAvailability(*this, D).IssueDiagnostics(Body); +} diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index e161c87f17399..084bd4c45eda2 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" @@ -36,9 +35,11 @@ #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" #include <map> #include <set> @@ -394,7 +395,8 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { ++argIdx) { ParmVarDecl *Param = cast<ParmVarDecl>(chunk.Fun.Params[argIdx].Param); if (Param->hasUnparsedDefaultArg()) { - CachedTokens *Toks = chunk.Fun.Params[argIdx].DefaultArgTokens; + std::unique_ptr<CachedTokens> Toks = + std::move(chunk.Fun.Params[argIdx].DefaultArgTokens); SourceRange SR; if (Toks->size() > 1) SR = SourceRange((*Toks)[1].getLocation(), @@ -403,8 +405,6 @@ void Sema::CheckExtraCXXDefaultArguments(Declarator &D) { SR = UnparsedDefaultArgLocs[Param]; Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) << SR; - delete Toks; - chunk.Fun.Params[argIdx].DefaultArgTokens = nullptr; } else if (Param->getDefaultArg()) { Diag(Param->getLocation(), diag::err_param_default_argument_nonfunc) << Param->getDefaultArg()->getSourceRange(); @@ -658,12 +658,773 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, Invalid = true; } - if (CheckEquivalentExceptionSpec(Old, New)) - Invalid = true; - return Invalid; } +NamedDecl * +Sema::ActOnDecompositionDeclarator(Scope *S, Declarator &D, + MultiTemplateParamsArg TemplateParamLists) { + assert(D.isDecompositionDeclarator()); + const DecompositionDeclarator &Decomp = D.getDecompositionDeclarator(); + + // The syntax only allows a decomposition declarator as a simple-declaration + // or a for-range-declaration, but we parse it in more cases than that. + if (!D.mayHaveDecompositionDeclarator()) { + Diag(Decomp.getLSquareLoc(), diag::err_decomp_decl_context) + << Decomp.getSourceRange(); + return nullptr; + } + + if (!TemplateParamLists.empty()) { + // FIXME: There's no rule against this, but there are also no rules that + // would actually make it usable, so we reject it for now. + Diag(TemplateParamLists.front()->getTemplateLoc(), + diag::err_decomp_decl_template); + return nullptr; + } + + Diag(Decomp.getLSquareLoc(), getLangOpts().CPlusPlus1z + ? diag::warn_cxx14_compat_decomp_decl + : diag::ext_decomp_decl) + << Decomp.getSourceRange(); + + // The semantic context is always just the current context. + DeclContext *const DC = CurContext; + + // C++1z [dcl.dcl]/8: + // The decl-specifier-seq shall contain only the type-specifier auto + // and cv-qualifiers. + auto &DS = D.getDeclSpec(); + { + SmallVector<StringRef, 8> BadSpecifiers; + SmallVector<SourceLocation, 8> BadSpecifierLocs; + if (auto SCS = DS.getStorageClassSpec()) { + BadSpecifiers.push_back(DeclSpec::getSpecifierName(SCS)); + BadSpecifierLocs.push_back(DS.getStorageClassSpecLoc()); + } + if (auto TSCS = DS.getThreadStorageClassSpec()) { + BadSpecifiers.push_back(DeclSpec::getSpecifierName(TSCS)); + BadSpecifierLocs.push_back(DS.getThreadStorageClassSpecLoc()); + } + if (DS.isConstexprSpecified()) { + BadSpecifiers.push_back("constexpr"); + BadSpecifierLocs.push_back(DS.getConstexprSpecLoc()); + } + if (DS.isInlineSpecified()) { + BadSpecifiers.push_back("inline"); + BadSpecifierLocs.push_back(DS.getInlineSpecLoc()); + } + if (!BadSpecifiers.empty()) { + auto &&Err = Diag(BadSpecifierLocs.front(), diag::err_decomp_decl_spec); + Err << (int)BadSpecifiers.size() + << llvm::join(BadSpecifiers.begin(), BadSpecifiers.end(), " "); + // Don't add FixItHints to remove the specifiers; we do still respect + // them when building the underlying variable. + for (auto Loc : BadSpecifierLocs) + Err << SourceRange(Loc, Loc); + } + // We can't recover from it being declared as a typedef. + if (DS.getStorageClassSpec() == DeclSpec::SCS_typedef) + return nullptr; + } + + TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); + QualType R = TInfo->getType(); + + if (DiagnoseUnexpandedParameterPack(D.getIdentifierLoc(), TInfo, + UPPC_DeclarationType)) + D.setInvalidType(); + + // The syntax only allows a single ref-qualifier prior to the decomposition + // declarator. No other declarator chunks are permitted. Also check the type + // specifier here. + if (DS.getTypeSpecType() != DeclSpec::TST_auto || + D.hasGroupingParens() || D.getNumTypeObjects() > 1 || + (D.getNumTypeObjects() == 1 && + D.getTypeObject(0).Kind != DeclaratorChunk::Reference)) { + Diag(Decomp.getLSquareLoc(), + (D.hasGroupingParens() || + (D.getNumTypeObjects() && + D.getTypeObject(0).Kind == DeclaratorChunk::Paren)) + ? diag::err_decomp_decl_parens + : diag::err_decomp_decl_type) + << R; + + // In most cases, there's no actual problem with an explicitly-specified + // type, but a function type won't work here, and ActOnVariableDeclarator + // shouldn't be called for such a type. + if (R->isFunctionType()) + D.setInvalidType(); + } + + // Build the BindingDecls. + SmallVector<BindingDecl*, 8> Bindings; + + // Build the BindingDecls. + for (auto &B : D.getDecompositionDeclarator().bindings()) { + // Check for name conflicts. + DeclarationNameInfo NameInfo(B.Name, B.NameLoc); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, + ForRedeclaration); + LookupName(Previous, S, + /*CreateBuiltins*/DC->getRedeclContext()->isTranslationUnit()); + + // It's not permitted to shadow a template parameter name. + if (Previous.isSingleResult() && + Previous.getFoundDecl()->isTemplateParameter()) { + DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), + Previous.getFoundDecl()); + Previous.clear(); + } + + bool ConsiderLinkage = DC->isFunctionOrMethod() && + DS.getStorageClassSpec() == DeclSpec::SCS_extern; + FilterLookupForScope(Previous, DC, S, ConsiderLinkage, + /*AllowInlineNamespace*/false); + if (!Previous.empty()) { + auto *Old = Previous.getRepresentativeDecl(); + Diag(B.NameLoc, diag::err_redefinition) << B.Name; + Diag(Old->getLocation(), diag::note_previous_definition); + } + + auto *BD = BindingDecl::Create(Context, DC, B.NameLoc, B.Name); + PushOnScopeChains(BD, S, true); + Bindings.push_back(BD); + ParsingInitForAutoVars.insert(BD); + } + + // There are no prior lookup results for the variable itself, because it + // is unnamed. + DeclarationNameInfo NameInfo((IdentifierInfo *)nullptr, + Decomp.getLSquareLoc()); + LookupResult Previous(*this, NameInfo, LookupOrdinaryName, ForRedeclaration); + + // Build the variable that holds the non-decomposed object. + bool AddToScope = true; + NamedDecl *New = + ActOnVariableDeclarator(S, D, DC, TInfo, Previous, + MultiTemplateParamsArg(), AddToScope, Bindings); + CurContext->addHiddenDecl(New); + + if (isInOpenMPDeclareTargetContext()) + checkDeclIsAllowedInOpenMPTarget(nullptr, New); + + return New; +} + +static bool checkSimpleDecomposition( + Sema &S, ArrayRef<BindingDecl *> Bindings, ValueDecl *Src, + QualType DecompType, const llvm::APSInt &NumElems, QualType ElemType, + llvm::function_ref<ExprResult(SourceLocation, Expr *, unsigned)> GetInit) { + if ((int64_t)Bindings.size() != NumElems) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << NumElems.toString(10) + << (NumElems < Bindings.size()); + return true; + } + + unsigned I = 0; + for (auto *B : Bindings) { + SourceLocation Loc = B->getLocation(); + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + E = GetInit(Loc, E.get(), I++); + if (E.isInvalid()) + return true; + B->setBinding(ElemType, E.get()); + } + + return false; +} + +static bool checkArrayLikeDecomposition(Sema &S, + ArrayRef<BindingDecl *> Bindings, + ValueDecl *Src, QualType DecompType, + const llvm::APSInt &NumElems, + QualType ElemType) { + return checkSimpleDecomposition( + S, Bindings, Src, DecompType, NumElems, ElemType, + [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult { + ExprResult E = S.ActOnIntegerConstant(Loc, I); + if (E.isInvalid()) + return ExprError(); + return S.CreateBuiltinArraySubscriptExpr(Base, Loc, E.get(), Loc); + }); +} + +static bool checkArrayDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, + ValueDecl *Src, QualType DecompType, + const ConstantArrayType *CAT) { + return checkArrayLikeDecomposition(S, Bindings, Src, DecompType, + llvm::APSInt(CAT->getSize()), + CAT->getElementType()); +} + +static bool checkVectorDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, + ValueDecl *Src, QualType DecompType, + const VectorType *VT) { + return checkArrayLikeDecomposition( + S, Bindings, Src, DecompType, llvm::APSInt::get(VT->getNumElements()), + S.Context.getQualifiedType(VT->getElementType(), + DecompType.getQualifiers())); +} + +static bool checkComplexDecomposition(Sema &S, + ArrayRef<BindingDecl *> Bindings, + ValueDecl *Src, QualType DecompType, + const ComplexType *CT) { + return checkSimpleDecomposition( + S, Bindings, Src, DecompType, llvm::APSInt::get(2), + S.Context.getQualifiedType(CT->getElementType(), + DecompType.getQualifiers()), + [&](SourceLocation Loc, Expr *Base, unsigned I) -> ExprResult { + return S.CreateBuiltinUnaryOp(Loc, I ? UO_Imag : UO_Real, Base); + }); +} + +static std::string printTemplateArgs(const PrintingPolicy &PrintingPolicy, + TemplateArgumentListInfo &Args) { + SmallString<128> SS; + llvm::raw_svector_ostream OS(SS); + bool First = true; + for (auto &Arg : Args.arguments()) { + if (!First) + OS << ", "; + Arg.getArgument().print(PrintingPolicy, OS); + First = false; + } + return OS.str(); +} + +static bool lookupStdTypeTraitMember(Sema &S, LookupResult &TraitMemberLookup, + SourceLocation Loc, StringRef Trait, + TemplateArgumentListInfo &Args, + unsigned DiagID) { + auto DiagnoseMissing = [&] { + if (DiagID) + S.Diag(Loc, DiagID) << printTemplateArgs(S.Context.getPrintingPolicy(), + Args); + return true; + }; + + // FIXME: Factor out duplication with lookupPromiseType in SemaCoroutine. + NamespaceDecl *Std = S.getStdNamespace(); + if (!Std) + return DiagnoseMissing(); + + // Look up the trait itself, within namespace std. We can diagnose various + // problems with this lookup even if we've been asked to not diagnose a + // missing specialization, because this can only fail if the user has been + // declaring their own names in namespace std or we don't support the + // standard library implementation in use. + LookupResult Result(S, &S.PP.getIdentifierTable().get(Trait), + Loc, Sema::LookupOrdinaryName); + if (!S.LookupQualifiedName(Result, Std)) + return DiagnoseMissing(); + if (Result.isAmbiguous()) + return true; + + ClassTemplateDecl *TraitTD = Result.getAsSingle<ClassTemplateDecl>(); + if (!TraitTD) { + Result.suppressDiagnostics(); + NamedDecl *Found = *Result.begin(); + S.Diag(Loc, diag::err_std_type_trait_not_class_template) << Trait; + S.Diag(Found->getLocation(), diag::note_declared_at); + return true; + } + + // Build the template-id. + QualType TraitTy = S.CheckTemplateIdType(TemplateName(TraitTD), Loc, Args); + if (TraitTy.isNull()) + return true; + if (!S.isCompleteType(Loc, TraitTy)) { + if (DiagID) + S.RequireCompleteType( + Loc, TraitTy, DiagID, + printTemplateArgs(S.Context.getPrintingPolicy(), Args)); + return true; + } + + CXXRecordDecl *RD = TraitTy->getAsCXXRecordDecl(); + assert(RD && "specialization of class template is not a class?"); + + // Look up the member of the trait type. + S.LookupQualifiedName(TraitMemberLookup, RD); + return TraitMemberLookup.isAmbiguous(); +} + +static TemplateArgumentLoc +getTrivialIntegralTemplateArgument(Sema &S, SourceLocation Loc, QualType T, + uint64_t I) { + TemplateArgument Arg(S.Context, S.Context.MakeIntValue(I, T), T); + return S.getTrivialTemplateArgumentLoc(Arg, T, Loc); +} + +static TemplateArgumentLoc +getTrivialTypeTemplateArgument(Sema &S, SourceLocation Loc, QualType T) { + return S.getTrivialTemplateArgumentLoc(TemplateArgument(T), QualType(), Loc); +} + +namespace { enum class IsTupleLike { TupleLike, NotTupleLike, Error }; } + +static IsTupleLike isTupleLike(Sema &S, SourceLocation Loc, QualType T, + llvm::APSInt &Size) { + EnterExpressionEvaluationContext ContextRAII(S, Sema::ConstantEvaluated); + + DeclarationName Value = S.PP.getIdentifierInfo("value"); + LookupResult R(S, Value, Loc, Sema::LookupOrdinaryName); + + // Form template argument list for tuple_size<T>. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); + + // If there's no tuple_size specialization, it's not tuple-like. + if (lookupStdTypeTraitMember(S, R, Loc, "tuple_size", Args, /*DiagID*/0)) + return IsTupleLike::NotTupleLike; + + // If we get this far, we've committed to the tuple interpretation, but + // we can still fail if there actually isn't a usable ::value. + + struct ICEDiagnoser : Sema::VerifyICEDiagnoser { + LookupResult &R; + TemplateArgumentListInfo &Args; + ICEDiagnoser(LookupResult &R, TemplateArgumentListInfo &Args) + : R(R), Args(Args) {} + void diagnoseNotICE(Sema &S, SourceLocation Loc, SourceRange SR) { + S.Diag(Loc, diag::err_decomp_decl_std_tuple_size_not_constant) + << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + } + } Diagnoser(R, Args); + + if (R.empty()) { + Diagnoser.diagnoseNotICE(S, Loc, SourceRange()); + return IsTupleLike::Error; + } + + ExprResult E = + S.BuildDeclarationNameExpr(CXXScopeSpec(), R, /*NeedsADL*/false); + if (E.isInvalid()) + return IsTupleLike::Error; + + E = S.VerifyIntegerConstantExpression(E.get(), &Size, Diagnoser, false); + if (E.isInvalid()) + return IsTupleLike::Error; + + return IsTupleLike::TupleLike; +} + +/// \return std::tuple_element<I, T>::type. +static QualType getTupleLikeElementType(Sema &S, SourceLocation Loc, + unsigned I, QualType T) { + // Form template argument list for tuple_element<I, T>. + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument( + getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I)); + Args.addArgument(getTrivialTypeTemplateArgument(S, Loc, T)); + + DeclarationName TypeDN = S.PP.getIdentifierInfo("type"); + LookupResult R(S, TypeDN, Loc, Sema::LookupOrdinaryName); + if (lookupStdTypeTraitMember( + S, R, Loc, "tuple_element", Args, + diag::err_decomp_decl_std_tuple_element_not_specialized)) + return QualType(); + + auto *TD = R.getAsSingle<TypeDecl>(); + if (!TD) { + R.suppressDiagnostics(); + S.Diag(Loc, diag::err_decomp_decl_std_tuple_element_not_specialized) + << printTemplateArgs(S.Context.getPrintingPolicy(), Args); + if (!R.empty()) + S.Diag(R.getRepresentativeDecl()->getLocation(), diag::note_declared_at); + return QualType(); + } + + return S.Context.getTypeDeclType(TD); +} + +namespace { +struct BindingDiagnosticTrap { + 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; + } +}; +} + +static bool checkTupleLikeDecomposition(Sema &S, + ArrayRef<BindingDecl *> Bindings, + VarDecl *Src, QualType DecompType, + const llvm::APSInt &TupleSize) { + if ((int64_t)Bindings.size() != TupleSize) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << TupleSize.toString(10) + << (TupleSize < Bindings.size()); + return true; + } + + if (Bindings.empty()) + return false; + + DeclarationName GetDN = S.PP.getIdentifierInfo("get"); + + // [dcl.decomp]p3: + // The unqualified-id get is looked up in the scope of E by class member + // access lookup + LookupResult MemberGet(S, GetDN, Src->getLocation(), Sema::LookupMemberName); + bool UseMemberGet = false; + if (S.isCompleteType(Src->getLocation(), DecompType)) { + if (auto *RD = DecompType->getAsCXXRecordDecl()) + S.LookupQualifiedName(MemberGet, RD); + if (MemberGet.isAmbiguous()) + return true; + UseMemberGet = !MemberGet.empty(); + S.FilterAcceptableTemplateNames(MemberGet); + } + + unsigned I = 0; + for (auto *B : Bindings) { + BindingDiagnosticTrap Trap(S, B); + SourceLocation Loc = B->getLocation(); + + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + + // e is an lvalue if the type of the entity is an lvalue reference and + // an xvalue otherwise + if (!Src->getType()->isLValueReferenceType()) + E = ImplicitCastExpr::Create(S.Context, E.get()->getType(), CK_NoOp, + E.get(), nullptr, VK_XValue); + + TemplateArgumentListInfo Args(Loc, Loc); + Args.addArgument( + getTrivialIntegralTemplateArgument(S, Loc, S.Context.getSizeType(), I)); + + if (UseMemberGet) { + // if [lookup of member get] finds at least one declaration, the + // initializer is e.get<i-1>(). + E = S.BuildMemberReferenceExpr(E.get(), DecompType, Loc, false, + CXXScopeSpec(), SourceLocation(), nullptr, + MemberGet, &Args, nullptr); + if (E.isInvalid()) + return true; + + E = S.ActOnCallExpr(nullptr, E.get(), Loc, None, Loc); + } else { + // Otherwise, the initializer is get<i-1>(e), where get is looked up + // in the associated namespaces. + Expr *Get = UnresolvedLookupExpr::Create( + S.Context, nullptr, NestedNameSpecifierLoc(), SourceLocation(), + DeclarationNameInfo(GetDN, Loc), /*RequiresADL*/true, &Args, + UnresolvedSetIterator(), UnresolvedSetIterator()); + + Expr *Arg = E.get(); + E = S.ActOnCallExpr(nullptr, Get, Loc, Arg, Loc); + } + if (E.isInvalid()) + return true; + Expr *Init = E.get(); + + // Given the type T designated by std::tuple_element<i - 1, E>::type, + QualType T = getTupleLikeElementType(S, Loc, I, DecompType); + if (T.isNull()) + return true; + + // each vi is a variable of type "reference to T" initialized with the + // initializer, where the reference is an lvalue reference if the + // initializer is an lvalue and an rvalue reference otherwise + QualType RefType = + S.BuildReferenceType(T, E.get()->isLValue(), Loc, B->getDeclName()); + if (RefType.isNull()) + return true; + auto *RefVD = VarDecl::Create( + S.Context, Src->getDeclContext(), Loc, Loc, + B->getDeclName().getAsIdentifierInfo(), RefType, + S.Context.getTrivialTypeSourceInfo(T, Loc), Src->getStorageClass()); + RefVD->setLexicalDeclContext(Src->getLexicalDeclContext()); + RefVD->setTSCSpec(Src->getTSCSpec()); + RefVD->setImplicit(); + if (Src->isInlineSpecified()) + RefVD->setInlineSpecified(); + RefVD->getLexicalDeclContext()->addHiddenDecl(RefVD); + + InitializedEntity Entity = InitializedEntity::InitializeBinding(RefVD); + InitializationKind Kind = InitializationKind::CreateCopy(Loc, Loc); + InitializationSequence Seq(S, Entity, Kind, Init); + E = Seq.Perform(S, Entity, Kind, Init); + if (E.isInvalid()) + return true; + E = S.ActOnFinishFullExpr(E.get(), Loc); + if (E.isInvalid()) + return true; + RefVD->setInit(E.get()); + RefVD->checkInitIsICE(); + + E = S.BuildDeclarationNameExpr(CXXScopeSpec(), + DeclarationNameInfo(B->getDeclName(), Loc), + RefVD); + if (E.isInvalid()) + return true; + + B->setBinding(T, E.get()); + I++; + } + + return false; +} + +/// Find the base class to decompose in a built-in decomposition of a class type. +/// This base class search is, unfortunately, not quite like any other that we +/// perform anywhere else in C++. +static const CXXRecordDecl *findDecomposableBaseClass(Sema &S, + SourceLocation Loc, + const CXXRecordDecl *RD, + CXXCastPath &BasePath) { + auto BaseHasFields = [](const CXXBaseSpecifier *Specifier, + CXXBasePath &Path) { + return Specifier->getType()->getAsCXXRecordDecl()->hasDirectFields(); + }; + + const CXXRecordDecl *ClassWithFields = nullptr; + if (RD->hasDirectFields()) + // [dcl.decomp]p4: + // Otherwise, all of E's non-static data members shall be public direct + // members of E ... + ClassWithFields = RD; + else { + // ... or of ... + CXXBasePaths Paths; + Paths.setOrigin(const_cast<CXXRecordDecl*>(RD)); + if (!RD->lookupInBases(BaseHasFields, Paths)) { + // If no classes have fields, just decompose RD itself. (This will work + // if and only if zero bindings were provided.) + return RD; + } + + CXXBasePath *BestPath = nullptr; + for (auto &P : Paths) { + if (!BestPath) + BestPath = &P; + else if (!S.Context.hasSameType(P.back().Base->getType(), + BestPath->back().Base->getType())) { + // ... the same ... + S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members) + << false << RD << BestPath->back().Base->getType() + << P.back().Base->getType(); + return nullptr; + } else if (P.Access < BestPath->Access) { + BestPath = &P; + } + } + + // ... unambiguous ... + QualType BaseType = BestPath->back().Base->getType(); + if (Paths.isAmbiguous(S.Context.getCanonicalType(BaseType))) { + S.Diag(Loc, diag::err_decomp_decl_ambiguous_base) + << RD << BaseType << S.getAmbiguousPathsDisplayString(Paths); + return nullptr; + } + + // ... public base class of E. + if (BestPath->Access != AS_public) { + S.Diag(Loc, diag::err_decomp_decl_non_public_base) + << RD << BaseType; + for (auto &BS : *BestPath) { + if (BS.Base->getAccessSpecifier() != AS_public) { + S.Diag(BS.Base->getLocStart(), diag::note_access_constrained_by_path) + << (BS.Base->getAccessSpecifier() == AS_protected) + << (BS.Base->getAccessSpecifierAsWritten() == AS_none); + break; + } + } + return nullptr; + } + + ClassWithFields = BaseType->getAsCXXRecordDecl(); + S.BuildBasePathArray(Paths, BasePath); + } + + // The above search did not check whether the selected class itself has base + // classes with fields, so check that now. + CXXBasePaths Paths; + if (ClassWithFields->lookupInBases(BaseHasFields, Paths)) { + S.Diag(Loc, diag::err_decomp_decl_multiple_bases_with_members) + << (ClassWithFields == RD) << RD << ClassWithFields + << Paths.front().back().Base->getType(); + return nullptr; + } + + return ClassWithFields; +} + +static bool checkMemberDecomposition(Sema &S, ArrayRef<BindingDecl*> Bindings, + ValueDecl *Src, QualType DecompType, + const CXXRecordDecl *RD) { + CXXCastPath BasePath; + RD = findDecomposableBaseClass(S, Src->getLocation(), RD, BasePath); + if (!RD) + return true; + QualType BaseType = S.Context.getQualifiedType(S.Context.getRecordType(RD), + DecompType.getQualifiers()); + + auto DiagnoseBadNumberOfBindings = [&]() -> bool { + unsigned NumFields = + std::count_if(RD->field_begin(), RD->field_end(), + [](FieldDecl *FD) { return !FD->isUnnamedBitfield(); }); + assert(Bindings.size() != NumFields); + S.Diag(Src->getLocation(), diag::err_decomp_decl_wrong_number_bindings) + << DecompType << (unsigned)Bindings.size() << NumFields + << (NumFields < Bindings.size()); + return true; + }; + + // all of E's non-static data members shall be public [...] members, + // E shall not have an anonymous union member, ... + unsigned I = 0; + for (auto *FD : RD->fields()) { + if (FD->isUnnamedBitfield()) + continue; + + if (FD->isAnonymousStructOrUnion()) { + S.Diag(Src->getLocation(), diag::err_decomp_decl_anon_union_member) + << DecompType << FD->getType()->isUnionType(); + S.Diag(FD->getLocation(), diag::note_declared_at); + return true; + } + + // We have a real field to bind. + if (I >= Bindings.size()) + return DiagnoseBadNumberOfBindings(); + auto *B = Bindings[I++]; + + SourceLocation Loc = B->getLocation(); + if (FD->getAccess() != AS_public) { + S.Diag(Loc, diag::err_decomp_decl_non_public_member) << FD << DecompType; + + // Determine whether the access specifier was explicit. + bool Implicit = true; + for (const auto *D : RD->decls()) { + if (declaresSameEntity(D, FD)) + break; + if (isa<AccessSpecDecl>(D)) { + Implicit = false; + break; + } + } + + S.Diag(FD->getLocation(), diag::note_access_natural) + << (FD->getAccess() == AS_protected) << Implicit; + return true; + } + + // Initialize the binding to Src.FD. + ExprResult E = S.BuildDeclRefExpr(Src, DecompType, VK_LValue, Loc); + if (E.isInvalid()) + return true; + E = S.ImpCastExprToType(E.get(), BaseType, CK_UncheckedDerivedToBase, + VK_LValue, &BasePath); + if (E.isInvalid()) + return true; + E = S.BuildFieldReferenceExpr(E.get(), /*IsArrow*/ false, Loc, + CXXScopeSpec(), FD, + DeclAccessPair::make(FD, FD->getAccess()), + DeclarationNameInfo(FD->getDeclName(), Loc)); + if (E.isInvalid()) + return true; + + // If the type of the member is T, the referenced type is cv T, where cv is + // the cv-qualification of the decomposition expression. + // + // FIXME: We resolve a defect here: if the field is mutable, we do not add + // 'const' to the type of the field. + Qualifiers Q = DecompType.getQualifiers(); + if (FD->isMutable()) + Q.removeConst(); + B->setBinding(S.BuildQualifiedType(FD->getType(), Loc, Q), E.get()); + } + + if (I != Bindings.size()) + return DiagnoseBadNumberOfBindings(); + + return false; +} + +void Sema::CheckCompleteDecompositionDeclaration(DecompositionDecl *DD) { + QualType DecompType = DD->getType(); + + // If the type of the decomposition is dependent, then so is the type of + // each binding. + if (DecompType->isDependentType()) { + for (auto *B : DD->bindings()) + B->setType(Context.DependentTy); + return; + } + + DecompType = DecompType.getNonReferenceType(); + ArrayRef<BindingDecl*> Bindings = DD->bindings(); + + // C++1z [dcl.decomp]/2: + // If E is an array type [...] + // As an extension, we also support decomposition of built-in complex and + // vector types. + if (auto *CAT = Context.getAsConstantArrayType(DecompType)) { + if (checkArrayDecomposition(*this, Bindings, DD, DecompType, CAT)) + DD->setInvalidDecl(); + return; + } + if (auto *VT = DecompType->getAs<VectorType>()) { + if (checkVectorDecomposition(*this, Bindings, DD, DecompType, VT)) + DD->setInvalidDecl(); + return; + } + if (auto *CT = DecompType->getAs<ComplexType>()) { + if (checkComplexDecomposition(*this, Bindings, DD, DecompType, CT)) + DD->setInvalidDecl(); + return; + } + + // C++1z [dcl.decomp]/3: + // if the expression std::tuple_size<E>::value is a well-formed integral + // constant expression, [...] + llvm::APSInt TupleSize(32); + switch (isTupleLike(*this, DD->getLocation(), DecompType, TupleSize)) { + case IsTupleLike::Error: + DD->setInvalidDecl(); + return; + + case IsTupleLike::TupleLike: + if (checkTupleLikeDecomposition(*this, Bindings, DD, DecompType, TupleSize)) + DD->setInvalidDecl(); + return; + + case IsTupleLike::NotTupleLike: + break; + } + + // C++1z [dcl.dcl]/8: + // [E shall be of array or non-union class type] + CXXRecordDecl *RD = DecompType->getAsCXXRecordDecl(); + if (!RD || RD->isUnion()) { + Diag(DD->getLocation(), diag::err_decomp_decl_unbindable_type) + << DD << !RD << DecompType; + DD->setInvalidDecl(); + return; + } + + // C++1z [dcl.decomp]/4: + // all of E's non-static data members shall be [...] direct members of + // E or of the same unambiguous public base class of E, ... + if (checkMemberDecomposition(*this, Bindings, DD, DecompType, RD)) + DD->setInvalidDecl(); +} + /// \brief Merge the exception specifications of two variable declarations. /// /// This is called when there's a redeclaration of a VarDecl. The function @@ -912,7 +1673,8 @@ static bool CheckConstexprDeclStmt(Sema &SemaRef, const FunctionDecl *Dcl, // C++11 and permitted in C++1y, so ignore them. continue; - case Decl::Var: { + case Decl::Var: + case Decl::Decomposition: { // C++1y [dcl.constexpr]p3 allows anything except: // a definition of a variable of non-literal type or of static or // thread storage duration or for which no initialization is performed. @@ -2192,7 +2954,8 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D, } else { Member = HandleField(S, cast<CXXRecordDecl>(CurContext), Loc, D, BitWidth, InitStyle, AS); - assert(Member && "HandleField never returns null"); + if (!Member) + return nullptr; } } else { Member = HandleDeclarator(S, D, TemplateParameterLists); @@ -3483,98 +4246,30 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, CtorArg = CastForMoving(SemaRef, CtorArg.get()); } - // When the field we are copying is an array, create index variables for - // each dimension of the array. We use these index variables to subscript - // the source array, and other clients (e.g., CodeGen) will perform the - // necessary iteration with these index variables. - SmallVector<VarDecl *, 4> IndexVariables; - QualType BaseType = Field->getType(); - QualType SizeType = SemaRef.Context.getSizeType(); - bool InitializingArray = false; - while (const ConstantArrayType *Array - = SemaRef.Context.getAsConstantArrayType(BaseType)) { - InitializingArray = true; - // Create the iteration variable for this array index. - IdentifierInfo *IterationVarName = nullptr; - { - SmallString<8> Str; - llvm::raw_svector_ostream OS(Str); - OS << "__i" << IndexVariables.size(); - IterationVarName = &SemaRef.Context.Idents.get(OS.str()); - } - VarDecl *IterationVar - = VarDecl::Create(SemaRef.Context, SemaRef.CurContext, Loc, Loc, - IterationVarName, SizeType, - SemaRef.Context.getTrivialTypeSourceInfo(SizeType, Loc), - SC_None); - IndexVariables.push_back(IterationVar); - - // Create a reference to the iteration variable. - ExprResult IterationVarRef - = SemaRef.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); - assert(!IterationVarRef.isInvalid() && - "Reference to invented variable cannot fail!"); - IterationVarRef = SemaRef.DefaultLvalueConversion(IterationVarRef.get()); - assert(!IterationVarRef.isInvalid() && - "Conversion of invented variable cannot fail!"); - - // Subscript the array with this iteration variable. - CtorArg = SemaRef.CreateBuiltinArraySubscriptExpr(CtorArg.get(), Loc, - IterationVarRef.get(), - Loc); - if (CtorArg.isInvalid()) - return true; + InitializedEntity Entity = + Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr, + /*Implicit*/ true) + : InitializedEntity::InitializeMember(Field, nullptr, + /*Implicit*/ true); - BaseType = Array->getElementType(); - } - - // The array subscript expression is an lvalue, which is wrong for moving. - if (Moving && InitializingArray) - CtorArg = CastForMoving(SemaRef, CtorArg.get()); - - // Construct the entity that we will be initializing. For an array, this - // will be first element in the array, which may require several levels - // of array-subscript entities. - SmallVector<InitializedEntity, 4> Entities; - Entities.reserve(1 + IndexVariables.size()); - if (Indirect) - Entities.push_back(InitializedEntity::InitializeMember(Indirect)); - else - Entities.push_back(InitializedEntity::InitializeMember(Field)); - for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) - Entities.push_back(InitializedEntity::InitializeElement(SemaRef.Context, - 0, - Entities.back())); - // Direct-initialize to use the copy constructor. InitializationKind InitKind = InitializationKind::CreateDirect(Loc, SourceLocation(), SourceLocation()); Expr *CtorArgE = CtorArg.getAs<Expr>(); - InitializationSequence InitSeq(SemaRef, Entities.back(), InitKind, - CtorArgE); - - ExprResult MemberInit - = InitSeq.Perform(SemaRef, Entities.back(), InitKind, - MultiExprArg(&CtorArgE, 1)); + InitializationSequence InitSeq(SemaRef, Entity, InitKind, CtorArgE); + ExprResult MemberInit = + InitSeq.Perform(SemaRef, Entity, InitKind, MultiExprArg(&CtorArgE, 1)); MemberInit = SemaRef.MaybeCreateExprWithCleanups(MemberInit); if (MemberInit.isInvalid()) return true; - if (Indirect) { - assert(IndexVariables.size() == 0 && - "Indirect field improperly initialized"); - CXXMemberInit - = new (SemaRef.Context) CXXCtorInitializer(SemaRef.Context, Indirect, - Loc, Loc, - MemberInit.getAs<Expr>(), - Loc); - } else - CXXMemberInit = CXXCtorInitializer::Create(SemaRef.Context, Field, Loc, - Loc, MemberInit.getAs<Expr>(), - Loc, - IndexVariables.data(), - IndexVariables.size()); + if (Indirect) + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer( + SemaRef.Context, Indirect, Loc, Loc, MemberInit.getAs<Expr>(), Loc); + else + CXXMemberInit = new (SemaRef.Context) CXXCtorInitializer( + SemaRef.Context, Field, Loc, Loc, MemberInit.getAs<Expr>(), Loc); return false; } @@ -3585,9 +4280,11 @@ BuildImplicitMemberInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, SemaRef.Context.getBaseElementType(Field->getType()); if (FieldBaseElementType->isRecordType()) { - InitializedEntity InitEntity - = Indirect? InitializedEntity::InitializeMember(Indirect) - : InitializedEntity::InitializeMember(Field); + InitializedEntity InitEntity = + Indirect ? InitializedEntity::InitializeMember(Indirect, nullptr, + /*Implicit*/ true) + : InitializedEntity::InitializeMember(Field, nullptr, + /*Implicit*/ true); InitializationKind InitKind = InitializationKind::CreateDefault(Loc); @@ -4778,7 +5475,8 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (MD->isInlined()) { // MinGW does not import or export inline methods. - if (!Context.getTargetInfo().getCXXABI().isMicrosoft()) + if (!Context.getTargetInfo().getCXXABI().isMicrosoft() && + !Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment()) continue; // MSVC versions before 2015 don't export the move assignment operators @@ -5333,7 +6031,8 @@ void Sema::EvaluateImplicitExceptionSpec(SourceLocation Loc, CXXMethodDecl *MD) return; // Evaluate the exception specification. - auto ESI = computeImplicitExceptionSpec(*this, Loc, MD).getExceptionSpec(); + auto IES = computeImplicitExceptionSpec(*this, Loc, MD); + auto ESI = IES.getExceptionSpec(); // Update the type of the special member to use it. UpdateExceptionSpec(MD, ESI); @@ -5531,8 +6230,8 @@ void Sema::CheckExplicitlyDefaultedMemberExceptionSpec( CallingConv CC = Context.getDefaultCallingConvention(/*IsVariadic=*/false, /*IsCXXMethod=*/true); FunctionProtoType::ExtProtoInfo EPI(CC); - EPI.ExceptionSpec = computeImplicitExceptionSpec(*this, MD->getLocation(), MD) - .getExceptionSpec(); + auto IES = computeImplicitExceptionSpec(*this, MD->getLocation(), MD); + EPI.ExceptionSpec = IES.getExceptionSpec(); const FunctionProtoType *ImplicitType = cast<FunctionProtoType>( Context.getFunctionType(Context.VoidTy, None, EPI)); @@ -5889,8 +6588,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { // This is a silly definition, because it gives an empty union a deleted // default constructor. Don't do that. - if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst && - !MD->getParent()->field_empty()) { + if (CSM == Sema::CXXDefaultConstructor && inUnion() && AllFieldsAreConst) { + bool AnyFields = false; + for (auto *F : MD->getParent()->fields()) + if ((AnyFields = !F->isUnnamedBitfield())) + break; + if (!AnyFields) + return false; if (Diagnose) S.Diag(MD->getParent()->getLocation(), diag::note_deleted_default_ctor_all_const) @@ -5939,10 +6643,15 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, (CSM == CXXCopyConstructor || CSM == CXXCopyAssignment)) { CXXMethodDecl *UserDeclaredMove = nullptr; - // In Microsoft mode, a user-declared move only causes the deletion of the - // corresponding copy operation, not both copy operations. + // In Microsoft mode up to MSVC 2013, a user-declared move only causes the + // deletion of the corresponding copy operation, not both copy operations. + // MSVC 2015 has adopted the standards conforming behavior. + bool DeletesOnlyMatchingCopy = + getLangOpts().MSVCCompat && + !getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015); + if (RD->hasUserDeclaredMoveConstructor() && - (!getLangOpts().MSVCCompat || CSM == CXXCopyConstructor)) { + (!DeletesOnlyMatchingCopy || CSM == CXXCopyConstructor)) { if (!Diagnose) return true; // Find any user-declared move constructor. @@ -5954,7 +6663,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, } assert(UserDeclaredMove); } else if (RD->hasUserDeclaredMoveAssignment() && - (!getLangOpts().MSVCCompat || CSM == CXXCopyAssignment)) { + (!DeletesOnlyMatchingCopy || CSM == CXXCopyAssignment)) { if (!Diagnose) return true; // Find any user-declared move assignment operator. @@ -5987,7 +6696,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); if (FindDeallocationFunction(MD->getLocation(), MD->getParent(), Name, - OperatorDelete, false)) { + OperatorDelete, /*Diagnose*/false)) { if (Diagnose) Diag(RD->getLocation(), diag::note_deleted_dtor_no_operator_delete); return true; @@ -5997,13 +6706,14 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose); for (auto &BI : RD->bases()) - if (!BI.isVirtual() && + if ((SMI.IsAssignment || !BI.isVirtual()) && SMI.shouldDeleteForBase(&BI)) return true; // Per DR1611, do not consider virtual bases of constructors of abstract - // classes, since we are not going to construct them. - if (!RD->isAbstract() || !SMI.IsConstructor) { + // classes, since we are not going to construct them. For assignment + // operators, we only assign (and thus only consider) direct bases. + if ((!RD->isAbstract() || !SMI.IsConstructor) && !SMI.IsAssignment) { for (auto &BI : RD->vbases()) if (SMI.shouldDeleteForBase(&BI)) return true; @@ -6618,6 +7328,17 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { 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()) { @@ -6926,19 +7647,11 @@ bool Sema::CheckDestructor(CXXDestructorDecl *Destructor) { Loc = RD->getLocation(); // If we have a virtual destructor, look up the deallocation function - FunctionDecl *OperatorDelete = nullptr; - DeclarationName Name = - Context.DeclarationNames.getCXXOperatorName(OO_Delete); - if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) - return true; - // If there's no class-specific operator delete, look up the global - // non-array delete. - if (!OperatorDelete) - OperatorDelete = FindUsualDeallocationFunction(Loc, true, Name); - - MarkFunctionReferenced(Loc, OperatorDelete); - - Destructor->setOperatorDelete(OperatorDelete); + if (FunctionDecl *OperatorDelete = + FindDeallocationFunctionForDestructor(Loc, RD)) { + MarkFunctionReferenced(Loc, OperatorDelete); + Destructor->setOperatorDelete(OperatorDelete); + } } return false; @@ -7320,7 +8033,7 @@ static void DiagnoseNamespaceInlineMismatch(Sema &S, SourceLocation KeywordLoc, S.Diag(Loc, diag::warn_inline_namespace_reopened_noninline) << FixItHint::CreateInsertion(KeywordLoc, "inline "); else - S.Diag(Loc, diag::err_inline_namespace_mismatch) << *IsInline; + S.Diag(Loc, diag::err_inline_namespace_mismatch); S.Diag(PrevNS->getLocation(), diag::note_previous_definition); *IsInline = PrevNS->isInline(); @@ -7497,11 +8210,29 @@ CXXRecordDecl *Sema::getStdBadAlloc() const { StdBadAlloc.get(Context.getExternalSource())); } +EnumDecl *Sema::getStdAlignValT() const { + return cast_or_null<EnumDecl>(StdAlignValT.get(Context.getExternalSource())); +} + NamespaceDecl *Sema::getStdNamespace() const { return cast_or_null<NamespaceDecl>( StdNamespace.get(Context.getExternalSource())); } +NamespaceDecl *Sema::lookupStdExperimentalNamespace() { + if (!StdExperimentalNamespaceCache) { + if (auto Std = getStdNamespace()) { + LookupResult Result(*this, &PP.getIdentifierTable().get("experimental"), + SourceLocation(), LookupNamespaceName); + if (!LookupQualifiedName(Result, Std) || + !(StdExperimentalNamespaceCache = + Result.getAsSingle<NamespaceDecl>())) + Result.suppressDiagnostics(); + } + } + return StdExperimentalNamespaceCache; +} + /// \brief Retrieve the special "std" namespace, which may require us to /// implicitly define the namespace. NamespaceDecl *Sema::getOrCreateStdNamespace() { @@ -7801,15 +8532,19 @@ void Sema::PushUsingDirective(Scope *S, UsingDirectiveDecl *UDir) { Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, - bool HasUsingKeyword, SourceLocation UsingLoc, + SourceLocation TypenameLoc, CXXScopeSpec &SS, UnqualifiedId &Name, - AttributeList *AttrList, - bool HasTypenameKeyword, - SourceLocation TypenameLoc) { + SourceLocation EllipsisLoc, + AttributeList *AttrList) { assert(S->getFlags() & Scope::DeclScope && "Invalid Scope."); + if (SS.isEmpty()) { + Diag(Name.getLocStart(), diag::err_using_requires_qualname); + return nullptr; + } + switch (Name.getKind()) { case UnqualifiedId::IK_ImplicitSelfParam: case UnqualifiedId::IK_Identifier: @@ -7848,21 +8583,30 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, return nullptr; // Warn about access declarations. - if (!HasUsingKeyword) { + if (UsingLoc.isInvalid()) { Diag(Name.getLocStart(), getLangOpts().CPlusPlus11 ? diag::err_access_decl : diag::warn_access_decl_deprecated) << FixItHint::CreateInsertion(SS.getRange().getBegin(), "using "); } - if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || - DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) - return nullptr; + if (EllipsisLoc.isInvalid()) { + if (DiagnoseUnexpandedParameterPack(SS, UPPC_UsingDeclaration) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC_UsingDeclaration)) + return nullptr; + } else { + if (!SS.getScopeRep()->containsUnexpandedParameterPack() && + !TargetNameInfo.containsUnexpandedParameterPack()) { + Diag(EllipsisLoc, diag::err_pack_expansion_without_parameter_packs) + << SourceRange(SS.getBeginLoc(), TargetNameInfo.getEndLoc()); + EllipsisLoc = SourceLocation(); + } + } - NamedDecl *UD = BuildUsingDeclaration(S, AS, UsingLoc, SS, - TargetNameInfo, AttrList, - /* IsInstantiation */ false, - HasTypenameKeyword, TypenameLoc); + NamedDecl *UD = + BuildUsingDeclaration(S, AS, UsingLoc, TypenameLoc.isValid(), TypenameLoc, + SS, TargetNameInfo, EllipsisLoc, AttrList, + /*IsInstantiation*/false); if (UD) PushOnScopeChains(UD, S, /*AddToContext*/ false); @@ -7925,6 +8669,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, diag::err_using_decl_nested_name_specifier_is_current_class) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); + Using->setInvalidDecl(); return true; } @@ -7934,6 +8679,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, << cast<CXXRecordDecl>(CurContext) << Using->getQualifierLoc().getSourceRange(); Diag(Orig->getLocation(), diag::note_using_decl_target); + Using->setInvalidDecl(); return true; } } @@ -7957,7 +8703,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // We can have UsingDecls in our Previous results because we use the same // LookupResult for checking whether the UsingDecl itself is a valid // redeclaration. - if (isa<UsingDecl>(D)) + if (isa<UsingDecl>(D) || isa<UsingPackDecl>(D)) continue; if (IsEquivalentForUsingDecl(Context, D, Target)) { @@ -8003,6 +8749,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Target->getLocation(), diag::note_using_decl_target); Diag(OldDecl->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8015,6 +8762,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(Tag->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8024,6 +8772,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, Diag(Using->getLocation(), diag::err_using_decl_conflict); Diag(Target->getLocation(), diag::note_using_decl_target); Diag(NonTag->getLocation(), diag::note_using_decl_conflict); + Using->setInvalidDecl(); return true; } @@ -8231,23 +8980,19 @@ private: /// the lookup differently for these declarations. NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, + bool HasTypenameKeyword, + SourceLocation TypenameLoc, CXXScopeSpec &SS, DeclarationNameInfo NameInfo, + SourceLocation EllipsisLoc, AttributeList *AttrList, - bool IsInstantiation, - bool HasTypenameKeyword, - SourceLocation TypenameLoc) { + bool IsInstantiation) { assert(!SS.isInvalid() && "Invalid CXXScopeSpec."); SourceLocation IdentLoc = NameInfo.getLoc(); assert(IdentLoc.isValid() && "Invalid TargetName location."); // FIXME: We ignore attributes for now. - if (SS.isEmpty()) { - Diag(IdentLoc, diag::err_using_requires_qualname); - return nullptr; - } - // For an inheriting constructor declaration, the name of the using // declaration is the name of a constructor in this class, not in the // base class. @@ -8281,8 +9026,23 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, F.done(); } else { assert(IsInstantiation && "no scope in non-instantiation"); - assert(CurContext->isRecord() && "scope not record in instantiation"); - LookupQualifiedName(Previous, CurContext); + if (CurContext->isRecord()) + LookupQualifiedName(Previous, CurContext); + else { + // No redeclaration check is needed here; in non-member contexts we + // diagnosed all possible conflicts with other using-declarations when + // building the template: + // + // For a dependent non-type using declaration, the only valid case is + // if we instantiate to a single enumerator. We check for conflicts + // between shadow declarations we introduce, and we check in the template + // definition for conflicts between a non-type using declaration and any + // other declaration, which together covers all cases. + // + // A dependent typename using declaration will never successfully + // instantiate, since it will always name a class member, so we reject + // that in the template definition. + } } // Check for invalid redeclarations. @@ -8291,22 +9051,24 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return nullptr; // Check for bad qualifiers. - if (CheckUsingDeclQualifier(UsingLoc, SS, NameInfo, IdentLoc)) + if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo, + IdentLoc)) return nullptr; DeclContext *LookupContext = computeDeclContext(SS); NamedDecl *D; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); - if (!LookupContext) { + if (!LookupContext || EllipsisLoc.isValid()) { if (HasTypenameKeyword) { // FIXME: not all declaration name kinds are legal here D = UnresolvedUsingTypenameDecl::Create(Context, CurContext, UsingLoc, TypenameLoc, QualifierLoc, - IdentLoc, NameInfo.getName()); + IdentLoc, NameInfo.getName(), + EllipsisLoc); } else { D = UnresolvedUsingValueDecl::Create(Context, CurContext, UsingLoc, - QualifierLoc, NameInfo); + QualifierLoc, NameInfo, EllipsisLoc); } D->setAccess(AS); CurContext->addDecl(D); @@ -8466,6 +9228,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return UD; } +NamedDecl *Sema::BuildUsingPackDecl(NamedDecl *InstantiatedFrom, + ArrayRef<NamedDecl *> Expansions) { + assert(isa<UnresolvedUsingValueDecl>(InstantiatedFrom) || + isa<UnresolvedUsingTypenameDecl>(InstantiatedFrom) || + isa<UsingPackDecl>(InstantiatedFrom)); + + auto *UPD = + UsingPackDecl::Create(Context, CurContext, InstantiatedFrom, Expansions); + UPD->setAccess(InstantiatedFrom->getAccess()); + CurContext->addDecl(UPD); + return UPD; +} + /// Additional checks for a using declaration referring to a constructor name. bool Sema::CheckInheritingConstructorUsingDecl(UsingDecl *UD) { assert(!UD->hasTypename() && "expecting a constructor name"); @@ -8502,6 +9277,8 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, const CXXScopeSpec &SS, SourceLocation NameLoc, const LookupResult &Prev) { + NestedNameSpecifier *Qual = SS.getScopeRep(); + // C++03 [namespace.udecl]p8: // C++0x [namespace.udecl]p10: // A using-declaration is a declaration and can therefore be used @@ -8509,10 +9286,28 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, // allowed. // // That's in non-member contexts. - if (!CurContext->getRedeclContext()->isRecord()) + if (!CurContext->getRedeclContext()->isRecord()) { + // A dependent qualifier outside a class can only ever resolve to an + // enumeration type. Therefore it conflicts with any other non-type + // declaration in the same scope. + // FIXME: How should we check for dependent type-type conflicts at block + // scope? + if (Qual->isDependent() && !HasTypenameKeyword) { + for (auto *D : Prev) { + if (!isa<TypeDecl>(D) && !isa<UsingDecl>(D) && !isa<UsingPackDecl>(D)) { + bool OldCouldBeEnumerator = + isa<UnresolvedUsingValueDecl>(D) || isa<EnumConstantDecl>(D); + Diag(NameLoc, + OldCouldBeEnumerator ? diag::err_redefinition + : diag::err_redefinition_different_kind) + << Prev.getLookupName(); + Diag(D->getLocation(), diag::note_previous_definition); + return true; + } + } + } return false; - - NestedNameSpecifier *Qual = SS.getScopeRep(); + } for (LookupResult::iterator I = Prev.begin(), E = Prev.end(); I != E; ++I) { NamedDecl *D = *I; @@ -8556,6 +9351,7 @@ bool Sema::CheckUsingDeclRedeclaration(SourceLocation UsingLoc, /// in the current context is appropriately related to the current /// scope. If an error is found, diagnoses it and returns true. bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, + bool HasTypename, const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, SourceLocation NameLoc) { @@ -8566,9 +9362,11 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, // C++0x [namespace.udecl]p8: // A using-declaration for a class member shall be a member-declaration. - // If we weren't able to compute a valid scope, it must be a - // dependent class scope. - if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) { + // If we weren't able to compute a valid scope, it might validly be a + // dependent class scope or a dependent enumeration unscoped scope. If + // we have a 'typename' keyword, the scope must resolve to a class type. + if ((HasTypename && !NamedContext) || + (NamedContext && NamedContext->getRedeclContext()->isRecord())) { auto *RD = NamedContext ? cast<CXXRecordDecl>(NamedContext->getRedeclContext()) : nullptr; @@ -8628,7 +9426,8 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, if (getLangOpts().CPlusPlus11) { // Convert 'using X::Y;' to 'auto &Y = X::Y;'. FixIt = FixItHint::CreateReplacement( - UsingLoc, "constexpr auto " + NameInfo.getName().getAsString() + " = "); + UsingLoc, + "constexpr auto " + NameInfo.getName().getAsString() + " = "); } Diag(UsingLoc, diag::note_using_decl_class_member_workaround) @@ -8638,7 +9437,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } - // Otherwise, everything is known to be fine. + // Otherwise, this might be valid. return false; } @@ -8683,11 +9482,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; } - Diag(SS.getRange().getBegin(), - diag::err_using_decl_nested_name_specifier_is_not_base_class) - << SS.getScopeRep() - << cast<CXXRecordDecl>(CurContext) - << SS.getRange(); + if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) { + Diag(SS.getRange().getBegin(), + diag::err_using_decl_nested_name_specifier_is_not_base_class) + << SS.getScopeRep() + << cast<CXXRecordDecl>(CurContext) + << SS.getRange(); + } return true; } @@ -9493,7 +10294,11 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { Scope *S = getScopeForContext(ClassDecl); CheckImplicitSpecialMemberDeclaration(S, Destructor); - if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) + // We can't check whether an implicit destructor is deleted before we complete + // the definition of the class, because its validity depends on the alignment + // of the class. We'll check this from ActOnFields once the class is complete. + if (ClassDecl->isCompleteDefinition() && + ShouldDeleteSpecialMember(Destructor, CXXDestructor)) SetDeclDeleted(Destructor, ClassLoc); // Introduce this destructor into its scope. @@ -9560,7 +10365,7 @@ void Sema::ActOnFinishCXXMemberDecls() { } } -static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { +static void checkDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { // Don't do anything for template patterns. if (Class->getDescribedClassTemplate()) return; @@ -9574,7 +10379,7 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { if (!CD) { // Recurse on nested classes. if (auto *NestedRD = dyn_cast<CXXRecordDecl>(Member)) - getDefaultArgExprsForConstructors(S, NestedRD); + checkDefaultArgExprsForConstructors(S, NestedRD); continue; } else if (!CD->isDefaultConstructor() || !CD->hasAttr<DLLExportAttr>()) { continue; @@ -9599,14 +10404,9 @@ static void getDefaultArgExprsForConstructors(Sema &S, CXXRecordDecl *Class) { LastExportedDefaultCtor = CD; for (unsigned I = 0; I != NumParams; ++I) { - // Skip any default arguments that we've already instantiated. - if (S.Context.getDefaultArgExprForConstructor(CD, I)) - continue; - - Expr *DefaultArg = S.BuildCXXDefaultArgExpr(Class->getLocation(), CD, - CD->getParamDecl(I)).get(); + (void)S.CheckCXXDefaultArgExpr(Class->getLocation(), CD, + CD->getParamDecl(I)); S.DiscardCleanupsInEvaluationContext(); - S.Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); } } } @@ -9618,7 +10418,7 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { // have default arguments or don't use the standard calling convention are // wrapped with a thunk called the default constructor closure. if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft()) - getDefaultArgExprsForConstructors(*this, RD); + checkDefaultArgExprsForConstructors(*this, RD); referenceDLLExportedClassMethods(); } @@ -11506,6 +12306,8 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) && "given constructor for wrong type"); MarkFunctionReferenced(ConstructLoc, Constructor); + if (getLangOpts().CUDA && !CheckCUDACall(ConstructLoc, Constructor)) + return ExprError(); return CXXConstructExpr::Create( Context, DeclInitType, ConstructLoc, Constructor, Elidable, @@ -11534,13 +12336,20 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // Lookup can return at most two results: the pattern for the field, or the // injected class name of the parent record. No other member can have the // same name as the field. - assert(!Lookup.empty() && Lookup.size() <= 2 && + // In modules mode, lookup can return multiple results (coming from + // different modules). + assert((getLangOpts().Modules || (!Lookup.empty() && Lookup.size() <= 2)) && "more than two lookup results for field name"); FieldDecl *Pattern = dyn_cast<FieldDecl>(Lookup[0]); if (!Pattern) { assert(isa<CXXRecordDecl>(Lookup[0]) && "cannot have other non-field member with same name"); - Pattern = cast<FieldDecl>(Lookup[1]); + for (auto L : Lookup) + if (isa<FieldDecl>(L)) { + Pattern = cast<FieldDecl>(L); + break; + } + assert(Pattern && "We must have set the Pattern!"); } if (InstantiateInClassInitializer(Loc, Field, Pattern, @@ -11564,14 +12373,9 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { // constructor before the initializer is lexically complete will ultimately // come here at which point we can diagnose it. RecordDecl *OutermostClass = ParentRD->getOuterLexicalRecordContext(); - if (OutermostClass == ParentRD) { - Diag(Field->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) - << ParentRD << Field; - } else { - Diag(Field->getLocEnd(), - diag::err_in_class_initializer_not_yet_parsed_outer_class) - << ParentRD << OutermostClass << Field; - } + Diag(Loc, diag::err_in_class_initializer_not_yet_parsed) + << OutermostClass << Field; + Diag(Field->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed); return ExprError(); } @@ -11963,6 +12767,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { if (FnDecl->isExternC()) { Diag(FnDecl->getLocation(), diag::err_literal_operator_extern_c); + if (const LinkageSpecDecl *LSD = + FnDecl->getDeclContext()->getExternCContext()) + Diag(LSD->getExternLoc(), diag::note_extern_c_begins_here); return true; } @@ -12106,7 +12913,7 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // Literal suffix identifiers that do not start with an underscore // are reserved for future standardization. Diag(FnDecl->getLocation(), diag::warn_user_literal_reserved) - << NumericLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); + << StringLiteralParser::isValidUDSuffix(getLangOpts(), LiteralName); } return false; @@ -12997,9 +13804,13 @@ NamedDecl *Sema::ActOnFriendFunctionDecl(Scope *S, Declarator &D, // and shall be the only declaration of the function or function // template in the translation unit. if (functionDeclHasDefaultArgument(FD)) { - if (FunctionDecl *OldFD = FD->getPreviousDecl()) { + // We can't look at FD->getPreviousDecl() because it may not have been set + // if we're in a dependent context. If the function is known to be a + // redeclaration, we will have narrowed Previous down to the right decl. + if (D.isRedeclaration()) { Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_redeclared); - Diag(OldFD->getLocation(), diag::note_previous_declaration); + Diag(Previous.getRepresentativeDecl()->getLocation(), + diag::note_previous_declaration); } else if (!D.isFunctionDefinition()) Diag(FD->getLocation(), diag::err_friend_decl_with_def_arg_must_be_def); } @@ -13052,7 +13863,7 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { // See if we're deleting a function which is already known to override a // non-deleted virtual function. - if (const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { + if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Fn)) { bool IssuedDiagnostic = false; for (CXXMethodDecl::method_iterator I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); @@ -13065,6 +13876,11 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { Diag((*I)->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()) + ShouldDeleteSpecialMember(MD, getSpecialMember(MD), nullptr, + /*Diagnose*/true); } // C++11 [basic.start.main]p3: @@ -13072,6 +13888,9 @@ void Sema::SetDeclDeleted(Decl *Dcl, SourceLocation DelLoc) { if (Fn->isMain()) Diag(DelLoc, diag::err_deleted_main); + // C++11 [dcl.fct.def.delete]p4: + // A deleted function is implicitly inline. + Fn->setImplicitlyInline(); Fn->setDeletedAsWritten(); } @@ -13461,6 +14280,8 @@ bool Sema::DefineUsedVTables() { CXXRecordDecl *Class = VTableUses[I].first->getDefinition(); if (!Class) continue; + TemplateSpecializationKind ClassTSK = + Class->getTemplateSpecializationKind(); SourceLocation Loc = VTableUses[I].second; @@ -13484,9 +14305,8 @@ bool Sema::DefineUsedVTables() { // of an explicit instantiation declaration, suppress the // vtable; it will live with the explicit instantiation // definition. - bool IsExplicitInstantiationDeclaration - = Class->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDeclaration; + bool IsExplicitInstantiationDeclaration = + ClassTSK == TSK_ExplicitInstantiationDeclaration; for (auto R : Class->redecls()) { TemplateSpecializationKind TSK = cast<CXXRecordDecl>(R)->getTemplateSpecializationKind(); @@ -13519,17 +14339,20 @@ bool Sema::DefineUsedVTables() { if (VTablesUsed[Canonical]) Consumer.HandleVTable(Class); - // Optionally warn if we're emitting a weak vtable. - if (Class->isExternallyVisible() && - Class->getTemplateSpecializationKind() != TSK_ImplicitInstantiation) { + // Warn if we're emitting a weak vtable. The vtable will be weak if there is + // no key function or the key function is inlined. Don't warn in C++ ABIs + // that lack key functions, since the user won't be able to make one. + if (Context.getTargetInfo().getCXXABI().hasKeyFunctions() && + Class->isExternallyVisible() && ClassTSK != TSK_ImplicitInstantiation) { const FunctionDecl *KeyFunctionDef = nullptr; - if (!KeyFunction || - (KeyFunction->hasBody(KeyFunctionDef) && - KeyFunctionDef->isInlined())) - Diag(Class->getLocation(), Class->getTemplateSpecializationKind() == - TSK_ExplicitInstantiationDefinition - ? diag::warn_weak_template_vtable : diag::warn_weak_vtable) - << Class; + if (!KeyFunction || (KeyFunction->hasBody(KeyFunctionDef) && + KeyFunctionDef->isInlined())) { + Diag(Class->getLocation(), + ClassTSK == TSK_ExplicitInstantiationDefinition + ? diag::warn_weak_template_vtable + : diag::warn_weak_vtable) + << Class; + } } } VTableUses.clear(); diff --git a/lib/Sema/SemaDeclObjC.cpp b/lib/Sema/SemaDeclObjC.cpp index 738de77cecb7b..d172c951e7494 100644 --- a/lib/Sema/SemaDeclObjC.cpp +++ b/lib/Sema/SemaDeclObjC.cpp @@ -11,22 +11,22 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" +#include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTMutationListener.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "clang/AST/ExprObjC.h" +#include "clang/AST/RecursiveASTVisitor.h" #include "clang/Basic/SourceManager.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseSet.h" -#include "TypeLocBuilder.h" using namespace clang; @@ -209,11 +209,11 @@ bool Sema::CheckARCMethodDecl(ObjCMethodDecl *method) { if (!Context.hasSameType(method->getReturnType(), Context.VoidTy)) { SourceRange ResultTypeRange = method->getReturnTypeSourceRange(); if (ResultTypeRange.isInvalid()) - Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::err_dealloc_bad_result_type) << method->getReturnType() << FixItHint::CreateInsertion(method->getSelectorLoc(0), "(void)"); else - Diag(method->getLocation(), diag::error_dealloc_bad_result_type) + Diag(method->getLocation(), diag::err_dealloc_bad_result_type) << method->getReturnType() << FixItHint::CreateReplacement(ResultTypeRange, "void"); return true; @@ -1028,6 +1028,7 @@ ActOnStartClassInterface(Scope *S, SourceLocation AtInterfaceLoc, /// typedef'ed use for a qualified super class and adds them to the list /// of the protocols. void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, + SmallVectorImpl<SourceLocation> &ProtocolLocs, IdentifierInfo *SuperName, SourceLocation SuperLoc) { if (!SuperName) @@ -1040,8 +1041,14 @@ void Sema::ActOnTypedefedProtocols(SmallVectorImpl<Decl *> &ProtocolRefs, if (const TypedefNameDecl *TDecl = dyn_cast_or_null<TypedefNameDecl>(IDecl)) { QualType T = TDecl->getUnderlyingType(); if (T->isObjCObjectType()) - if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>()) + if (const ObjCObjectType *OPT = T->getAs<ObjCObjectType>()) { ProtocolRefs.append(OPT->qual_begin(), OPT->qual_end()); + // FIXME: Consider whether this should be an invalid loc since the loc + // is not actually pointing to a protocol name reference but to the + // typedef reference. Note that the base class name loc is also pointing + // at the typedef. + ProtocolLocs.append(OPT->getNumProtocols(), SuperLoc); + } } } @@ -2353,7 +2360,7 @@ static bool CheckMethodOverrideParam(Sema &S, } if (S.Context.hasSameUnqualifiedType(ImplTy, IfaceTy)) return true; - + if (!Warn) return false; unsigned DiagID = @@ -2741,7 +2748,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getInstanceMethod(I->getSelector()); - assert(CDecl->getInstanceMethod(I->getSelector()) && + assert(CDecl->getInstanceMethod(I->getSelector(), true/*AllowHidden*/) && "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { @@ -2767,7 +2774,7 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, } else { ObjCMethodDecl *ImpMethodDecl = IMPDecl->getClassMethod(I->getSelector()); - assert(CDecl->getClassMethod(I->getSelector()) && + assert(CDecl->getClassMethod(I->getSelector(), true/*AllowHidden*/) && "Expected to find the method through lookup as well"); // ImpMethodDecl may be null as in a @dynamic property. if (ImpMethodDecl) { @@ -3217,7 +3224,7 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodList *ListWithSameDeclaration = nullptr; for (; List; Previous = List, List = List->getNext()) { // If we are building a module, keep all of the methods. - if (getLangOpts().CompilingModule) + if (getLangOpts().isCompilingModule()) continue; bool SameDeclaration = MatchTwoMethodDeclarations(Method, @@ -3853,6 +3860,18 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, Diag(IDecl->getLocation(), diag::err_objc_root_class_subclass); } + if (const ObjCInterfaceDecl *Super = IDecl->getSuperClass()) { + // An interface can subclass another interface with a + // objc_subclassing_restricted attribute when it has that attribute as + // well (because of interfaces imported from Swift). Therefore we have + // to check if we can subclass in the implementation as well. + if (IDecl->hasAttr<ObjCSubclassingRestrictedAttr>() && + Super->hasAttr<ObjCSubclassingRestrictedAttr>()) { + Diag(IC->getLocation(), diag::err_restricted_superclass_mismatch); + Diag(Super->getLocation(), diag::note_class_declared); + } + } + if (LangOpts.ObjCRuntime.isNonFragile()) { while (IDecl->getSuperClass()) { DiagnoseDuplicateIvars(IDecl, IDecl->getSuperClass()); @@ -3873,6 +3892,14 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, ImplMethodsVsClassMethods(S, CatImplClass, Cat); } } + } else if (const auto *IntfDecl = dyn_cast<ObjCInterfaceDecl>(ClassDecl)) { + if (const ObjCInterfaceDecl *Super = IntfDecl->getSuperClass()) { + if (!IntfDecl->hasAttr<ObjCSubclassingRestrictedAttr>() && + Super->hasAttr<ObjCSubclassingRestrictedAttr>()) { + Diag(IntfDecl->getLocation(), diag::err_restricted_superclass_mismatch); + Diag(Super->getLocation(), diag::note_class_declared); + } + } } if (isInterfaceDeclKind) { // Reject invalid vardecls. @@ -4290,7 +4317,7 @@ Decl *Sema::ActOnMethodDeclaration( bool isVariadic, bool MethodDefinition) { // Make sure we can establish a context for the method. if (!CurContext->isObjCContainer()) { - Diag(MethodLoc, diag::error_missing_method_context); + Diag(MethodLoc, diag::err_missing_method_context); return nullptr; } ObjCContainerDecl *OCD = dyn_cast<ObjCContainerDecl>(CurContext); diff --git a/lib/Sema/SemaExceptionSpec.cpp b/lib/Sema/SemaExceptionSpec.cpp index 4a21eb308fe53..2ac2aca6f6601 100644 --- a/lib/Sema/SemaExceptionSpec.cpp +++ b/lib/Sema/SemaExceptionSpec.cpp @@ -43,22 +43,36 @@ bool Sema::isLibstdcxxEagerExceptionSpecHack(const Declarator &D) { auto *RD = dyn_cast<CXXRecordDecl>(CurContext); // All the problem cases are member functions named "swap" within class - // templates declared directly within namespace std. - if (!RD || RD->getEnclosingNamespaceContext() != getStdNamespace() || - !RD->getIdentifier() || !RD->getDescribedClassTemplate() || + // templates declared directly within namespace std or std::__debug or + // std::__profile. + if (!RD || !RD->getIdentifier() || !RD->getDescribedClassTemplate() || !D.getIdentifier() || !D.getIdentifier()->isStr("swap")) return false; + auto *ND = dyn_cast<NamespaceDecl>(RD->getDeclContext()); + if (!ND) + return false; + + bool IsInStd = ND->isStdNamespace(); + if (!IsInStd) { + // This isn't a direct member of namespace std, but it might still be + // libstdc++'s std::__debug::array or std::__profile::array. + IdentifierInfo *II = ND->getIdentifier(); + if (!II || !(II->isStr("__debug") || II->isStr("__profile")) || + !ND->isInStdNamespace()) + return false; + } + // Only apply this hack within a system header. if (!Context.getSourceManager().isInSystemHeader(D.getLocStart())) return false; return llvm::StringSwitch<bool>(RD->getIdentifier()->getName()) .Case("array", true) - .Case("pair", true) - .Case("priority_queue", true) - .Case("stack", true) - .Case("queue", true) + .Case("pair", IsInStd) + .Case("priority_queue", IsInStd) + .Case("stack", IsInStd) + .Case("queue", IsInStd) .Default(false); } @@ -129,6 +143,11 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { /// to member to a function with an exception specification. This means that /// it is invalid to add another level of indirection. bool Sema::CheckDistantExceptionSpec(QualType T) { + // C++17 removes this rule in favor of putting exception specifications into + // the type system. + if (getLangOpts().CPlusPlus1z) + return false; + if (const PointerType *PT = T->getAs<PointerType>()) T = PT->getPointeeType(); else if (const MemberPointerType *PT = T->getAs<MemberPointerType>()) @@ -188,6 +207,14 @@ Sema::UpdateExceptionSpec(FunctionDecl *FD, Context.adjustExceptionSpec(cast<FunctionDecl>(Redecl), ESI); } +static bool CheckEquivalentExceptionSpecImpl( + Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification = nullptr, + bool *MissingEmptyExceptionSpecification = nullptr, + bool AllowNoexceptAllMatchWithNoSpec = false, bool IsOperatorNew = false); + /// Determine whether a function has an implicitly-generated exception /// specification. static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { @@ -210,6 +237,12 @@ static bool hasImplicitExceptionSpec(FunctionDecl *Decl) { } bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { + // Just completely ignore this under -fno-exceptions prior to C++1z. + // In C++1z onwards, the exception specification is part of the type and + // we will diagnose mismatches anyway, so it's better to check for them here. + if (!getLangOpts().CXXExceptions && !getLangOpts().CPlusPlus1z) + return false; + OverloadedOperatorKind OO = New->getDeclName().getCXXOverloadedOperator(); bool IsOperatorNew = OO == OO_New || OO == OO_Array_New; bool MissingExceptionSpecification = false; @@ -224,8 +257,8 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // Check the types as written: they must match before any exception // specification adjustment is applied. - if (!CheckEquivalentExceptionSpec( - PDiag(DiagID), PDiag(diag::note_previous_declaration), + if (!CheckEquivalentExceptionSpecImpl( + *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), New->getType()->getAs<FunctionProtoType>(), New->getLocation(), &MissingExceptionSpecification, &MissingEmptyExceptionSpecification, @@ -234,7 +267,7 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // If a declaration of a function has an implicit // exception-specification, other declarations of the function shall // not specify an exception-specification. - if (getLangOpts().CPlusPlus11 && + if (getLangOpts().CPlusPlus11 && getLangOpts().CXXExceptions && hasImplicitExceptionSpec(Old) != hasImplicitExceptionSpec(New)) { Diag(New->getLocation(), diag::ext_implicit_exception_spec_mismatch) << hasImplicitExceptionSpec(Old); @@ -255,14 +288,15 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { // The new function declaration is only missing an empty exception // specification "throw()". If the throw() specification came from a // function in a system header that has C linkage, just add an empty - // exception specification to the "new" declaration. This is an - // egregious workaround for glibc, which adds throw() specifications - // to many libc functions as an optimization. Unfortunately, that - // optimization isn't permitted by the C++ standard, so we're forced - // to work around it here. + // exception specification to the "new" declaration. Note that C library + // implementations are permitted to add these nothrow exception + // specifications. + // + // Likewise if the old function is a builtin. if (MissingEmptyExceptionSpecification && NewProto && (Old->getLocation().isInvalid() || - Context.getSourceManager().isInSystemHeader(Old->getLocation())) && + Context.getSourceManager().isInSystemHeader(Old->getLocation()) || + Old->getBuiltinID()) && Old->isExternC()) { New->setType(Context.getFunctionType( NewProto->getReturnType(), NewProto->getParamTypes(), @@ -376,11 +410,15 @@ bool Sema::CheckEquivalentExceptionSpec(FunctionDecl *Old, FunctionDecl *New) { bool Sema::CheckEquivalentExceptionSpec( const FunctionProtoType *Old, SourceLocation OldLoc, const FunctionProtoType *New, SourceLocation NewLoc) { + if (!getLangOpts().CXXExceptions) + return false; + unsigned DiagID = diag::err_mismatched_exception_spec; if (getLangOpts().MicrosoftExt) DiagID = diag::ext_mismatched_exception_spec; - bool Result = CheckEquivalentExceptionSpec(PDiag(DiagID), - PDiag(diag::note_previous_declaration), Old, OldLoc, New, NewLoc); + bool Result = CheckEquivalentExceptionSpecImpl( + *this, PDiag(DiagID), PDiag(diag::note_previous_declaration), + Old, OldLoc, New, NewLoc); // In Microsoft mode, mismatching exception specifications just cause a warning. if (getLangOpts().MicrosoftExt) @@ -394,30 +432,23 @@ bool Sema::CheckEquivalentExceptionSpec( /// \return \c false if the exception specifications match, \c true if there is /// a problem. If \c true is returned, either a diagnostic has already been /// produced or \c *MissingExceptionSpecification is set to \c true. -bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, - const PartialDiagnostic & NoteID, - const FunctionProtoType *Old, - SourceLocation OldLoc, - const FunctionProtoType *New, - SourceLocation NewLoc, - bool *MissingExceptionSpecification, - bool*MissingEmptyExceptionSpecification, - bool AllowNoexceptAllMatchWithNoSpec, - bool IsOperatorNew) { - // Just completely ignore this under -fno-exceptions. - if (!getLangOpts().CXXExceptions) - return false; - +static bool CheckEquivalentExceptionSpecImpl( + Sema &S, const PartialDiagnostic &DiagID, const PartialDiagnostic &NoteID, + const FunctionProtoType *Old, SourceLocation OldLoc, + const FunctionProtoType *New, SourceLocation NewLoc, + bool *MissingExceptionSpecification, + bool *MissingEmptyExceptionSpecification, + bool AllowNoexceptAllMatchWithNoSpec, bool IsOperatorNew) { if (MissingExceptionSpecification) *MissingExceptionSpecification = false; if (MissingEmptyExceptionSpecification) *MissingEmptyExceptionSpecification = false; - Old = ResolveExceptionSpec(NewLoc, Old); + Old = S.ResolveExceptionSpec(NewLoc, Old); if (!Old) return false; - New = ResolveExceptionSpec(NewLoc, New); + New = S.ResolveExceptionSpec(NewLoc, New); if (!New) return false; @@ -451,8 +482,8 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (OldEST == EST_None && NewEST == EST_None) return false; - FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(Context); - FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(Context); + FunctionProtoType::NoexceptResult OldNR = Old->getNoexceptSpec(S.Context); + FunctionProtoType::NoexceptResult NewNR = New->getNoexceptSpec(S.Context); if (OldNR == FunctionProtoType::NR_BadNoexcept || NewNR == FunctionProtoType::NR_BadNoexcept) return false; @@ -467,9 +498,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (OldNR != NewNR && OldNR != FunctionProtoType::NR_NoNoexcept && NewNR != FunctionProtoType::NR_NoNoexcept) { - Diag(NewLoc, DiagID); + S.Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0 && OldLoc.isValid()) - Diag(OldLoc, NoteID); + S.Diag(OldLoc, NoteID); return true; } @@ -507,7 +538,7 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // As a special compatibility feature, under C++0x we accept no spec and // throw(std::bad_alloc) as equivalent for operator new and operator new[]. // This is because the implicit declaration changed, but old code would break. - if (getLangOpts().CPlusPlus11 && IsOperatorNew) { + if (S.getLangOpts().CPlusPlus11 && IsOperatorNew) { const FunctionProtoType *WithExceptions = nullptr; if (OldEST == EST_None && NewEST == EST_Dynamic) WithExceptions = New; @@ -548,9 +579,9 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, return true; } - Diag(NewLoc, DiagID); + S.Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0 && OldLoc.isValid()) - Diag(OldLoc, NoteID); + S.Diag(OldLoc, NoteID); return true; } @@ -562,11 +593,11 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, // to the second. llvm::SmallPtrSet<CanQualType, 8> OldTypes, NewTypes; for (const auto &I : Old->exceptions()) - OldTypes.insert(Context.getCanonicalType(I).getUnqualifiedType()); + OldTypes.insert(S.Context.getCanonicalType(I).getUnqualifiedType()); for (const auto &I : New->exceptions()) { - CanQualType TypePtr = Context.getCanonicalType(I).getUnqualifiedType(); - if(OldTypes.count(TypePtr)) + CanQualType TypePtr = S.Context.getCanonicalType(I).getUnqualifiedType(); + if (OldTypes.count(TypePtr)) NewTypes.insert(TypePtr); else Success = false; @@ -577,19 +608,34 @@ bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, if (Success) { return false; } - Diag(NewLoc, DiagID); + S.Diag(NewLoc, DiagID); if (NoteID.getDiagID() != 0 && OldLoc.isValid()) - Diag(OldLoc, NoteID); + S.Diag(OldLoc, NoteID); return true; } +bool Sema::CheckEquivalentExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic &NoteID, + const FunctionProtoType *Old, + SourceLocation OldLoc, + const FunctionProtoType *New, + SourceLocation NewLoc) { + if (!getLangOpts().CXXExceptions) + return false; + return CheckEquivalentExceptionSpecImpl(*this, DiagID, NoteID, Old, OldLoc, + New, NewLoc); +} + /// CheckExceptionSpecSubset - Check whether the second function type's /// exception specification is a subset (or equivalent) of the first function /// type. This is used by override and pointer assignment checks. -bool Sema::CheckExceptionSpecSubset( - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - const FunctionProtoType *Superset, SourceLocation SuperLoc, - const FunctionProtoType *Subset, SourceLocation SubLoc) { +bool Sema::CheckExceptionSpecSubset(const PartialDiagnostic &DiagID, + const PartialDiagnostic &NestedDiagID, + const PartialDiagnostic &NoteID, + const FunctionProtoType *Superset, + SourceLocation SuperLoc, + const FunctionProtoType *Subset, + SourceLocation SubLoc) { // Just auto-succeed under -fno-exceptions. if (!getLangOpts().CXXExceptions) @@ -613,7 +659,8 @@ bool Sema::CheckExceptionSpecSubset( // If superset contains everything, we're done. if (SuperEST == EST_None || SuperEST == EST_MSAny) - return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, + Subset, SubLoc); // If there are dependent noexcept specs, assume everything is fine. Unlike // with the equivalency check, this is safe in this case, because we don't @@ -628,7 +675,8 @@ bool Sema::CheckExceptionSpecSubset( // Another case of the superset containing everything. if (SuperNR == FunctionProtoType::NR_Throw) - return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, + Subset, SubLoc); ExceptionSpecificationType SubEST = Subset->getExceptionSpecType(); @@ -659,7 +707,8 @@ bool Sema::CheckExceptionSpecSubset( // If the subset contains nothing, we're done. if (SubEST == EST_DynamicNone || SubNR == FunctionProtoType::NR_Nothrow) - return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, + Subset, SubLoc); // Otherwise, if the superset contains nothing, we've failed. if (SuperEST == EST_DynamicNone || SuperNR == FunctionProtoType::NR_Nothrow) { @@ -751,14 +800,15 @@ bool Sema::CheckExceptionSpecSubset( } } // We've run half the gauntlet. - return CheckParamExceptionSpec(NoteID, Superset, SuperLoc, Subset, SubLoc); + return CheckParamExceptionSpec(NestedDiagID, NoteID, Superset, SuperLoc, + Subset, SubLoc); } -static bool CheckSpecForTypesEquivalent(Sema &S, - const PartialDiagnostic &DiagID, const PartialDiagnostic & NoteID, - QualType Target, SourceLocation TargetLoc, - QualType Source, SourceLocation SourceLoc) -{ +static bool +CheckSpecForTypesEquivalent(Sema &S, const PartialDiagnostic &DiagID, + const PartialDiagnostic &NoteID, QualType Target, + SourceLocation TargetLoc, QualType Source, + SourceLocation SourceLoc) { const FunctionProtoType *TFunc = GetUnderlyingFunction(Target); if (!TFunc) return false; @@ -775,13 +825,16 @@ static bool CheckSpecForTypesEquivalent(Sema &S, /// assignment and override compatibility check. We do not check the parameters /// of parameter function pointers recursively, as no sane programmer would /// even be able to write such a function type. -bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, +bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &DiagID, + const PartialDiagnostic &NoteID, const FunctionProtoType *Target, SourceLocation TargetLoc, const FunctionProtoType *Source, SourceLocation SourceLoc) { + auto RetDiag = DiagID; + RetDiag << 0; if (CheckSpecForTypesEquivalent( - *this, PDiag(diag::err_deep_exception_specs_differ) << 0, PDiag(), + *this, RetDiag, PDiag(), Target->getReturnType(), TargetLoc, Source->getReturnType(), SourceLoc)) return true; @@ -791,8 +844,10 @@ bool Sema::CheckParamExceptionSpec(const PartialDiagnostic &NoteID, assert(Target->getNumParams() == Source->getNumParams() && "Functions have different argument counts."); for (unsigned i = 0, E = Target->getNumParams(); i != E; ++i) { + auto ParamDiag = DiagID; + ParamDiag << 1; if (CheckSpecForTypesEquivalent( - *this, PDiag(diag::err_deep_exception_specs_differ) << 1, PDiag(), + *this, ParamDiag, PDiag(), Target->getParamType(i), TargetLoc, Source->getParamType(i), SourceLoc)) return true; @@ -812,6 +867,16 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { if (!FromFunc || FromFunc->hasDependentExceptionSpec()) return false; + unsigned DiagID = diag::err_incompatible_exception_specs; + unsigned NestedDiagID = diag::err_deep_exception_specs_differ; + // This is not an error in C++17 onwards, unless the noexceptness doesn't + // match, but in that case we have a full-on type mismatch, not just a + // type sugar mismatch. + if (getLangOpts().CPlusPlus1z) { + DiagID = diag::warn_incompatible_exception_specs; + NestedDiagID = diag::warn_deep_exception_specs_differ; + } + // Now we've got the correct types on both sides, check their compatibility. // This means that the source of the conversion can only throw a subset of // the exceptions of the target, and any exception specs on arguments or @@ -824,10 +889,10 @@ bool Sema::CheckExceptionSpecCompatibility(Expr *From, QualType ToType) { // void (*q)(void (*) throw(int)) = p; // } // ... because it might be instantiated with T=int. - return CheckExceptionSpecSubset(PDiag(diag::err_incompatible_exception_specs), - PDiag(), ToFunc, - From->getSourceRange().getBegin(), - FromFunc, SourceLocation()); + return CheckExceptionSpecSubset(PDiag(DiagID), PDiag(NestedDiagID), PDiag(), + ToFunc, From->getSourceRange().getBegin(), + FromFunc, SourceLocation()) && + !getLangOpts().CPlusPlus1z; } bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, @@ -861,6 +926,7 @@ bool Sema::CheckOverridingFunctionExceptionSpec(const CXXMethodDecl *New, if (getLangOpts().MicrosoftExt) DiagID = diag::ext_override_exception_spec; return CheckExceptionSpecSubset(PDiag(DiagID), + PDiag(diag::err_deep_exception_specs_differ), PDiag(diag::note_overridden_virtual_function), Old->getType()->getAs<FunctionProtoType>(), Old->getLocation(), @@ -879,19 +945,37 @@ static CanThrowResult canSubExprsThrow(Sema &S, const Expr *E) { } static CanThrowResult canCalleeThrow(Sema &S, const Expr *E, const Decl *D) { - assert(D && "Expected decl"); - - // See if we can get a function type from the decl somehow. - const ValueDecl *VD = dyn_cast<ValueDecl>(D); - if (!VD) // If we have no clue what we're calling, assume the worst. - return CT_Can; - // As an extension, we assume that __attribute__((nothrow)) functions don't // throw. - if (isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) + if (D && isa<FunctionDecl>(D) && D->hasAttr<NoThrowAttr>()) return CT_Cannot; - QualType T = VD->getType(); + QualType T; + + // In C++1z, just look at the function type of the callee. + if (S.getLangOpts().CPlusPlus1z && isa<CallExpr>(E)) { + E = cast<CallExpr>(E)->getCallee(); + T = E->getType(); + if (T->isSpecificPlaceholderType(BuiltinType::BoundMember)) { + // Sadly we don't preserve the actual type as part of the "bound member" + // placeholder, so we need to reconstruct it. + E = E->IgnoreParenImpCasts(); + + // Could be a call to a pointer-to-member or a plain member access. + if (auto *Op = dyn_cast<BinaryOperator>(E)) { + assert(Op->getOpcode() == BO_PtrMemD || Op->getOpcode() == BO_PtrMemI); + T = Op->getRHS()->getType() + ->castAs<MemberPointerType>()->getPointeeType(); + } else { + T = cast<MemberExpr>(E)->getMemberDecl()->getType(); + } + } + } else if (const ValueDecl *VD = dyn_cast_or_null<ValueDecl>(D)) + T = VD->getType(); + else + // If we have no clue what we're calling, assume the worst. + return CT_Can; + const FunctionProtoType *FT; if ((FT = T->getAs<FunctionProtoType>())) { } else if (const PointerType *PT = T->getAs<PointerType>()) @@ -983,10 +1067,8 @@ CanThrowResult Sema::canThrow(const Expr *E) { CT = CT_Dependent; else if (isa<CXXPseudoDestructorExpr>(CE->getCallee()->IgnoreParens())) CT = CT_Cannot; - else if (CE->getCalleeDecl()) - CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); else - CT = CT_Can; + CT = canCalleeThrow(*this, E, CE->getCalleeDecl()); if (CT == CT_Can) return CT; return mergeCanThrow(CT, canSubExprsThrow(*this, E)); @@ -1085,6 +1167,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ExprWithCleanupsClass: case Expr::ExtVectorElementExprClass: case Expr::InitListExprClass: + case Expr::ArrayInitLoopExprClass: case Expr::MemberExprClass: case Expr::ObjCIsaExprClass: case Expr::ObjCIvarRefExprClass: @@ -1178,6 +1261,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ImaginaryLiteralClass: case Expr::ImplicitValueInitExprClass: case Expr::IntegerLiteralClass: + case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::ObjCEncodeExprClass: case Expr::ObjCStringLiteralClass: diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 719e1e3502cad..3c554c9a5244f 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -42,6 +41,7 @@ #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" #include "clang/Sema/SemaFixItUtils.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/Support/ConvertUTF.h" using namespace clang; @@ -103,13 +103,9 @@ static bool HasRedeclarationWithoutAvailabilityInCategory(const Decl *D) { return false; } -static AvailabilityResult -DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, - const ObjCInterfaceDecl *UnknownObjCClass, - bool ObjCPropertyAccess) { - // See if this declaration is unavailable or deprecated. - std::string Message; - AvailabilityResult Result = D->getAvailability(&Message); +AvailabilityResult +Sema::ShouldDiagnoseAvailabilityOfDecl(NamedDecl *&D, std::string *Message) { + 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. @@ -117,18 +113,18 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, if (Result == AR_Available) { if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) { D = TT->getDecl(); - Result = D->getAvailability(&Message); + Result = D->getAvailability(Message); continue; } } break; } - + // Forward class declarations get their attributes from their definition. if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(D)) { if (IDecl->getDefinition()) { D = IDecl->getDefinition(); - Result = D->getAvailability(&Message); + Result = D->getAvailability(Message); } } @@ -136,12 +132,51 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, if (Result == AR_Available) { const DeclContext *DC = ECD->getDeclContext(); if (const EnumDecl *TheEnumDecl = dyn_cast<EnumDecl>(DC)) - Result = TheEnumDecl->getAvailability(&Message); + Result = TheEnumDecl->getAvailability(Message); + } + + if (Result == AR_NotYetIntroduced) { + // Don't do this for enums, they can't be redeclared. + if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) + return AR_Available; + + bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); + // Objective-C method declarations in categories are not modelled as + // redeclarations, so manually look for a redeclaration in a category + // if necessary. + if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) + Warn = false; + // In general, D will point to the most recent redeclaration. However, + // for `@class A;` decls, this isn't true -- manually go through the + // redecl chain in that case. + if (Warn && isa<ObjCInterfaceDecl>(D)) + for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; + Redecl = Redecl->getPreviousDecl()) + if (!Redecl->hasAttr<AvailabilityAttr>() || + Redecl->getAttr<AvailabilityAttr>()->isInherited()) + Warn = false; + + return Warn ? AR_NotYetIntroduced : AR_Available; + } + + return Result; +} + +static void +DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, + const ObjCInterfaceDecl *UnknownObjCClass, + bool ObjCPropertyAccess) { + std::string Message; + // See if this declaration is unavailable, deprecated, or partial. + if (AvailabilityResult Result = + S.ShouldDiagnoseAvailabilityOfDecl(D, &Message)) { + + if (Result == AR_NotYetIntroduced && S.getCurFunctionOrMethodDecl()) { + S.getEnclosingFunction()->HasPotentialAvailabilityViolations = true; + return; } - const ObjCPropertyDecl *ObjCPDecl = nullptr; - if (Result == AR_Deprecated || Result == AR_Unavailable || - Result == AR_NotYetIntroduced) { + const ObjCPropertyDecl *ObjCPDecl = nullptr; if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); @@ -149,56 +184,10 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, ObjCPDecl = PD; } } - } - - switch (Result) { - case AR_Available: - break; - - case AR_Deprecated: - if (S.getCurContextAvailability() != AR_Deprecated) - S.EmitAvailabilityWarning(Sema::AD_Deprecation, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - - case AR_NotYetIntroduced: { - // Don't do this for enums, they can't be redeclared. - if (isa<EnumConstantDecl>(D) || isa<EnumDecl>(D)) - break; - - bool Warn = !D->getAttr<AvailabilityAttr>()->isInherited(); - // Objective-C method declarations in categories are not modelled as - // redeclarations, so manually look for a redeclaration in a category - // if necessary. - if (Warn && HasRedeclarationWithoutAvailabilityInCategory(D)) - Warn = false; - // In general, D will point to the most recent redeclaration. However, - // for `@class A;` decls, this isn't true -- manually go through the - // redecl chain in that case. - if (Warn && isa<ObjCInterfaceDecl>(D)) - for (Decl *Redecl = D->getMostRecentDecl(); Redecl && Warn; - Redecl = Redecl->getPreviousDecl()) - if (!Redecl->hasAttr<AvailabilityAttr>() || - Redecl->getAttr<AvailabilityAttr>()->isInherited()) - Warn = false; - - if (Warn) - S.EmitAvailabilityWarning(Sema::AD_Partial, D, Message, Loc, - UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - } - case AR_Unavailable: - if (S.getCurContextAvailability() != AR_Unavailable) - S.EmitAvailabilityWarning(Sema::AD_Unavailable, - D, Message, Loc, UnknownObjCClass, ObjCPDecl, - ObjCPropertyAccess); - break; - - } - return Result; + S.EmitAvailabilityWarning(Result, D, Message, Loc, UnknownObjCClass, + ObjCPDecl, ObjCPropertyAccess); + } } /// \brief Emit a note explaining that this function is deleted. @@ -340,10 +329,15 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) { - const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType(); + if (isa<BindingDecl>(D)) { + Diag(Loc, diag::err_binding_cannot_appear_in_own_initializer) + << D->getDeclName(); + } else { + const AutoType *AT = cast<VarDecl>(D)->getType()->getContainedAutoType(); - Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) - << D->getDeclName() << (unsigned)AT->getKeyword(); + Diag(Loc, diag::err_auto_variable_cannot_appear_in_own_initializer) + << D->getDeclName() << (unsigned)AT->getKeyword(); + } return true; } @@ -366,6 +360,9 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, if (getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && DeduceReturnType(FD, Loc)) return true; + + if (getLangOpts().CUDA && !CheckCUDACall(Loc, FD)) + return true; } // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions @@ -660,7 +657,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { return E; // OpenCL usually rejects direct accesses to values of 'half' type. - if (getLangOpts().OpenCL && !getOpenCLOptions().cl_khr_fp16 && + if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp16") && T->isHalfType()) { Diag(E->getExprLoc(), diag::err_opencl_half_load_store) << 0 << T; @@ -820,8 +817,16 @@ ExprResult Sema::DefaultArgumentPromotion(Expr *E) { // double. const BuiltinType *BTy = Ty->getAs<BuiltinType>(); if (BTy && (BTy->getKind() == BuiltinType::Half || - BTy->getKind() == BuiltinType::Float)) - E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get(); + BTy->getKind() == BuiltinType::Float)) { + if (getLangOpts().OpenCL && + !getOpenCLOptions().isEnabled("cl_khr_fp64")) { + if (BTy->getKind() == BuiltinType::Half) { + E = ImpCastExprToType(E, Context.FloatTy, CK_FloatingCast).get(); + } + } else { + E = ImpCastExprToType(E, Context.DoubleTy, CK_FloatingCast).get(); + } + } // C++ performs lvalue-to-rvalue conversion as a default argument // promotion, even on class types, but note: @@ -1189,7 +1194,7 @@ static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, */ return Float128AndLongDouble && (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != - &llvm::APFloat::IEEEdouble); + &llvm::APFloat::IEEEdouble()); } typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); @@ -1735,19 +1740,6 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, const DeclarationNameInfo &NameInfo, const CXXScopeSpec *SS, NamedDecl *FoundD, const TemplateArgumentListInfo *TemplateArgs) { - if (getLangOpts().CUDA) - if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) - if (const FunctionDecl *Callee = dyn_cast<FunctionDecl>(D)) { - if (CheckCUDATarget(Caller, Callee)) { - Diag(NameInfo.getLoc(), diag::err_ref_bad_target) - << IdentifyCUDATarget(Callee) << D->getIdentifier() - << IdentifyCUDATarget(Caller); - Diag(D->getLocation(), diag::note_previous_decl) - << D->getIdentifier(); - return ExprError(); - } - } - bool RefersToCapturedVariable = isa<VarDecl>(D) && NeedToCaptureVariable(cast<VarDecl>(D), NameInfo.getLoc()); @@ -1785,6 +1777,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, E->setObjectKind(OK_BitField); } + // C++ [expr.prim]/8: The expression [...] is a bit-field if the identifier + // designates a bit-field. + if (auto *BD = dyn_cast<BindingDecl>(D)) + if (auto *BE = BD->getBinding()) + E->setObjectKind(BE->getObjectKind()); + return E; } @@ -2462,7 +2460,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, if (IFace && (IV = IFace->lookupInstanceVariable(II, ClassDeclared))) { // Diagnose using an ivar in a class method. if (IsClassMethod) - return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method) + return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName()); // If we're referencing an invalid decl, just return this as a silent @@ -2478,7 +2476,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, if (IV->getAccessControl() == ObjCIvarDecl::Private && !declaresSameEntity(ClassDeclared, IFace) && !getLangOpts().DebuggerSupport) - Diag(Loc, diag::error_private_ivar_access) << IV->getDeclName(); + Diag(Loc, diag::err_private_ivar_access) << IV->getDeclName(); // FIXME: This should use a new expr for a direct reference, don't // turn this into Self->ivar, just return a BareIVarExpr or something. @@ -2534,7 +2532,7 @@ Sema::LookupInObjCMethod(LookupResult &Lookup, Scope *S, Lookup.getFoundDecl()->isDefinedOutsideFunctionOrMethod()) { // If accessing a stand-alone ivar in a class method, this is an error. if (const ObjCIvarDecl *IV = dyn_cast<ObjCIvarDecl>(Lookup.getFoundDecl())) - return ExprError(Diag(Loc, diag::error_ivar_use_in_class_method) + return ExprError(Diag(Loc, diag::err_ivar_use_in_class_method) << IV->getDeclName()); } @@ -2829,6 +2827,10 @@ ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS, return ULE; } +static void +diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, + ValueDecl *var, DeclContext *DC); + /// \brief Complete semantic analysis for a reference to the given declaration. ExprResult Sema::BuildDeclarationNameExpr( const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D, @@ -2881,6 +2883,14 @@ ExprResult Sema::BuildDeclarationNameExpr( { QualType type = VD->getType(); + if (auto *FPT = type->getAs<FunctionProtoType>()) { + // C++ [except.spec]p17: + // An exception-specification is considered to be needed when: + // - in an expression, the function is the unique lookup result or + // the selected member of a set of overloaded functions. + ResolveExceptionSpec(Loc, FPT); + type = VD->getType(); + } ExprValueKind valueKind = VK_RValue; switch (D->getKind()) { @@ -2939,6 +2949,7 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::Var: case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: + case Decl::Decomposition: case Decl::OMPCapturedExpr: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && @@ -2966,6 +2977,19 @@ ExprResult Sema::BuildDeclarationNameExpr( break; } + + case Decl::Binding: { + // These are always lvalues. + valueKind = VK_LValue; + type = type.getNonReferenceType(); + // FIXME: Support lambda-capture of BindingDecls, once CWG actually + // decides how that's supposed to work. + auto *BD = cast<BindingDecl>(VD); + if (BD->getDeclContext()->isFunctionOrMethod() && + BD->getDeclContext() != CurContext) + diagnoseUncapturableValueReference(*this, Loc, BD, CurContext); + break; + } case Decl::Function: { if (unsigned BID = cast<FunctionDecl>(VD)->getBuiltinID()) { @@ -3046,8 +3070,9 @@ static void ConvertUTF8ToWideString(unsigned CharByteWidth, StringRef Source, SmallString<32> &Target) { Target.resize(CharByteWidth * (Source.size() + 1)); char *ResultPtr = &Target[0]; - const UTF8 *ErrorPtr; - bool success = ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr); + const llvm::UTF8 *ErrorPtr; + bool success = + llvm::ConvertUTF8toWide(CharByteWidth, Source, ResultPtr, ErrorPtr); (void)success; assert(success); Target.resize(ResultPtr - &Target[0]); @@ -3361,7 +3386,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Literal.isFloatingLiteral()) { QualType Ty; if (Literal.isHalf){ - if (getOpenCLOptions().cl_khr_fp16) + if (getOpenCLOptions().isEnabled("cl_khr_fp16")) Ty = Context.HalfTy; else { Diag(Tok.getLocation(), diag::err_half_const_requires_fp16); @@ -3380,10 +3405,13 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Ty == Context.DoubleTy) { if (getLangOpts().SinglePrecisionConstants) { - Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); + const BuiltinType *BTy = Ty->getAs<BuiltinType>(); + if (BTy->getKind() != BuiltinType::Float) { + Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); + } } else if (getLangOpts().OpenCL && - !((getLangOpts().OpenCLVersion >= 120) || - getOpenCLOptions().cl_khr_fp64)) { + !getOpenCLOptions().isEnabled("cl_khr_fp64")) { + // Impose single-precision float type when cl_khr_fp64 is not enabled. Diag(Tok.getLocation(), diag::warn_double_const_requires_fp64); Res = ImpCastExprToType(Res, Context.FloatTy, CK_FloatingCast).get(); } @@ -3493,7 +3521,7 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { // To be compatible with MSVC, hex integer literals ending with the // LL or i64 suffix are always signed in Microsoft mode. if (!Literal.isUnsigned && (ResultVal[LongLongSize-1] == 0 || - (getLangOpts().MicrosoftExt && Literal.isLongLong))) + (getLangOpts().MSVCCompat && Literal.isLongLong))) Ty = Context.LongLongTy; else if (AllowUnsigned) Ty = Context.UnsignedLongLongTy; @@ -3852,6 +3880,7 @@ static void captureVariablyModifiedType(ASTContext &Context, QualType T, case Type::ObjCObject: case Type::ObjCInterface: case Type::ObjCObjectPointer: + case Type::ObjCTypeParam: case Type::Pipe: llvm_unreachable("type class is never variably-modified!"); case Type::Adjusted: @@ -4304,14 +4333,13 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, diag::err_omp_section_incomplete_type, Base)) return ExprError(); - if (LowerBound) { + if (LowerBound && !OriginalTy->isAnyPointerType()) { llvm::APSInt LowerBoundValue; if (LowerBound->EvaluateAsInt(LowerBoundValue, Context)) { - // OpenMP 4.0, [2.4 Array Sections] - // The lower-bound and length must evaluate to non-negative integers. + // OpenMP 4.5, [2.4 Array Sections] + // The array section must be a subset of the original array. if (LowerBoundValue.isNegative()) { - Diag(LowerBound->getExprLoc(), diag::err_omp_section_negative) - << 0 << LowerBoundValue.toString(/*Radix=*/10, /*Signed=*/true) + Diag(LowerBound->getExprLoc(), diag::err_omp_section_not_subset_of_array) << LowerBound->getSourceRange(); return ExprError(); } @@ -4321,11 +4349,11 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, if (Length) { llvm::APSInt LengthValue; if (Length->EvaluateAsInt(LengthValue, Context)) { - // OpenMP 4.0, [2.4 Array Sections] - // The lower-bound and length must evaluate to non-negative integers. + // OpenMP 4.5, [2.4 Array Sections] + // The length must evaluate to non-negative integers. if (LengthValue.isNegative()) { - Diag(Length->getExprLoc(), diag::err_omp_section_negative) - << 1 << LengthValue.toString(/*Radix=*/10, /*Signed=*/true) + Diag(Length->getExprLoc(), diag::err_omp_section_length_negative) + << LengthValue.toString(/*Radix=*/10, /*Signed=*/true) << Length->getSourceRange(); return ExprError(); } @@ -4333,7 +4361,7 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, } else if (ColonLoc.isValid() && (OriginalTy.isNull() || (!OriginalTy->isConstantArrayType() && !OriginalTy->isVariableArrayType()))) { - // OpenMP 4.0, [2.4 Array Sections] + // OpenMP 4.5, [2.4 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) @@ -4359,6 +4387,16 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, Expr *LHSExp = Base; Expr *RHSExp = Idx; + ExprValueKind VK = VK_LValue; + ExprObjectKind OK = OK_Ordinary; + + // Per C++ core issue 1213, the result is an xvalue if either operand is + // a non-lvalue array, and an lvalue otherwise. + if (getLangOpts().CPlusPlus11 && + ((LHSExp->getType()->isArrayType() && !LHSExp->isLValue()) || + (RHSExp->getType()->isArrayType() && !RHSExp->isLValue()))) + VK = VK_XValue; + // Perform default conversions. if (!LHSExp->getType()->getAs<VectorType>()) { ExprResult Result = DefaultFunctionArrayLvalueConversion(LHSExp); @@ -4372,8 +4410,6 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, RHSExp = Result.get(); QualType LHSTy = LHSExp->getType(), RHSTy = RHSExp->getType(); - ExprValueKind VK = VK_LValue; - ExprObjectKind OK = OK_Ordinary; // C99 6.5.2.1p2: the expression e1[e2] is by definition precisely equivalent // to the expression *((e1)+(e2)). This means the array "Base" may actually be @@ -4496,16 +4532,15 @@ Sema::CreateBuiltinArraySubscriptExpr(Expr *Base, SourceLocation LLoc, ArraySubscriptExpr(LHSExp, RHSExp, ResultType, VK, OK, RLoc); } -ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, - FunctionDecl *FD, - ParmVarDecl *Param) { +bool Sema::CheckCXXDefaultArgExpr(SourceLocation CallLoc, FunctionDecl *FD, + ParmVarDecl *Param) { if (Param->hasUnparsedDefaultArg()) { Diag(CallLoc, diag::err_use_of_default_argument_to_function_declared_later) << FD << cast<CXXRecordDecl>(FD->getDeclContext())->getDeclName(); Diag(UnparsedDefaultArgLocs[Param], diag::note_default_argument_declared_here); - return ExprError(); + return true; } if (Param->hasUninstantiatedDefaultArg()) { @@ -4521,11 +4556,11 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, InstantiatingTemplate Inst(*this, CallLoc, Param, MutiLevelArgList.getInnermost()); if (Inst.isInvalid()) - return ExprError(); + return true; if (Inst.isAlreadyInstantiating()) { Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD; Param->setInvalidDecl(); - return ExprError(); + return true; } ExprResult Result; @@ -4536,10 +4571,11 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // default argument expression appears. ContextRAII SavedContext(*this, FD); LocalInstantiationScope Local(*this); - Result = SubstExpr(UninstExpr, MutiLevelArgList); + Result = SubstInitializer(UninstExpr, MutiLevelArgList, + /*DirectInit*/false); } if (Result.isInvalid()) - return ExprError(); + return true; // Check the expression as an initializer for the parameter. InitializedEntity Entity @@ -4552,12 +4588,12 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, InitializationSequence InitSeq(*this, Entity, Kind, ResultE); Result = InitSeq.Perform(*this, Entity, Kind, ResultE); if (Result.isInvalid()) - return ExprError(); + return true; Result = ActOnFinishFullExpr(Result.getAs<Expr>(), Param->getOuterLocStart()); if (Result.isInvalid()) - return ExprError(); + return true; // Remember the instantiated default argument. Param->setDefaultArg(Result.getAs<Expr>()); @@ -4570,7 +4606,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, if (!Param->hasInit()) { Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD; Param->setInvalidDecl(); - return ExprError(); + return true; } // If the default expression creates temporaries, we need to @@ -4597,9 +4633,15 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // as being "referenced". MarkDeclarationsReferencedInExpr(Param->getDefaultArg(), /*SkipLocalVariables=*/true); - return CXXDefaultArgExpr::Create(Context, CallLoc, Param); + return false; } +ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, + FunctionDecl *FD, ParmVarDecl *Param) { + if (CheckCXXDefaultArgExpr(CallLoc, FD, Param)) + return ExprError(); + return CXXDefaultArgExpr::Create(Context, CallLoc, Param); +} Sema::VariadicCallType Sema::getVariadicCallType(FunctionDecl *FDecl, const FunctionProtoType *Proto, @@ -5057,7 +5099,11 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, for (QualType ParamType : FT->param_types()) { // Convert array arguments to pointer to simplify type lookup. - Expr *Arg = Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]).get(); + ExprResult ArgRes = + Sema->DefaultFunctionArrayLvalueConversion(ArgExprs[i++]); + if (ArgRes.isInvalid()) + return nullptr; + Expr *Arg = ArgRes.get(); QualType ArgType = Arg->getType(); if (!ParamType->isPointerType() || ParamType.getQualifiers().hasAddressSpace() || @@ -5116,12 +5162,11 @@ static bool isNumberOfArgsValidForCall(Sema &S, const FunctionDecl *Callee, /// ActOnCallExpr - Handle a call to Fn with the specified array of arguments. /// This provides the location of the left/right parens and a list of comma /// locations. -ExprResult -Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, - MultiExprArg ArgExprs, SourceLocation RParenLoc, - Expr *ExecConfig, bool IsExecConfig) { +ExprResult Sema::ActOnCallExpr(Scope *Scope, Expr *Fn, SourceLocation LParenLoc, + MultiExprArg ArgExprs, SourceLocation RParenLoc, + Expr *ExecConfig, bool IsExecConfig) { // Since this might be a postfix expression, get rid of ParenListExprs. - ExprResult Result = MaybeConvertParenListExprToParenExpr(S, Fn); + ExprResult Result = MaybeConvertParenListExprToParenExpr(Scope, Fn); if (Result.isInvalid()) return ExprError(); Fn = Result.get(); @@ -5134,9 +5179,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (!ArgExprs.empty()) { // Pseudo-destructor calls should not have any arguments. Diag(Fn->getLocStart(), diag::err_pseudo_dtor_call_with_args) - << FixItHint::CreateRemoval( - SourceRange(ArgExprs.front()->getLocStart(), - ArgExprs.back()->getLocEnd())); + << FixItHint::CreateRemoval( + SourceRange(ArgExprs.front()->getLocStart(), + ArgExprs.back()->getLocEnd())); } return new (Context) @@ -5169,7 +5214,7 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, // Determine whether this is a call to an object (C++ [over.call.object]). if (Fn->getType()->isRecordType()) - return BuildCallToObjectOfClassType(S, Fn, LParenLoc, ArgExprs, + return BuildCallToObjectOfClassType(Scope, Fn, LParenLoc, ArgExprs, RParenLoc); if (Fn->getType() == Context.UnknownAnyTy) { @@ -5179,7 +5224,8 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, } if (Fn->getType() == Context.BoundMemberTy) { - return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc); + return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, + RParenLoc); } } @@ -5187,15 +5233,16 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, if (Fn->getType() == Context.OverloadTy) { OverloadExpr::FindResult find = OverloadExpr::find(Fn); - // We aren't supposed to apply this logic for if there's an '&' involved. + // We aren't supposed to apply this logic for if there'Scope an '&' + // involved. if (!find.HasFormOfMemberPointer) { OverloadExpr *ovl = find.Expression; if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(ovl)) - return BuildOverloadedCallExpr(S, Fn, ULE, LParenLoc, ArgExprs, - RParenLoc, ExecConfig, - /*AllowTypoCorrection=*/true, - find.IsAddressOfOperand); - return BuildCallToMemberFunction(S, Fn, LParenLoc, ArgExprs, RParenLoc); + return BuildOverloadedCallExpr( + Scope, Fn, ULE, LParenLoc, ArgExprs, RParenLoc, ExecConfig, + /*AllowTypoCorrection=*/true, find.IsAddressOfOperand); + return BuildCallToMemberFunction(Scope, Fn, LParenLoc, ArgExprs, + RParenLoc); } } @@ -5225,12 +5272,12 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, // Rewrite the function decl for this builtin by replacing parameters // with no explicit address space with the address space of the arguments // in ArgExprs. - if ((FDecl = rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { + if ((FDecl = + rewriteBuiltinFunctionDecl(this, Context, FDecl, ArgExprs))) { NDecl = FDecl; - Fn = DeclRefExpr::Create(Context, FDecl->getQualifierLoc(), - SourceLocation(), FDecl, false, - SourceLocation(), FDecl->getType(), - Fn->getValueKind(), FDecl); + Fn = DeclRefExpr::Create( + Context, FDecl->getQualifierLoc(), SourceLocation(), FDecl, false, + SourceLocation(), FDecl->getType(), Fn->getValueKind(), FDecl); } } } else if (isa<MemberExpr>(NakedFn)) @@ -5242,6 +5289,9 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, Fn->getLocStart())) return ExprError(); + if (getLangOpts().OpenCL && checkOpenCLDisabledDecl(*FD, *Fn)) + return ExprError(); + // CheckEnableIf assumes that the we're passing in a sane number of args for // FD, but that doesn't always hold true here. This is because, in some // cases, we'll emit a diag about an ill-formed function call, but then @@ -5252,10 +5302,10 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, isNumberOfArgsValidForCall(*this, FD, ArgExprs.size())) { if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) { Diag(Fn->getLocStart(), - isa<CXXMethodDecl>(FD) ? - diag::err_ovl_no_viable_member_function_in_call : - diag::err_ovl_no_viable_function_in_call) - << FD << FD->getSourceRange(); + isa<CXXMethodDecl>(FD) + ? diag::err_ovl_no_viable_member_function_in_call + : diag::err_ovl_no_viable_function_in_call) + << FD << FD->getSourceRange(); Diag(FD->getLocation(), diag::note_ovl_candidate_disabled_by_enable_if_attr) << Attr->getCond()->getSourceRange() << Attr->getMessage(); @@ -5549,7 +5599,7 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, return ExprError(); LiteralExpr = Result.get(); - bool isFileScope = getCurFunctionOrMethodDecl() == nullptr; + bool isFileScope = !CurContext->isFunctionOrMethod(); if (isFileScope && !LiteralExpr->isTypeDependent() && !LiteralExpr->isValueDependent() && @@ -5559,11 +5609,31 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, TypeSourceInfo *TInfo, } // In C, compound literals are l-values for some reason. - ExprValueKind VK = getLangOpts().CPlusPlus ? VK_RValue : VK_LValue; + // For GCC compatibility, in C++, file-scope array compound literals with + // constant initializers are also l-values, and compound literals are + // otherwise prvalues. + // + // (GCC also treats C++ list-initialized file-scope array prvalues with + // constant initializers as l-values, but that's non-conforming, so we don't + // follow it there.) + // + // FIXME: It would be better to handle the lvalue cases as materializing and + // lifetime-extending a temporary object, but our materialized temporaries + // representation only supports lifetime extension from a variable, not "out + // of thin air". + // FIXME: For C++, we might want to instead lifetime-extend only if a pointer + // is bound to the result of applying array-to-pointer decay to the compound + // literal. + // FIXME: GCC supports compound literals of reference type, which should + // obviously have a value kind derived from the kind of reference involved. + ExprValueKind VK = + (getLangOpts().CPlusPlus && !(isFileScope && literalType->isArrayType())) + ? VK_RValue + : VK_LValue; return MaybeBindToTemporary( - new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, - VK, LiteralExpr, isFileScope)); + new (Context) CompoundLiteralExpr(LParenLoc, TInfo, literalType, + VK, LiteralExpr, isFileScope)); } ExprResult @@ -6006,7 +6076,9 @@ Sema::ActOnCastExpr(Scope *S, SourceLocation LParenLoc, CheckTollFreeBridgeCast(castType, CastExpr); CheckObjCBridgeRelatedCast(castType, CastExpr); - + + DiscardMisalignedMemberAddress(castType.getTypePtr(), CastExpr); + return BuildCStyleCastExpr(LParenLoc, castTInfo, RParenLoc, CastExpr); } @@ -7007,6 +7079,55 @@ static void DiagnoseConditionalPrecedence(Sema &Self, SourceRange(CondRHS->getLocStart(), RHSExpr->getLocEnd())); } +/// Compute the nullability of a conditional expression. +static QualType computeConditionalNullability(QualType ResTy, bool IsBin, + QualType LHSTy, QualType RHSTy, + ASTContext &Ctx) { + if (!ResTy->isAnyPointerType()) + return ResTy; + + auto GetNullability = [&Ctx](QualType Ty) { + Optional<NullabilityKind> Kind = Ty->getNullability(Ctx); + if (Kind) + return *Kind; + return NullabilityKind::Unspecified; + }; + + auto LHSKind = GetNullability(LHSTy), RHSKind = GetNullability(RHSTy); + NullabilityKind MergedKind; + + // Compute nullability of a binary conditional expression. + if (IsBin) { + if (LHSKind == NullabilityKind::NonNull) + MergedKind = NullabilityKind::NonNull; + else + MergedKind = RHSKind; + // Compute nullability of a normal conditional expression. + } else { + if (LHSKind == NullabilityKind::Nullable || + RHSKind == NullabilityKind::Nullable) + MergedKind = NullabilityKind::Nullable; + else if (LHSKind == NullabilityKind::NonNull) + MergedKind = RHSKind; + else if (RHSKind == NullabilityKind::NonNull) + MergedKind = LHSKind; + else + MergedKind = NullabilityKind::Unspecified; + } + + // Return if ResTy already has the correct nullability. + if (GetNullability(ResTy) == MergedKind) + return ResTy; + + // Strip all nullability from ResTy. + while (ResTy->getNullability(Ctx)) + ResTy = ResTy.getSingleStepDesugaredType(Ctx); + + // Create a new AttributedType with the new nullability kind. + auto NewAttr = AttributedType::getNullabilityAttrKind(MergedKind); + return Ctx.getAttributedType(NewAttr, ResTy, ResTy); +} + /// ActOnConditionalOp - Parse a ?: operation. Note that 'LHS' may be null /// in the case of a the GNU conditional expr extension. ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, @@ -7074,6 +7195,7 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, LHSExpr = CondExpr = opaqueValue; } + QualType LHSTy = LHSExpr->getType(), RHSTy = RHSExpr->getType(); ExprValueKind VK = VK_RValue; ExprObjectKind OK = OK_Ordinary; ExprResult Cond = CondExpr, LHS = LHSExpr, RHS = RHSExpr; @@ -7088,6 +7210,9 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, CheckBoolLikeConversion(Cond.get(), QuestionLoc); + result = computeConditionalNullability(result, commonExpr, LHSTy, RHSTy, + Context); + if (!commonExpr) return new (Context) ConditionalOperator(Cond.get(), QuestionLoc, LHS.get(), ColonLoc, @@ -7218,7 +7343,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { return Sema::IncompatiblePointer; } if (!S.getLangOpts().CPlusPlus && - S.IsNoReturnConversion(ltrans, rtrans, ltrans)) + S.IsFunctionConversion(ltrans, rtrans, ltrans)) return Sema::IncompatiblePointer; return ConvTy; } @@ -7603,6 +7728,11 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, } } + if (LHSType->isSamplerT() && RHSType->isIntegerType()) { + Kind = CK_IntToOCLSampler; + return Compatible; + } + return Incompatible; } @@ -7683,6 +7813,10 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, bool Diagnose, bool DiagnoseCFAudited, bool ConvertRHS) { + // We need to be able to tell the caller whether we diagnosed a problem, if + // they ask us to issue diagnostics. + assert((ConvertRHS || !Diagnose) && "can't indicate whether we diagnosed"); + // If ConvertRHS is false, we want to leave the caller's RHS untouched. Sadly, // we can't avoid *all* modifications at the moment, so we need some somewhere // to put the updated value. @@ -7694,9 +7828,9 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, // C++ 5.17p3: If the left operand is not of class type, the // expression is implicitly converted (C++ 4) to the // cv-unqualified type of the left operand. - ExprResult Res; + QualType RHSType = RHS.get()->getType(); if (Diagnose) { - Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), + RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), AA_Assigning); } else { ImplicitConversionSequence ICS = @@ -7708,17 +7842,15 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, /*AllowObjCWritebackConversion=*/false); if (ICS.isFailure()) return Incompatible; - Res = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), + RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(), ICS, AA_Assigning); } - if (Res.isInvalid()) + if (RHS.isInvalid()) return Incompatible; Sema::AssignConvertType result = Compatible; if (getLangOpts().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(LHSType, - RHS.get()->getType())) + !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType)) result = IncompatibleObjCWeakRef; - RHS = Res; return result; } @@ -7942,6 +8074,7 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, // If there's an ext-vector type and a scalar, try to convert the scalar to // the vector element type and splat. + // FIXME: this should also work for regular vector types as supported in GCC. if (!RHSVecType && isa<ExtVectorType>(LHSVecType)) { if (!tryVectorConvertAndSplat(*this, &RHS, RHSType, LHSVecType->getElementType(), LHSType)) @@ -7954,16 +8087,31 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS, return RHSType; } - // If we're allowing lax vector conversions, only the total (data) size needs - // to be the same. If one of the types is scalar, the result is always the - // vector type. Don't allow this if the scalar operand is an lvalue. + // FIXME: The code below also handles convertion between vectors and + // non-scalars, we should break this down into fine grained specific checks + // and emit proper diagnostics. QualType VecType = LHSVecType ? LHSType : RHSType; - QualType ScalarType = LHSVecType ? RHSType : LHSType; - ExprResult *ScalarExpr = LHSVecType ? &RHS : &LHS; - if (isLaxVectorConversion(ScalarType, VecType) && - !ScalarExpr->get()->isLValue()) { - *ScalarExpr = ImpCastExprToType(ScalarExpr->get(), VecType, CK_BitCast); - return VecType; + const VectorType *VT = LHSVecType ? LHSVecType : RHSVecType; + QualType OtherType = LHSVecType ? RHSType : LHSType; + ExprResult *OtherExpr = LHSVecType ? &RHS : &LHS; + if (isLaxVectorConversion(OtherType, VecType)) { + // If we're allowing lax vector conversions, only the total (data) size + // needs to be the same. For non compound assignment, if one of the types is + // scalar, the result is always the vector type. + if (!IsCompAssign) { + *OtherExpr = ImpCastExprToType(OtherExpr->get(), VecType, CK_BitCast); + return VecType; + // In a compound assignment, lhs += rhs, 'lhs' is a lvalue src, forbidding + // any implicit cast. Here, the 'rhs' should be implicit casted to 'lhs' + // type. Note that this is already done by non-compound assignments in + // CheckAssignmentConstraints. If it's a scalar type, only bitcast for + // <1 x T> -> T. The result is also a vector type. + } else if (OtherType->isExtVectorType() || + (OtherType->isScalarType() && VT->getNumElements() == 1)) { + ExprResult *RHSExpr = &RHS; + *RHSExpr = ImpCastExprToType(RHSExpr->get(), LHSType, CK_BitCast); + return VecType; + } } // Okay, the expression is invalid. @@ -8608,13 +8756,13 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, << RHS.get()->getSourceRange(); } -/// \brief Return the resulting type when an OpenCL vector is shifted +/// \brief Return the resulting type when a vector is shifted /// by a scalar or vector shift amount. -static QualType checkOpenCLVectorShift(Sema &S, - ExprResult &LHS, ExprResult &RHS, - SourceLocation Loc, bool IsCompAssign) { +static QualType checkVectorShift(Sema &S, ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, bool IsCompAssign) { // OpenCL v1.1 s6.3.j says RHS can be a vector only if LHS is a vector. - if (!LHS.get()->getType()->isVectorType()) { + if ((S.LangOpts.OpenCL || S.LangOpts.ZVector) && + !LHS.get()->getType()->isVectorType()) { S.Diag(Loc, diag::err_shift_rhs_only_vector) << RHS.get()->getType() << LHS.get()->getType() << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); @@ -8630,15 +8778,17 @@ static QualType checkOpenCLVectorShift(Sema &S, if (RHS.isInvalid()) return QualType(); QualType LHSType = LHS.get()->getType(); - const VectorType *LHSVecTy = LHSType->castAs<VectorType>(); - QualType LHSEleType = LHSVecTy->getElementType(); + // Note that LHS might be a scalar because the routine calls not only in + // OpenCL case. + const VectorType *LHSVecTy = LHSType->getAs<VectorType>(); + QualType LHSEleType = LHSVecTy ? LHSVecTy->getElementType() : LHSType; // Note that RHS might not be a vector. QualType RHSType = RHS.get()->getType(); const VectorType *RHSVecTy = RHSType->getAs<VectorType>(); QualType RHSEleType = RHSVecTy ? RHSVecTy->getElementType() : RHSType; - // OpenCL v1.1 s6.3.j says that the operands need to be integers. + // The operands need to be integers. if (!LHSEleType->isIntegerType()) { S.Diag(Loc, diag::err_typecheck_expect_int) << LHS.get()->getType() << LHS.get()->getSourceRange(); @@ -8651,7 +8801,19 @@ static QualType checkOpenCLVectorShift(Sema &S, return QualType(); } - if (RHSVecTy) { + if (!LHSVecTy) { + assert(RHSVecTy); + if (IsCompAssign) + return RHSType; + if (LHSEleType != RHSEleType) { + LHS = S.ImpCastExprToType(LHS.get(),RHSEleType, CK_IntegralCast); + LHSEleType = RHSEleType; + } + QualType VecTy = + S.Context.getExtVectorType(LHSEleType, RHSVecTy->getNumElements()); + LHS = S.ImpCastExprToType(LHS.get(), VecTy, CK_VectorSplat); + LHSType = VecTy; + } else if (RHSVecTy) { // OpenCL v1.1 s6.3.j says that for vector types, the operators // are applied component-wise. So if RHS is a vector, then ensure // that the number of elements is the same as LHS... @@ -8661,6 +8823,16 @@ static QualType checkOpenCLVectorShift(Sema &S, << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); return QualType(); } + if (!S.LangOpts.OpenCL && !S.LangOpts.ZVector) { + const BuiltinType *LHSBT = LHSEleType->getAs<clang::BuiltinType>(); + const BuiltinType *RHSBT = RHSEleType->getAs<clang::BuiltinType>(); + if (LHSBT != RHSBT && + S.Context.getTypeSize(LHSBT) != S.Context.getTypeSize(RHSBT)) { + S.Diag(Loc, diag::warn_typecheck_vector_element_sizes_not_equal) + << LHS.get()->getType() << RHS.get()->getType() + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + } + } } else { // ...else expand RHS to match the number of elements in LHS. QualType VecTy = @@ -8680,11 +8852,9 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, // Vector shifts promote their scalar inputs to vector type. if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { - if (LangOpts.OpenCL) - return checkOpenCLVectorShift(*this, LHS, RHS, Loc, IsCompAssign); if (LangOpts.ZVector) { // The shift operators for the z vector extensions work basically - // like OpenCL shifts, except that neither the LHS nor the RHS is + // like general shifts, except that neither the LHS nor the RHS is // allowed to be a "vector bool". if (auto LHSVecType = LHS.get()->getType()->getAs<VectorType>()) if (LHSVecType->getVectorKind() == VectorType::AltiVecBool) @@ -8692,11 +8862,8 @@ QualType Sema::CheckShiftOperands(ExprResult &LHS, ExprResult &RHS, if (auto RHSVecType = RHS.get()->getType()->getAs<VectorType>()) if (RHSVecType->getVectorKind() == VectorType::AltiVecBool) return InvalidOperands(Loc, LHS, RHS); - return checkOpenCLVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } - return CheckVectorOperands(LHS, RHS, Loc, IsCompAssign, - /*AllowBothBool*/true, - /*AllowBoolConversions*/false); + return checkVectorShift(*this, LHS, RHS, Loc, IsCompAssign); } // Shifts don't perform usual arithmetic conversions, they just do integer @@ -8795,35 +8962,21 @@ static bool convertPointersToCompositeType(Sema &S, SourceLocation Loc, // C++ [expr.eq]p1 uses the same notion for (in)equality // comparisons of pointers. - // C++ [expr.eq]p2: - // In addition, pointers to members can be compared, or a pointer to - // member and a null pointer constant. Pointer to member conversions - // (4.11) and qualification conversions (4.4) are performed to bring - // them to a common type. If one operand is a null pointer constant, - // the common type is the type of the other operand. Otherwise, the - // common type is a pointer to member type similar (4.4) to the type - // of one of the operands, with a cv-qualification signature (4.4) - // that is the union of the cv-qualification signatures of the operand - // types. - QualType LHSType = LHS.get()->getType(); QualType RHSType = RHS.get()->getType(); - assert((LHSType->isPointerType() && RHSType->isPointerType()) || - (LHSType->isMemberPointerType() && RHSType->isMemberPointerType())); + assert(LHSType->isPointerType() || RHSType->isPointerType() || + LHSType->isMemberPointerType() || RHSType->isMemberPointerType()); - bool NonStandardCompositeType = false; - bool *BoolPtr = S.isSFINAEContext() ? nullptr : &NonStandardCompositeType; - QualType T = S.FindCompositePointerType(Loc, LHS, RHS, BoolPtr); + QualType T = S.FindCompositePointerType(Loc, LHS, RHS); if (T.isNull()) { - diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); + if ((LHSType->isPointerType() || LHSType->isMemberPointerType()) && + (RHSType->isPointerType() || RHSType->isMemberPointerType())) + diagnoseDistinctPointerComparison(S, Loc, LHS, RHS, /*isError*/true); + else + S.InvalidOperands(Loc, LHS, RHS); return true; } - if (NonStandardCompositeType) - S.Diag(Loc, diag::ext_typecheck_comparison_of_distinct_pointers_nonstandard) - << LHSType << RHSType << T << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); - LHS = S.ImpCastExprToType(LHS.get(), T, CK_BitCast); RHS = S.ImpCastExprToType(RHS.get(), T, CK_BitCast); return false; @@ -8989,10 +9142,10 @@ static void diagnoseObjCLiteralComparison(Sema &S, SourceLocation Loc, } } -static void diagnoseLogicalNotOnLHSofComparison(Sema &S, ExprResult &LHS, - ExprResult &RHS, - SourceLocation Loc, - BinaryOperatorKind Opc) { +/// Warns on !x < y, !x & y where !(x < y), !(x & y) was probably intended. +static void diagnoseLogicalNotOnLHSofCheck(Sema &S, ExprResult &LHS, + ExprResult &RHS, SourceLocation Loc, + BinaryOperatorKind Opc) { // Check that left hand side is !something. UnaryOperator *UO = dyn_cast<UnaryOperator>(LHS.get()->IgnoreImpCasts()); if (!UO || UO->getOpcode() != UO_LNot) return; @@ -9005,8 +9158,9 @@ static void diagnoseLogicalNotOnLHSofComparison(Sema &S, ExprResult &LHS, if (SubExpr->isKnownToHaveBooleanValue()) return; // Emit warning. - S.Diag(UO->getOperatorLoc(), diag::warn_logical_not_on_lhs_of_comparison) - << Loc; + bool IsBitwiseOp = Opc == BO_And || Opc == BO_Or || Opc == BO_Xor; + S.Diag(UO->getOperatorLoc(), diag::warn_logical_not_on_lhs_of_check) + << Loc << IsBitwiseOp; // First note suggest !(x < y) SourceLocation FirstOpen = SubExpr->getLocStart(); @@ -9015,6 +9169,7 @@ static void diagnoseLogicalNotOnLHSofComparison(Sema &S, ExprResult &LHS, if (FirstClose.isInvalid()) FirstOpen = SourceLocation(); S.Diag(UO->getOperatorLoc(), diag::note_logical_not_fix) + << IsBitwiseOp << FixItHint::CreateInsertion(FirstOpen, "(") << FixItHint::CreateInsertion(FirstClose, ")"); @@ -9063,7 +9218,7 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, Expr *RHSStripped = RHS.get()->IgnoreParenImpCasts(); checkEnumComparison(*this, Loc, LHS.get(), RHS.get()); - diagnoseLogicalNotOnLHSofComparison(*this, LHS, RHS, Loc, Opc); + diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); if (!LHSType->hasFloatingRepresentation() && !(LHSType->isBlockPointerType() && IsRelational) && @@ -9180,41 +9335,53 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, LHS.get()->getSourceRange()); } - // All of the following pointer-related warnings are GCC extensions, except - // when handling null pointer constants. - if (LHSType->isPointerType() && RHSType->isPointerType()) { // C99 6.5.8p2 - QualType LCanPointeeTy = - LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); - QualType RCanPointeeTy = - RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); - - if (getLangOpts().CPlusPlus) { - if (LCanPointeeTy == RCanPointeeTy) - return ResultTy; - if (!IsRelational && - (LCanPointeeTy->isVoidType() || RCanPointeeTy->isVoidType())) { - // Valid unless comparison between non-null pointer and function pointer - // This is a gcc extension compatibility comparison. - // In a SFINAE context, we treat this as a hard error to maintain - // conformance with the C++ standard. - if ((LCanPointeeTy->isFunctionType() || RCanPointeeTy->isFunctionType()) - && !LHSIsNull && !RHSIsNull) { - diagnoseFunctionPointerToVoidComparison( - *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext()); - - if (isSFINAEContext()) - return QualType(); - - RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); - return ResultTy; - } - } + if ((LHSType->isIntegerType() && !LHSIsNull) || + (RHSType->isIntegerType() && !RHSIsNull)) { + // Skip normal pointer conversion checks in this case; we have better + // diagnostics for this below. + } else if (getLangOpts().CPlusPlus) { + // Equality comparison of a function pointer to a void pointer is invalid, + // but we allow it as an extension. + // FIXME: If we really want to allow this, should it be part of composite + // pointer type computation so it works in conditionals too? + if (!IsRelational && + ((LHSType->isFunctionPointerType() && RHSType->isVoidPointerType()) || + (RHSType->isFunctionPointerType() && LHSType->isVoidPointerType()))) { + // This is a gcc extension compatibility comparison. + // In a SFINAE context, we treat this as a hard error to maintain + // conformance with the C++ standard. + diagnoseFunctionPointerToVoidComparison( + *this, Loc, LHS, RHS, /*isError*/ (bool)isSFINAEContext()); + + if (isSFINAEContext()) + return QualType(); + + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_BitCast); + return ResultTy; + } + // C++ [expr.eq]p2: + // If at least one operand is a pointer [...] bring them to their + // composite pointer type. + // C++ [expr.rel]p2: + // If both operands are pointers, [...] bring them to their composite + // pointer type. + if ((int)LHSType->isPointerType() + (int)RHSType->isPointerType() >= + (IsRelational ? 2 : 1)) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); else return ResultTy; } + } else if (LHSType->isPointerType() && + RHSType->isPointerType()) { // C99 6.5.8p2 + // All of the following pointer-related warnings are GCC extensions, except + // when handling null pointer constants. + QualType LCanPointeeTy = + LHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); + QualType RCanPointeeTy = + RHSType->castAs<PointerType>()->getPointeeType().getCanonicalType(); + // C99 6.5.9p2 and C99 6.5.8p2 if (Context.typesAreCompatible(LCanPointeeTy.getUnqualifiedType(), RCanPointeeTy.getUnqualifiedType())) { @@ -9259,36 +9426,63 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, } if (getLangOpts().CPlusPlus) { - // Comparison of nullptr_t with itself. - if (LHSType->isNullPtrType() && RHSType->isNullPtrType()) - return ResultTy; - - // Comparison of pointers with null pointer constants and equality - // comparisons of member pointers to null pointer constants. - if (RHSIsNull && - ((LHSType->isAnyPointerType() || LHSType->isNullPtrType()) || - (!IsRelational && - (LHSType->isMemberPointerType() || LHSType->isBlockPointerType())))) { - RHS = ImpCastExprToType(RHS.get(), LHSType, - LHSType->isMemberPointerType() - ? CK_NullToMemberPointer - : CK_NullToPointer); + // C++ [expr.eq]p4: + // Two operands of type std::nullptr_t or one operand of type + // std::nullptr_t and the other a null pointer constant compare equal. + if (!IsRelational && LHSIsNull && RHSIsNull) { + if (LHSType->isNullPtrType()) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return ResultTy; + } + if (RHSType->isNullPtrType()) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return ResultTy; + } + } + + // Comparison of Objective-C pointers and block pointers against nullptr_t. + // These aren't covered by the composite pointer type rules. + if (!IsRelational && RHSType->isNullPtrType() && + (LHSType->isObjCObjectPointerType() || LHSType->isBlockPointerType())) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); return ResultTy; } - if (LHSIsNull && - ((RHSType->isAnyPointerType() || RHSType->isNullPtrType()) || - (!IsRelational && - (RHSType->isMemberPointerType() || RHSType->isBlockPointerType())))) { - LHS = ImpCastExprToType(LHS.get(), RHSType, - RHSType->isMemberPointerType() - ? CK_NullToMemberPointer - : CK_NullToPointer); + if (!IsRelational && LHSType->isNullPtrType() && + (RHSType->isObjCObjectPointerType() || RHSType->isBlockPointerType())) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); return ResultTy; } - // Comparison of member pointers. + if (IsRelational && + ((LHSType->isNullPtrType() && RHSType->isPointerType()) || + (RHSType->isNullPtrType() && LHSType->isPointerType()))) { + // HACK: Relational comparison of nullptr_t against a pointer type is + // invalid per DR583, but we allow it within std::less<> and friends, + // since otherwise common uses of it break. + // FIXME: Consider removing this hack once LWG fixes std::less<> and + // friends to have std::nullptr_t overload candidates. + DeclContext *DC = CurContext; + if (isa<FunctionDecl>(DC)) + DC = DC->getParent(); + if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(DC)) { + if (CTSD->isInStdNamespace() && + llvm::StringSwitch<bool>(CTSD->getName()) + .Cases("less", "less_equal", "greater", "greater_equal", true) + .Default(false)) { + if (RHSType->isNullPtrType()) + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + else + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return ResultTy; + } + } + } + + // C++ [expr.eq]p2: + // If at least one operand is a pointer to member, [...] bring them to + // their composite pointer type. if (!IsRelational && - LHSType->isMemberPointerType() && RHSType->isMemberPointerType()) { + (LHSType->isMemberPointerType() || RHSType->isMemberPointerType())) { if (convertPointersToCompositeType(*this, Loc, LHS, RHS)) return QualType(); else @@ -9397,15 +9591,19 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, // Under a debugger, allow the comparison of pointers to integers, // since users tend to want to compare addresses. } else if ((LHSIsNull && LHSType->isIntegerType()) || - (RHSIsNull && RHSType->isIntegerType())) { - if (IsRelational && !getLangOpts().CPlusPlus) - DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; - } else if (IsRelational && !getLangOpts().CPlusPlus) - DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; - else if (getLangOpts().CPlusPlus) { + (RHSIsNull && RHSType->isIntegerType())) { + if (IsRelational) { + isError = getLangOpts().CPlusPlus; + DiagID = + isError ? diag::err_typecheck_ordered_comparison_of_pointer_and_zero + : diag::ext_typecheck_ordered_comparison_of_pointer_and_zero; + } + } else if (getLangOpts().CPlusPlus) { DiagID = diag::err_typecheck_comparison_of_pointer_integer; isError = true; - } else + } else if (IsRelational) + DiagID = diag::ext_typecheck_ordered_comparison_of_pointer_integer; + else DiagID = diag::ext_typecheck_comparison_of_pointer_integer; if (DiagID) { @@ -9437,6 +9635,18 @@ QualType Sema::CheckCompareOperands(ExprResult &LHS, ExprResult &RHS, return ResultTy; } + if (getLangOpts().OpenCLVersion >= 200) { + if (LHSIsNull && RHSType->isQueueT()) { + LHS = ImpCastExprToType(LHS.get(), RHSType, CK_NullToPointer); + return ResultTy; + } + + if (LHSType->isQueueT() && RHSIsNull) { + RHS = ImpCastExprToType(RHS.get(), LHSType, CK_NullToPointer); + return ResultTy; + } + } + return InvalidOperands(Loc, LHS, RHS); } @@ -9526,10 +9736,14 @@ QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, return GetSignedVectorType(LHS.get()->getType()); } -inline QualType Sema::CheckBitwiseOperands( - ExprResult &LHS, ExprResult &RHS, SourceLocation Loc, bool IsCompAssign) { +inline QualType Sema::CheckBitwiseOperands(ExprResult &LHS, ExprResult &RHS, + SourceLocation Loc, + BinaryOperatorKind Opc) { checkArithmeticNull(*this, LHS, RHS, Loc, /*isCompare=*/false); + bool IsCompAssign = + Opc == BO_AndAssign || Opc == BO_OrAssign || Opc == BO_XorAssign; + if (LHS.get()->getType()->isVectorType() || RHS.get()->getType()->isVectorType()) { if (LHS.get()->getType()->hasIntegerRepresentation() && @@ -9540,6 +9754,9 @@ inline QualType Sema::CheckBitwiseOperands( return InvalidOperands(Loc, LHS, RHS); } + if (Opc == BO_And) + diagnoseLogicalNotOnLHSofCheck(*this, LHS, RHS, Loc, Opc); + ExprResult LHSResult = LHS, RHSResult = RHS; QualType compType = UsualArithmeticConversions(LHSResult, RHSResult, IsCompAssign); @@ -9647,8 +9864,8 @@ static bool IsReadonlyMessage(Expr *E, Sema &S) { const MemberExpr *ME = dyn_cast<MemberExpr>(E); if (!ME) return false; if (!isa<FieldDecl>(ME->getMemberDecl())) return false; - ObjCMessageExpr *Base = - dyn_cast<ObjCMessageExpr>(ME->getBase()->IgnoreParenImpCasts()); + ObjCMessageExpr *Base = dyn_cast<ObjCMessageExpr>( + ME->getBase()->IgnoreImplicit()->IgnoreParenImpCasts()); if (!Base) return false; return Base->getMethodDecl() != nullptr; } @@ -9722,17 +9939,16 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, // a note to the error. bool DiagnosticEmitted = false; - // Track if the current expression is the result of a derefence, and if the - // next checked expression is the result of a derefence. + // Track if the current expression is the result of a dereference, and if the + // next checked expression is the result of a dereference. bool IsDereference = false; bool NextIsDereference = false; // Loop to process MemberExpr chains. while (true) { IsDereference = NextIsDereference; - NextIsDereference = false; - E = E->IgnoreParenImpCasts(); + E = E->IgnoreImplicit()->IgnoreParenImpCasts(); if (const MemberExpr *ME = dyn_cast<MemberExpr>(E)) { NextIsDereference = ME->isArrow(); const ValueDecl *VD = ME->getMemberDecl(); @@ -9930,10 +10146,10 @@ static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { case Expr::MLV_NoSetterProperty: llvm_unreachable("readonly properties should be processed differently"); case Expr::MLV_InvalidMessageExpression: - DiagID = diag::error_readonly_message_assignment; + DiagID = diag::err_readonly_message_assignment; break; case Expr::MLV_SubObjCPropertySetting: - DiagID = diag::error_no_subobject_property_setting; + DiagID = diag::err_no_subobject_property_setting; break; } @@ -9982,6 +10198,16 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, QualType LHSType = LHSExpr->getType(); QualType RHSType = CompoundType.isNull() ? RHS.get()->getType() : CompoundType; + // OpenCL v1.2 s6.1.1.1 p2: + // The half data type can only be used to declare a pointer to a buffer that + // contains half values + if (getLangOpts().OpenCL && !getOpenCLOptions().isEnabled("cl_khr_fp16") && + LHSType->isHalfType()) { + Diag(Loc, diag::err_opencl_half_load_store) << 1 + << LHSType.getUnqualifiedType(); + return QualType(); + } + AssignConvertType ConvTy; if (CompoundType.isNull()) { Expr *RHSCheck = RHS.get(); @@ -10519,7 +10745,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { return MPTy; } } - } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl)) + } else if (!isa<FunctionDecl>(dcl) && !isa<NonTypeTemplateParmDecl>(dcl) && + !isa<BindingDecl>(dcl)) llvm_unreachable("Unknown/unexpected decl type"); } @@ -10539,6 +10766,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + CheckAddressOfPackedMember(op); + return Context.getPointerType(op->getType()); } @@ -10895,7 +11124,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, checkObjCPointerIntrospection(*this, LHS, RHS, OpLoc); case BO_Xor: case BO_Or: - ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc); + ResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); break; case BO_LAnd: case BO_LOr: @@ -10936,7 +11165,7 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, case BO_OrAssign: // fallthrough DiagnoseSelfAssignment(*this, LHS.get(), RHS.get(), OpLoc); case BO_XorAssign: - CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, true); + CompResultTy = CheckBitwiseOperands(LHS, RHS, OpLoc, Opc); CompLHSTy = CompResultTy; if (!CompResultTy.isNull() && !LHS.isInvalid() && !RHS.isInvalid()) ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, CompResultTy); @@ -12428,10 +12657,14 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, MayHaveConvFixit = true; break; case IncompatiblePointer: - DiagKind = - (Action == AA_Passing_CFAudited ? - diag::err_arc_typecheck_convert_incompatible_pointer : - diag::ext_typecheck_convert_incompatible_pointer); + 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 + DiagKind = diag::ext_typecheck_convert_incompatible_pointer; + CheckInferredResultType = DstType->isObjCObjectPointerType() && SrcType->isObjCObjectPointerType(); if (Hint.isNull() && !CheckInferredResultType) { @@ -12582,7 +12815,7 @@ bool Sema::DiagnoseAssignmentResult(AssignConvertType ConvTy, Diag(Loc, FDiag); if (DiagKind == diag::warn_incompatible_qualified_id && PDecl && IFace && !IFace->hasDefinition()) - Diag(IFace->getLocation(), diag::not_incomplete_class_and_qualified_id) + Diag(IFace->getLocation(), diag::note_incomplete_class_and_qualified_id) << IFace->getName() << PDecl->getName(); if (SecondType == Context.OverloadTy) @@ -13005,6 +13238,19 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, Func->getMemberSpecializationInfo())) checkSpecializationVisibility(Loc, Func); + // C++14 [except.spec]p17: + // An exception-specification is considered to be needed when: + // - the function is odr-used or, if it appears in an unevaluated operand, + // would be odr-used if the expression were potentially-evaluated; + // + // Note, we do this even if MightBeOdrUse is false. That indicates that the + // function is a pure virtual function we're calling, and in that case the + // function was selected by overload resolution and we need to resolve its + // exception specification for a different reason. + const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); + if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) + ResolveExceptionSpec(Loc, FPT); + // If we don't need to mark the function as used, and we don't need to // try to provide a definition, there's nothing more to do. if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) && @@ -13063,12 +13309,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // FIXME: Is this really right? if (CurContext == Func) return; - // Resolve the exception specification for any function which is - // used: CodeGen will need it. - const FunctionProtoType *FPT = Func->getType()->getAs<FunctionProtoType>(); - if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) - ResolveExceptionSpec(Loc, FPT); - // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -13137,7 +13377,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, static void diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, - VarDecl *var, DeclContext *DC) { + ValueDecl *var, DeclContext *DC) { DeclContext *VarDC = var->getDeclContext(); // If the parameter still belongs to the translation unit, then @@ -13157,25 +13397,21 @@ diagnoseUncapturableValueReference(Sema &S, SourceLocation loc, if (!S.getLangOpts().CPlusPlus && !S.CurContext->isFunctionOrMethod()) return; + unsigned ValueKind = isa<BindingDecl>(var) ? 1 : 0; + unsigned ContextKind = 3; // unknown if (isa<CXXMethodDecl>(VarDC) && cast<CXXRecordDecl>(VarDC->getParent())->isLambda()) { - S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_lambda) - << var->getIdentifier(); - } else if (FunctionDecl *fn = dyn_cast<FunctionDecl>(VarDC)) { - S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_function) - << var->getIdentifier() << fn->getDeclName(); + ContextKind = 2; + } else if (isa<FunctionDecl>(VarDC)) { + ContextKind = 0; } else if (isa<BlockDecl>(VarDC)) { - S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_block) - << var->getIdentifier(); - } else { - // FIXME: Is there any other context where a local variable can be - // declared? - S.Diag(loc, diag::err_reference_to_local_var_in_enclosing_context) - << var->getIdentifier(); + ContextKind = 1; } + S.Diag(loc, diag::err_reference_to_local_in_enclosing_context) + << var << ValueKind << ContextKind << VarDC; S.Diag(var->getLocation(), diag::note_entity_declared_at) - << var->getIdentifier(); + << var; // FIXME: Add additional diagnostic info about class etc. which prevents // capture. @@ -13319,6 +13555,23 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, } return false; } + + // Warn about implicitly autoreleasing indirect parameters captured by blocks. + if (auto *PT = dyn_cast<PointerType>(CaptureType)) { + QualType PointeeTy = PT->getPointeeType(); + if (isa<ObjCObjectPointerType>(PointeeTy.getCanonicalType()) && + PointeeTy.getObjCLifetime() == Qualifiers::OCL_Autoreleasing && + !isa<AttributedType>(PointeeTy)) { + if (BuildAndDiagnose) { + SourceLocation VarLoc = Var->getLocation(); + S.Diag(Loc, diag::warn_block_capture_autoreleasing); + S.Diag(VarLoc, diag::note_declare_parameter_autoreleasing) << + FixItHint::CreateInsertion(VarLoc, "__autoreleasing"); + S.Diag(VarLoc, diag::note_declare_parameter_strong); + } + } + } + const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); if (HasBlocksAttr || CaptureType->isReferenceType() || (S.getLangOpts().OpenMP && S.IsOpenMPCapturedDecl(Var))) { @@ -13539,7 +13792,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // C++ [expr.prim.lambda]p5: // The closure type for a lambda-expression has a public inline // function call operator [...]. This function call operator is - // declared const (9.3.1) if and only if the lambda-expression’s + // declared const (9.3.1) if and only if the lambda-expression's // parameter-declaration-clause is not followed by mutable. DeclRefType = CaptureType.getNonReferenceType(); if (!LSI->Mutable && !CaptureType->isReferenceType()) @@ -14580,6 +14833,13 @@ namespace { << E->getSourceRange(); return ExprError(); } + + if (isa<CallExpr>(E->getSubExpr())) { + S.Diag(E->getOperatorLoc(), diag::err_unknown_any_addrof_call) + << E->getSourceRange(); + return ExprError(); + } + assert(E->getValueKind() == VK_RValue); assert(E->getObjectKind() == OK_Ordinary); E->setType(DestType); @@ -15104,11 +15364,6 @@ ExprResult Sema::ActOnObjCAvailabilityCheckExpr( VersionTuple Version; if (Spec != AvailSpecs.end()) Version = Spec->getVersion(); - else - // This is the '*' case in @available. We should diagnose this; the - // programmer should explicitly account for this case if they target this - // platform. - Diag(AtLoc, diag::warn_available_using_star_case) << RParen << Platform; return new (Context) ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy); diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index dfdd36752bf65..5f769cc40ded4 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -292,7 +292,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, if (isDependent) { // We didn't find our type, but that's okay: it's dependent // anyway. - + // FIXME: What if we have no nested-name-specifier? QualType T = CheckTypenameType(ETK_None, SourceLocation(), SS.getWithLocInContext(Context), @@ -326,14 +326,14 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) return nullptr; - assert(DS.getTypeSpecType() == DeclSpec::TST_decltype + assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "only get destructor types from declspecs"); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); QualType SearchType = GetTypeFromParser(ObjectType); if (SearchType->isDependentType() || Context.hasSameUnqualifiedType(SearchType, T)) { return ParsedType::make(T); } - + Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; return nullptr; @@ -520,17 +520,17 @@ getUuidAttrOfType(Sema &SemaRef, QualType QT, else if (QT->isArrayType()) Ty = Ty->getBaseElementTypeUnsafe(); - const auto *RD = Ty->getAsCXXRecordDecl(); - if (!RD) + const auto *TD = Ty->getAsTagDecl(); + if (!TD) return; - if (const auto *Uuid = RD->getMostRecentDecl()->getAttr<UuidAttr>()) { + if (const auto *Uuid = TD->getMostRecentDecl()->getAttr<UuidAttr>()) { UuidAttrs.insert(Uuid); return; } // __uuidof can grab UUIDs from template arguments. - if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(TD)) { const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); for (const TemplateArgument &TA : TAL.asArray()) { const UuidAttr *UuidForTA = nullptr; @@ -662,7 +662,7 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { IsThrownVarInScope = true; break; } - + if (S->getFlags() & (Scope::FnScope | Scope::ClassScope | Scope::BlockScope | Scope::FunctionPrototypeScope | Scope::ObjCMethodScope | @@ -672,17 +672,22 @@ Sema::ActOnCXXThrow(Scope *S, SourceLocation OpLoc, Expr *Ex) { } } } - + return BuildCXXThrow(OpLoc, Ex, IsThrownVarInScope); } -ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, +ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex, bool IsThrownVarInScope) { // Don't report an error if 'throw' is used in system headers. if (!getLangOpts().CXXExceptions && !getSourceManager().isInSystemHeader(OpLoc)) Diag(OpLoc, diag::err_exceptions_disabled) << "throw"; + // Exceptions aren't allowed in CUDA device code. + if (getLangOpts().CUDA) + CUDADiagIfDeviceCode(OpLoc, diag::err_cuda_device_exceptions) + << "throw" << CurrentCUDATarget(); + if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw"; @@ -858,13 +863,8 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, // We don't keep the instantiated default argument expressions around so // we must rebuild them here. for (unsigned I = 1, E = CD->getNumParams(); I != E; ++I) { - // Skip any default arguments that we've already instantiated. - if (Context.getDefaultArgExprForConstructor(CD, I)) - continue; - - Expr *DefaultArg = - BuildCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I)).get(); - Context.addDefaultArgExprForConstructor(CD, I, DefaultArg); + if (CheckCXXDefaultArgExpr(ThrowLoc, CD, CD->getParamDecl(I))) + return true; } } } @@ -903,10 +903,10 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( I-- && isa<LambdaScopeInfo>(FunctionScopes[I]); CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]); - - if (!CurLSI->isCXXThisCaptured()) + + if (!CurLSI->isCXXThisCaptured()) continue; - + auto C = CurLSI->getCXXThisCapture(); if (C.isCopyCapture()) { @@ -922,7 +922,7 @@ static QualType adjustCVQualifiersForCXXThisWithinLambda( assert(CurLSI); assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator)); assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); - + auto IsThisCaptured = [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { IsConst = false; @@ -992,10 +992,10 @@ QualType Sema::getCurrentThisType() { return ThisTy; } -Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, +Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Decl *ContextDecl, unsigned CXXThisTypeQuals, - bool Enabled) + bool Enabled) : S(S), OldCXXThisTypeOverride(S.CXXThisTypeOverride), Enabled(false) { if (!Enabled || !ContextDecl) @@ -1006,13 +1006,13 @@ Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, Record = Template->getTemplatedDecl(); else Record = cast<CXXRecordDecl>(ContextDecl); - + // We care only for CVR qualifiers here, so cut everything else. CXXThisTypeQuals &= Qualifiers::FastMask; S.CXXThisTypeOverride = S.Context.getPointerType( S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals)); - + this->Enabled = true; } @@ -1026,7 +1026,7 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, QualType ThisTy, SourceLocation Loc, const bool ByCopy) { - + QualType AdjustedThisTy = ThisTy; // The type of the corresponding data member (not a 'this' pointer if 'by // copy'). @@ -1039,7 +1039,7 @@ static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask); AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy); } - + FieldDecl *Field = FieldDecl::Create( Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy, Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false, @@ -1065,24 +1065,24 @@ static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD, return This; } -bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, +bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt, const bool ByCopy) { // We don't need to capture this in an unevaluated context. if (isUnevaluatedContext() && !Explicit) return true; - + assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value"); const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ? *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1; - + // Check that we can capture the *enclosing object* (referred to by '*this') - // by the capturing-entity/closure (lambda/block/etc) at - // MaxFunctionScopesIndex-deep on the FunctionScopes stack. + // by the capturing-entity/closure (lambda/block/etc) at + // MaxFunctionScopesIndex-deep on the FunctionScopes stack. - // Note: The *enclosing object* can only be captured by-value by a - // closure that is a lambda, using the explicit notation: + // Note: The *enclosing object* can only be captured by-value by a + // closure that is a lambda, using the explicit notation: // [*this] { ... }. // Every other capture of the *enclosing object* results in its by-reference // capture. @@ -1091,15 +1091,15 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // stack), we can capture the *enclosing object* only if: // - 'L' has an explicit byref or byval capture of the *enclosing object* // - or, 'L' has an implicit capture. - // AND + // AND // -- there is no enclosing closure - // -- or, there is some enclosing closure 'E' that has already captured the - // *enclosing object*, and every intervening closure (if any) between 'E' + // -- or, there is some enclosing closure 'E' that has already captured the + // *enclosing object*, and every intervening closure (if any) between 'E' // and 'L' can implicitly capture the *enclosing object*. - // -- or, every enclosing closure can implicitly capture the + // -- or, every enclosing closure can implicitly capture the // *enclosing object* - - + + unsigned NumCapturingClosures = 0; for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { if (CapturingScopeInfo *CSI = @@ -1145,7 +1145,7 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // In the loop below, respect the ByCopy flag only for the closure requesting // the capture (i.e. first iteration through the loop below). Ignore it for - // all enclosing closure's upto NumCapturingClosures (since they must be + // all enclosing closure's up to NumCapturingClosures (since they must be // implicitly capturing the *enclosing object* by reference (see loop // above)). assert((!ByCopy || @@ -1155,18 +1155,18 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit, // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. QualType ThisTy = getCurrentThisType(); - for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; + for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = nullptr; - + if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) { // For lambda expressions, build a field and an initializing expression, // and capture the *enclosing object* by copy only if this is the first // iteration. ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc, ByCopy && idx == MaxFunctionScopesIndex); - + } else if (CapturedRegionScopeInfo *RSI = dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx])) ThisExpr = @@ -1196,7 +1196,7 @@ bool Sema::isThisOutsideMemberFunctionBody(QualType BaseType) { // type for 'this'. if (CXXThisTypeOverride.isNull()) return false; - + // Determine whether we're looking into a class that's currently being // defined. CXXRecordDecl *Class = BaseType->getAsCXXRecordDecl(); @@ -1216,6 +1216,17 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); + // Handle errors like: int({0}) + if (exprs.size() == 1 && !canInitializeWithParenthesizedList(Ty) && + LParenLoc.isValid() && RParenLoc.isValid()) + if (auto IList = dyn_cast<InitListExpr>(exprs[0])) { + Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens) + << Ty << IList->getSourceRange() + << FixItHint::CreateRemoval(LParenLoc) + << FixItHint::CreateRemoval(RParenLoc); + LParenLoc = RParenLoc = SourceLocation(); + } + auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); // Avoid creating a non-type-dependent expression that contains typos. // Non-type-dependent expressions are liable to be discarded without @@ -1280,10 +1291,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, diag::err_invalid_incomplete_type_use, FullRange)) return ExprError(); - if (RequireNonAbstractType(TyBeginLoc, Ty, - diag::err_allocation_of_abstract_type)) - return ExprError(); - InitializedEntity Entity = InitializedEntity::InitializeTemporary(TInfo); InitializationKind Kind = Exprs.size() ? ListInitialization @@ -1317,8 +1324,133 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo, return Result; } -/// doesUsualArrayDeleteWantSize - Answers whether the usual -/// operator delete[] for the given type has a size_t parameter. +/// \brief Determine whether the given function is a non-placement +/// deallocation function. +static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { + if (FD->isInvalidDecl()) + return false; + + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) + return Method->isUsualDeallocationFunction(); + + if (FD->getOverloadedOperator() != OO_Delete && + FD->getOverloadedOperator() != OO_Array_Delete) + return false; + + unsigned UsualParams = 1; + + if (S.getLangOpts().SizedDeallocation && UsualParams < FD->getNumParams() && + S.Context.hasSameUnqualifiedType( + FD->getParamDecl(UsualParams)->getType(), + S.Context.getSizeType())) + ++UsualParams; + + if (S.getLangOpts().AlignedAllocation && UsualParams < FD->getNumParams() && + S.Context.hasSameUnqualifiedType( + FD->getParamDecl(UsualParams)->getType(), + S.Context.getTypeDeclType(S.getStdAlignValT()))) + ++UsualParams; + + return UsualParams == FD->getNumParams(); +} + +namespace { + struct UsualDeallocFnInfo { + UsualDeallocFnInfo() : Found(), FD(nullptr) {} + UsualDeallocFnInfo(Sema &S, DeclAccessPair Found) + : Found(Found), FD(dyn_cast<FunctionDecl>(Found->getUnderlyingDecl())), + HasSizeT(false), HasAlignValT(false), CUDAPref(Sema::CFP_Native) { + // A function template declaration is never a usual deallocation function. + if (!FD) + return; + if (FD->getNumParams() == 3) + HasAlignValT = HasSizeT = true; + else if (FD->getNumParams() == 2) { + HasSizeT = FD->getParamDecl(1)->getType()->isIntegerType(); + HasAlignValT = !HasSizeT; + } + + // In CUDA, determine how much we'd like / dislike to call this. + if (S.getLangOpts().CUDA) + if (auto *Caller = dyn_cast<FunctionDecl>(S.CurContext)) + CUDAPref = S.IdentifyCUDAPreference(Caller, FD); + } + + operator bool() const { return FD; } + + bool isBetterThan(const UsualDeallocFnInfo &Other, bool WantSize, + bool WantAlign) const { + // C++17 [expr.delete]p10: + // If the type has new-extended alignment, a function with a parameter + // of type std::align_val_t is preferred; otherwise a function without + // such a parameter is preferred + if (HasAlignValT != Other.HasAlignValT) + return HasAlignValT == WantAlign; + + if (HasSizeT != Other.HasSizeT) + return HasSizeT == WantSize; + + // Use CUDA call preference as a tiebreaker. + return CUDAPref > Other.CUDAPref; + } + + DeclAccessPair Found; + FunctionDecl *FD; + bool HasSizeT, HasAlignValT; + Sema::CUDAFunctionPreference CUDAPref; + }; +} + +/// Determine whether a type has new-extended alignment. This may be called when +/// the type is incomplete (for a delete-expression with an incomplete pointee +/// type), in which case it will conservatively return false if the alignment is +/// not known. +static bool hasNewExtendedAlignment(Sema &S, QualType AllocType) { + return S.getLangOpts().AlignedAllocation && + S.getASTContext().getTypeAlignIfKnown(AllocType) > + S.getASTContext().getTargetInfo().getNewAlign(); +} + +/// Select the correct "usual" deallocation function to use from a selection of +/// deallocation functions (either global or class-scope). +static UsualDeallocFnInfo resolveDeallocationOverload( + Sema &S, LookupResult &R, bool WantSize, bool WantAlign, + llvm::SmallVectorImpl<UsualDeallocFnInfo> *BestFns = nullptr) { + UsualDeallocFnInfo Best; + + for (auto I = R.begin(), E = R.end(); I != E; ++I) { + UsualDeallocFnInfo Info(S, I.getPair()); + if (!Info || !isNonPlacementDeallocationFunction(S, Info.FD) || + Info.CUDAPref == Sema::CFP_Never) + continue; + + if (!Best) { + Best = Info; + if (BestFns) + BestFns->push_back(Info); + continue; + } + + if (Best.isBetterThan(Info, WantSize, WantAlign)) + continue; + + // If more than one preferred function is found, all non-preferred + // functions are eliminated from further consideration. + if (BestFns && Info.isBetterThan(Best, WantSize, WantAlign)) + BestFns->clear(); + + Best = Info; + if (BestFns) + BestFns->push_back(Info); + } + + return Best; +} + +/// Determine whether a given type is a class for which 'delete[]' would call +/// a member 'operator delete[]' with a 'size_t' parameter. This implies that +/// we need to store the array size (even if the type is +/// trivially-destructible). static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, QualType allocType) { const RecordType *record = @@ -1342,35 +1474,13 @@ static bool doesUsualArrayDeleteWantSize(Sema &S, SourceLocation loc, // on this thing, so it doesn't matter if we allocate extra space or not. if (ops.isAmbiguous()) return false; - LookupResult::Filter filter = ops.makeFilter(); - while (filter.hasNext()) { - NamedDecl *del = filter.next()->getUnderlyingDecl(); - - // C++0x [basic.stc.dynamic.deallocation]p2: - // A template instance is never a usual deallocation function, - // regardless of its signature. - if (isa<FunctionTemplateDecl>(del)) { - filter.erase(); - continue; - } - - // C++0x [basic.stc.dynamic.deallocation]p2: - // If class T does not declare [an operator delete[] with one - // parameter] but does declare a member deallocation function - // named operator delete[] with exactly two parameters, the - // second of which has type std::size_t, then this function - // is a usual deallocation function. - if (!cast<CXXMethodDecl>(del)->isUsualDeallocationFunction()) { - filter.erase(); - continue; - } - } - filter.done(); - - if (!ops.isSingleResult()) return false; - - const FunctionDecl *del = cast<FunctionDecl>(ops.getFoundDecl()); - return (del->getNumParams() == 2); + // C++17 [expr.delete]p10: + // If the deallocation functions have class scope, the one without a + // parameter of type std::size_t is selected. + auto Best = resolveDeallocationOverload( + S, ops, /*WantSize*/false, + /*WantAlign*/hasNewExtendedAlignment(S, allocType)); + return Best && Best.HasSizeT; } /// \brief Parsed a C++ 'new' expression (C++ 5.3.4). @@ -1454,8 +1564,20 @@ Sema::ActOnCXXNew(SourceLocation StartLoc, bool UseGlobal, return ExprError(); SourceRange DirectInitRange; - if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) + if (ParenListExpr *List = dyn_cast_or_null<ParenListExpr>(Initializer)) { DirectInitRange = List->getSourceRange(); + // Handle errors like: new int a({0}) + if (List->getNumExprs() == 1 && + !canInitializeWithParenthesizedList(AllocType)) + if (auto IList = dyn_cast<InitListExpr>(List->getExpr(0))) { + Diag(TInfo->getTypeLoc().getLocStart(), diag::err_list_init_in_parens) + << AllocType << List->getSourceRange() + << FixItHint::CreateRemoval(List->getLocStart()) + << FixItHint::CreateRemoval(List->getLocEnd()); + DirectInitRange = SourceRange(); + Initializer = IList; + } + } return BuildCXXNew(SourceRange(StartLoc, D.getLocEnd()), UseGlobal, PlacementLParen, @@ -1574,7 +1696,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, << /*at end of FE*/0 << Inits[0]->getSourceRange(); } - // In ARC, infer 'retaining' for the allocated + // In ARC, infer 'retaining' for the allocated if (getLangOpts().ObjCAutoRefCount && AllocType.getObjCLifetime() == Qualifiers::OCL_None && AllocType->isObjCLifetimeType()) { @@ -1583,7 +1705,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } QualType ResultType = Context.getPointerType(AllocType); - + if (ArraySize && ArraySize->getType()->isNonOverloadPlaceholderType()) { ExprResult result = CheckPlaceholderExpr(ArraySize); if (result.isInvalid()) return ExprError(); @@ -1596,6 +1718,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // conversion function to integral or unscoped enumeration type exists. // C++1y [expr.new]p6: The expression [...] is implicitly converted to // std::size_t. + llvm::Optional<uint64_t> KnownArraySize; if (ArraySize && !ArraySize->isTypeDependent()) { ExprResult ConvertedSize; if (getLangOpts().CPlusPlus14) { @@ -1604,7 +1727,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, ConvertedSize = PerformImplicitConversion(ArraySize, Context.getSizeType(), AA_Converting); - if (!ConvertedSize.isInvalid() && + if (!ConvertedSize.isInvalid() && ArraySize->getType()->getAs<RecordType>()) // Diagnose the compatibility of this conversion. Diag(StartLoc, diag::warn_cxx98_compat_array_size_conversion) @@ -1613,7 +1736,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, class SizeConvertDiagnoser : public ICEConvertDiagnoser { protected: Expr *ArraySize; - + public: SizeConvertDiagnoser(Expr *ArraySize) : ICEConvertDiagnoser(/*AllowScopedEnumerations*/false, false, false), @@ -1680,44 +1803,34 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // The expression in a direct-new-declarator shall have integral type // with a non-negative value. // - // Let's see if this is a constant < 0. If so, we reject it out of - // hand. Otherwise, if it's not a constant, we must have an unparenthesized - // array type. - // - // Note: such a construct has well-defined semantics in C++11: it throws - // std::bad_array_new_length. + // Let's see if this is a constant < 0. If so, we reject it out of hand, + // per CWG1464. Otherwise, if it's not a constant, we must have an + // unparenthesized array type. if (!ArraySize->isValueDependent()) { llvm::APSInt Value; // We've already performed any required implicit conversion to integer or // unscoped enumeration type. + // FIXME: Per CWG1464, we are required to check the value prior to + // converting to size_t. This will never find a negative array size in + // C++14 onwards, because Value is always unsigned here! if (ArraySize->isIntegerConstantExpr(Value, Context)) { - if (Value < llvm::APSInt( - llvm::APInt::getNullValue(Value.getBitWidth()), - Value.isUnsigned())) { - if (getLangOpts().CPlusPlus11) - Diag(ArraySize->getLocStart(), - diag::warn_typecheck_negative_array_new_size) - << ArraySize->getSourceRange(); - else - return ExprError(Diag(ArraySize->getLocStart(), - diag::err_typecheck_negative_array_size) - << ArraySize->getSourceRange()); - } else if (!AllocType->isDependentType()) { + if (Value.isSigned() && Value.isNegative()) { + return ExprError(Diag(ArraySize->getLocStart(), + diag::err_typecheck_negative_array_size) + << ArraySize->getSourceRange()); + } + + if (!AllocType->isDependentType()) { unsigned ActiveSizeBits = ConstantArrayType::getNumAddressingBits(Context, AllocType, Value); - if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) { - if (getLangOpts().CPlusPlus11) - Diag(ArraySize->getLocStart(), - diag::warn_array_new_too_large) - << Value.toString(10) - << ArraySize->getSourceRange(); - else - return ExprError(Diag(ArraySize->getLocStart(), - diag::err_array_too_large) - << Value.toString(10) - << ArraySize->getSourceRange()); - } + if (ActiveSizeBits > ConstantArrayType::getMaxSizeBits(Context)) + return ExprError(Diag(ArraySize->getLocStart(), + diag::err_array_too_large) + << Value.toString(10) + << ArraySize->getSourceRange()); } + + KnownArraySize = Value.getZExtValue(); } else if (TypeIdParens.isValid()) { // Can't have dynamic array size when the type-id is in parentheses. Diag(ArraySize->getLocStart(), diag::ext_new_paren_array_nonconst) @@ -1735,21 +1848,26 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, FunctionDecl *OperatorNew = nullptr; FunctionDecl *OperatorDelete = nullptr; + unsigned Alignment = + AllocType->isDependentType() ? 0 : Context.getTypeAlign(AllocType); + unsigned NewAlignment = Context.getTargetInfo().getNewAlign(); + bool PassAlignment = getLangOpts().AlignedAllocation && + Alignment > NewAlignment; if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments(PlacementArgs) && FindAllocationFunctions(StartLoc, SourceRange(PlacementLParen, PlacementRParen), - UseGlobal, AllocType, ArraySize, PlacementArgs, - OperatorNew, OperatorDelete)) + UseGlobal, AllocType, ArraySize, PassAlignment, + PlacementArgs, OperatorNew, OperatorDelete)) return ExprError(); // If this is an array allocation, compute whether the usual array // deallocation function for the type has a size_t parameter. bool UsualArrayDeleteWantsSize = false; if (ArraySize && !AllocType->isDependentType()) - UsualArrayDeleteWantsSize - = doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); + UsualArrayDeleteWantsSize = + doesUsualArrayDeleteWantSize(*this, StartLoc, AllocType); SmallVector<Expr *, 8> AllPlaceArgs; if (OperatorNew) { @@ -1760,9 +1878,11 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // We've already converted the placement args, just fill in any default // arguments. Skip the first parameter because we don't have a corresponding - // argument. - if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, 1, - PlacementArgs, AllPlaceArgs, CallType)) + // argument. Skip the second parameter too if we're passing in the + // alignment; we've already filled it in. + if (GatherArgumentsForCall(PlacementLParen, OperatorNew, Proto, + PassAlignment ? 2 : 1, PlacementArgs, + AllPlaceArgs, CallType)) return ExprError(); if (!AllPlaceArgs.empty()) @@ -1772,44 +1892,29 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, DiagnoseSentinelCalls(OperatorNew, PlacementLParen, PlacementArgs); // FIXME: Missing call to CheckFunctionCall or equivalent - } - // Warn if the type is over-aligned and is being allocated by global operator - // new. - if (PlacementArgs.empty() && OperatorNew && - (OperatorNew->isImplicit() || - (OperatorNew->getLocStart().isValid() && - getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { - if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){ - unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign(); - if (Align > SuitableAlign) + // Warn if the type is over-aligned and is being allocated by (unaligned) + // global operator new. + if (PlacementArgs.empty() && !PassAlignment && + (OperatorNew->isImplicit() || + (OperatorNew->getLocStart().isValid() && + getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { + if (Alignment > NewAlignment) Diag(StartLoc, diag::warn_overaligned_type) << AllocType - << unsigned(Align / Context.getCharWidth()) - << unsigned(SuitableAlign / Context.getCharWidth()); + << unsigned(Alignment / Context.getCharWidth()) + << unsigned(NewAlignment / Context.getCharWidth()); } } - QualType InitType = AllocType; // Array 'new' can't have any initializers except empty parentheses. // Initializer lists are also allowed, in C++11. Rely on the parser for the // dialect distinction. - if (ResultType->isArrayType() || ArraySize) { - if (!isLegalArrayNewInitializer(initStyle, Initializer)) { - SourceRange InitRange(Inits[0]->getLocStart(), - Inits[NumInits - 1]->getLocEnd()); - Diag(StartLoc, diag::err_new_array_init_args) << InitRange; - return ExprError(); - } - if (InitListExpr *ILE = dyn_cast_or_null<InitListExpr>(Initializer)) { - // We do the initialization typechecking against the array type - // corresponding to the number of initializers + 1 (to also check - // default-initialization). - unsigned NumElements = ILE->getNumInits() + 1; - InitType = Context.getConstantArrayType(AllocType, - llvm::APInt(Context.getTypeSize(Context.getSizeType()), NumElements), - ArrayType::Normal, 0); - } + if (ArraySize && !isLegalArrayNewInitializer(initStyle, Initializer)) { + SourceRange InitRange(Inits[0]->getLocStart(), + Inits[NumInits - 1]->getLocEnd()); + Diag(StartLoc, diag::err_new_array_init_args) << InitRange; + return ExprError(); } // If we can perform the initialization, and we've not already done so, @@ -1817,6 +1922,19 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (!AllocType->isDependentType() && !Expr::hasAnyTypeDependentArguments( llvm::makeArrayRef(Inits, NumInits))) { + // The type we initialize is the complete type, including the array bound. + QualType InitType; + if (KnownArraySize) + InitType = Context.getConstantArrayType( + AllocType, llvm::APInt(Context.getTypeSize(Context.getSizeType()), + *KnownArraySize), + ArrayType::Normal, 0); + else if (ArraySize) + InitType = + Context.getIncompleteArrayType(AllocType, ArrayType::Normal, 0); + else + InitType = AllocType; + // C++11 [expr.new]p15: // A new-expression that creates an object of type T initializes that // object as follows: @@ -1836,7 +1954,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, InitializedEntity Entity = InitializedEntity::InitializeNew(StartLoc, InitType); - InitializationSequence InitSeq(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); + InitializationSequence InitSeq(*this, Entity, Kind, + MultiExprArg(Inits, NumInits)); ExprResult FullInit = InitSeq.Perform(*this, Entity, Kind, MultiExprArg(Inits, NumInits)); if (FullInit.isInvalid()) @@ -1844,6 +1963,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // FullInit is our initializer; strip off CXXBindTemporaryExprs, because // we don't want the initialized object to be destructed. + // FIXME: We should not create these in the first place. if (CXXBindTemporaryExpr *Binder = dyn_cast_or_null<CXXBindTemporaryExpr>(FullInit.get())) FullInit = Binder->getSubExpr(); @@ -1872,7 +1992,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, if (CXXDestructorDecl *dtor = LookupDestructor( cast<CXXRecordDecl>(BaseRecordType->getDecl()))) { MarkFunctionReferenced(StartLoc, dtor); - CheckDestructorAccess(StartLoc, dtor, + CheckDestructorAccess(StartLoc, dtor, PDiag(diag::err_access_dtor) << BaseAllocType); if (DiagnoseUseOfDecl(dtor, StartLoc)) @@ -1882,7 +2002,7 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, } return new (Context) - CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, + CXXNewExpr(Context, UseGlobal, OperatorNew, OperatorDelete, PassAlignment, UsualArrayDeleteWantsSize, PlacementArgs, TypeIdParens, ArraySize, initStyle, Initializer, ResultType, AllocTypeInfo, Range, DirectInitRange); @@ -1921,36 +2041,132 @@ bool Sema::CheckAllocatedType(QualType AllocType, SourceLocation Loc, << BaseAllocType; } } - + return false; } -/// \brief Determine whether the given function is a non-placement -/// deallocation function. -static bool isNonPlacementDeallocationFunction(Sema &S, FunctionDecl *FD) { - if (FD->isInvalidDecl()) - return false; +static bool +resolveAllocationOverload(Sema &S, LookupResult &R, SourceRange Range, + SmallVectorImpl<Expr *> &Args, bool &PassAlignment, + FunctionDecl *&Operator, + OverloadCandidateSet *AlignedCandidates = nullptr, + Expr *AlignArg = nullptr) { + OverloadCandidateSet Candidates(R.getNameLoc(), + OverloadCandidateSet::CSK_Normal); + for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); + Alloc != AllocEnd; ++Alloc) { + // Even member operator new/delete are implicitly treated as + // static, so don't use AddMemberCandidate. + NamedDecl *D = (*Alloc)->getUnderlyingDecl(); - if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(FD)) - return Method->isUsualDeallocationFunction(); + if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { + S.AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), + /*ExplicitTemplateArgs=*/nullptr, Args, + Candidates, + /*SuppressUserConversions=*/false); + continue; + } - if (FD->getOverloadedOperator() != OO_Delete && - FD->getOverloadedOperator() != OO_Array_Delete) + FunctionDecl *Fn = cast<FunctionDecl>(D); + S.AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, + /*SuppressUserConversions=*/false); + } + + // Do the resolution. + OverloadCandidateSet::iterator Best; + switch (Candidates.BestViableFunction(S, R.getNameLoc(), Best)) { + case OR_Success: { + // Got one! + FunctionDecl *FnDecl = Best->Function; + if (S.CheckAllocationAccess(R.getNameLoc(), Range, R.getNamingClass(), + Best->FoundDecl) == Sema::AR_inaccessible) + return true; + + Operator = FnDecl; return false; + } + + case OR_No_Viable_Function: + // C++17 [expr.new]p13: + // If no matching function is found and the allocated object type has + // new-extended alignment, the alignment argument is removed from the + // argument list, and overload resolution is performed again. + if (PassAlignment) { + PassAlignment = false; + AlignArg = Args[1]; + Args.erase(Args.begin() + 1); + return resolveAllocationOverload(S, R, Range, Args, PassAlignment, + Operator, &Candidates, AlignArg); + } - if (FD->getNumParams() == 1) + // MSVC will fall back on trying to find a matching global operator new + // if operator new[] cannot be found. Also, MSVC will leak by not + // generating a call to operator delete or operator delete[], but we + // will not replicate that bug. + // FIXME: Find out how this interacts with the std::align_val_t fallback + // once MSVC implements it. + if (R.getLookupName().getCXXOverloadedOperator() == OO_Array_New && + S.Context.getLangOpts().MSVCCompat) { + R.clear(); + R.setLookupName(S.Context.DeclarationNames.getCXXOperatorName(OO_New)); + S.LookupQualifiedName(R, S.Context.getTranslationUnitDecl()); + // FIXME: This will give bad diagnostics pointing at the wrong functions. + return resolveAllocationOverload(S, R, Range, Args, PassAlignment, + Operator, nullptr); + } + + S.Diag(R.getNameLoc(), diag::err_ovl_no_viable_function_in_call) + << R.getLookupName() << Range; + + // If we have aligned candidates, only note the align_val_t candidates + // from AlignedCandidates and the non-align_val_t candidates from + // Candidates. + if (AlignedCandidates) { + auto IsAligned = [](OverloadCandidate &C) { + return C.Function->getNumParams() > 1 && + C.Function->getParamDecl(1)->getType()->isAlignValT(); + }; + auto IsUnaligned = [&](OverloadCandidate &C) { return !IsAligned(C); }; + + // This was an overaligned allocation, so list the aligned candidates + // first. + Args.insert(Args.begin() + 1, AlignArg); + AlignedCandidates->NoteCandidates(S, OCD_AllCandidates, Args, "", + R.getNameLoc(), IsAligned); + Args.erase(Args.begin() + 1); + Candidates.NoteCandidates(S, OCD_AllCandidates, Args, "", R.getNameLoc(), + IsUnaligned); + } else { + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + } + return true; + + case OR_Ambiguous: + S.Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) + << R.getLookupName() << Range; + Candidates.NoteCandidates(S, OCD_ViableCandidates, Args); return true; - return S.getLangOpts().SizedDeallocation && FD->getNumParams() == 2 && - S.Context.hasSameUnqualifiedType(FD->getParamDecl(1)->getType(), - S.Context.getSizeType()); + case OR_Deleted: { + S.Diag(R.getNameLoc(), diag::err_ovl_deleted_call) + << Best->Function->isDeleted() + << R.getLookupName() + << S.getDeletedOrUnavailableSuffix(Best->Function) + << Range; + Candidates.NoteCandidates(S, OCD_AllCandidates, Args); + return true; + } + } + llvm_unreachable("Unreachable, bad result from BestViableFunction"); } + /// FindAllocationFunctions - Finds the overloads of operator new and delete /// that are appropriate for the allocation. bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, bool UseGlobal, QualType AllocType, - bool IsArray, MultiExprArg PlaceArgs, + bool IsArray, bool &PassAlignment, + MultiExprArg PlaceArgs, FunctionDecl *&OperatorNew, FunctionDecl *&OperatorDelete) { // --- Choosing an allocation function --- @@ -1962,16 +2178,29 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // 3) The first argument is always size_t. Append the arguments from the // placement form. - SmallVector<Expr*, 8> AllocArgs(1 + PlaceArgs.size()); - // We don't care about the actual value of this argument. + SmallVector<Expr*, 8> AllocArgs; + AllocArgs.reserve((PassAlignment ? 2 : 1) + PlaceArgs.size()); + + // We don't care about the actual value of these arguments. // FIXME: Should the Sema create the expression and embed it in the syntax // tree? Or should the consumer just recalculate the value? + // FIXME: Using a dummy value will interact poorly with attribute enable_if. IntegerLiteral Size(Context, llvm::APInt::getNullValue( Context.getTargetInfo().getPointerWidth(0)), Context.getSizeType(), SourceLocation()); - AllocArgs[0] = &Size; - std::copy(PlaceArgs.begin(), PlaceArgs.end(), AllocArgs.begin() + 1); + AllocArgs.push_back(&Size); + + QualType AlignValT = Context.VoidTy; + if (PassAlignment) { + DeclareGlobalNewDelete(); + AlignValT = Context.getTypeDeclType(getStdAlignValT()); + } + CXXScalarValueInitExpr Align(AlignValT, nullptr, SourceLocation()); + if (PassAlignment) + AllocArgs.push_back(&Align); + + AllocArgs.insert(AllocArgs.end(), PlaceArgs.begin(), PlaceArgs.end()); // C++ [expr.new]p8: // If the allocated type is a non-array type, the allocation @@ -1980,50 +2209,57 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // type, the allocation function's name is operator new[] and the // deallocation function's name is operator delete[]. DeclarationName NewName = Context.DeclarationNames.getCXXOperatorName( - IsArray ? OO_Array_New : OO_New); - DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( - IsArray ? OO_Array_Delete : OO_Delete); + IsArray ? OO_Array_New : OO_New); QualType AllocElemType = Context.getBaseElementType(AllocType); - if (AllocElemType->isRecordType() && !UseGlobal) { - CXXRecordDecl *Record - = cast<CXXRecordDecl>(AllocElemType->getAs<RecordType>()->getDecl()); - if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, Record, - /*AllowMissing=*/true, OperatorNew)) + // Find the allocation function. + { + LookupResult R(*this, NewName, StartLoc, LookupOrdinaryName); + + // C++1z [expr.new]p9: + // If the new-expression begins with a unary :: operator, the allocation + // function's name is looked up in the global scope. Otherwise, if the + // allocated type is a class type T or array thereof, the allocation + // function's name is looked up in the scope of T. + if (AllocElemType->isRecordType() && !UseGlobal) + LookupQualifiedName(R, AllocElemType->getAsCXXRecordDecl()); + + // We can see ambiguity here if the allocation function is found in + // multiple base classes. + if (R.isAmbiguous()) return true; - } - if (!OperatorNew) { - // Didn't find a member overload. Look for a global one. - DeclareGlobalNewDelete(); - DeclContext *TUDecl = Context.getTranslationUnitDecl(); - bool FallbackEnabled = IsArray && Context.getLangOpts().MSVCCompat; - if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, - /*AllowMissing=*/FallbackEnabled, OperatorNew, - /*Diagnose=*/!FallbackEnabled)) { - if (!FallbackEnabled) - return true; + // If this lookup fails to find the name, or if the allocated type is not + // a class type, the allocation function's name is looked up in the + // global scope. + if (R.empty()) + LookupQualifiedName(R, Context.getTranslationUnitDecl()); + + assert(!R.empty() && "implicitly declared allocation functions not found"); + assert(!R.isAmbiguous() && "global allocation functions are ambiguous"); - // MSVC will fall back on trying to find a matching global operator new - // if operator new[] cannot be found. Also, MSVC will leak by not - // generating a call to operator delete or operator delete[], but we - // will not replicate that bug. - NewName = Context.DeclarationNames.getCXXOperatorName(OO_New); - DeleteName = Context.DeclarationNames.getCXXOperatorName(OO_Delete); - if (FindAllocationOverload(StartLoc, Range, NewName, AllocArgs, TUDecl, - /*AllowMissing=*/false, OperatorNew)) + // We do our own custom access checks below. + R.suppressDiagnostics(); + + if (resolveAllocationOverload(*this, R, Range, AllocArgs, PassAlignment, + OperatorNew)) return true; - } } - // We don't need an operator delete if we're running under - // -fno-exceptions. + // We don't need an operator delete if we're running under -fno-exceptions. if (!getLangOpts().Exceptions) { OperatorDelete = nullptr; return false; } + // Note, the name of OperatorNew might have been changed from array to + // non-array by resolveAllocationOverload. + DeclarationName DeleteName = Context.DeclarationNames.getCXXOperatorName( + OperatorNew->getDeclName().getCXXOverloadedOperator() == OO_Array_New + ? OO_Array_Delete + : OO_Delete); + // C++ [expr.new]p19: // // If the new-expression begins with a unary :: operator, the @@ -2042,6 +2278,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (FoundDelete.isAmbiguous()) return true; // FIXME: clean up expressions? + bool FoundGlobalDelete = FoundDelete.empty(); if (FoundDelete.empty()) { DeclareGlobalNewDelete(); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); @@ -2056,7 +2293,16 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // we had explicit placement arguments. This matters for things like // struct A { void *operator new(size_t, int = 0); ... }; // A *a = new A() - bool isPlacementNew = (!PlaceArgs.empty() || OperatorNew->param_size() != 1); + // + // We don't have any definition for what a "placement allocation function" + // is, but we assume it's any allocation function whose + // parameter-declaration-clause is anything other than (size_t). + // + // FIXME: Should (size_t, std::align_val_t) also be considered non-placement? + // This affects whether an exception from the constructor of an overaligned + // type uses the sized or non-sized form of aligned operator delete. + bool isPlacementNew = !PlaceArgs.empty() || OperatorNew->param_size() != 1 || + OperatorNew->isVariadic(); if (isPlacementNew) { // C++ [expr.new]p20: @@ -2069,8 +2315,6 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, // To perform this comparison, we compute the function type that // the deallocation function should have, and use that type both // for template argument deduction and for comparison purposes. - // - // FIXME: this comparison should ignore CC and the like. QualType ExpectedFunctionType; { const FunctionProtoType *Proto @@ -2082,6 +2326,7 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, ArgTypes.push_back(Proto->getParamType(I)); FunctionProtoType::ExtProtoInfo EPI; + // FIXME: This is not part of the standard's rule. EPI.Variadic = Proto->isVariadic(); ExpectedFunctionType @@ -2092,8 +2337,8 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, DEnd = FoundDelete.end(); D != DEnd; ++D) { FunctionDecl *Fn = nullptr; - if (FunctionTemplateDecl *FnTmpl - = dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { + if (FunctionTemplateDecl *FnTmpl = + dyn_cast<FunctionTemplateDecl>((*D)->getUnderlyingDecl())) { // Perform template argument deduction to try to match the // expected function type. TemplateDeductionInfo Info(StartLoc); @@ -2103,38 +2348,35 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, } else Fn = cast<FunctionDecl>((*D)->getUnderlyingDecl()); - if (Context.hasSameType(Fn->getType(), ExpectedFunctionType)) + if (Context.hasSameType(adjustCCAndNoReturn(Fn->getType(), + ExpectedFunctionType, + /*AdjustExcpetionSpec*/true), + ExpectedFunctionType)) Matches.push_back(std::make_pair(D.getPair(), Fn)); } - } else { - // C++ [expr.new]p20: - // [...] Any non-placement deallocation function matches a - // non-placement allocation function. [...] - for (LookupResult::iterator D = FoundDelete.begin(), - DEnd = FoundDelete.end(); - D != DEnd; ++D) { - if (FunctionDecl *Fn = dyn_cast<FunctionDecl>((*D)->getUnderlyingDecl())) - if (isNonPlacementDeallocationFunction(*this, Fn)) - Matches.push_back(std::make_pair(D.getPair(), Fn)); - } + if (getLangOpts().CUDA) + EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); + } else { // C++1y [expr.new]p22: // For a non-placement allocation function, the normal deallocation // function lookup is used - // C++1y [expr.delete]p?: - // If [...] deallocation function lookup finds both a usual deallocation - // function with only a pointer parameter and a usual deallocation - // function with both a pointer parameter and a size parameter, then the - // selected deallocation function shall be the one with two parameters. - // Otherwise, the selected deallocation function shall be the function - // with one parameter. - if (getLangOpts().SizedDeallocation && Matches.size() == 2) { - if (Matches[0].second->getNumParams() == 1) - Matches.erase(Matches.begin()); - else - Matches.erase(Matches.begin() + 1); - assert(Matches[0].second->getNumParams() == 2 && - "found an unexpected usual deallocation function"); + // + // Per [expr.delete]p10, this lookup prefers a member operator delete + // without a size_t argument, but prefers a non-member operator delete + // with a size_t where possible (which it always is in this case). + llvm::SmallVector<UsualDeallocFnInfo, 4> BestDeallocFns; + UsualDeallocFnInfo Selected = resolveDeallocationOverload( + *this, FoundDelete, /*WantSize*/ FoundGlobalDelete, + /*WantAlign*/ hasNewExtendedAlignment(*this, AllocElemType), + &BestDeallocFns); + if (Selected) + Matches.push_back(std::make_pair(Selected.Found, Selected.FD)); + else { + // If we failed to select an operator, all remaining functions are viable + // but ambiguous. + for (auto Fn : BestDeallocFns) + Matches.push_back(std::make_pair(Fn.Found, Fn.FD)); } } @@ -2145,130 +2387,59 @@ bool Sema::FindAllocationFunctions(SourceLocation StartLoc, SourceRange Range, if (Matches.size() == 1) { OperatorDelete = Matches[0].second; - // C++0x [expr.new]p20: - // If the lookup finds the two-parameter form of a usual - // deallocation function (3.7.4.2) and that function, considered + // C++1z [expr.new]p23: + // If the lookup finds a usual deallocation function (3.7.4.2) + // with a parameter of type std::size_t and that function, considered // as a placement deallocation function, would have been // selected as a match for the allocation function, the program // is ill-formed. - if (!PlaceArgs.empty() && getLangOpts().CPlusPlus11 && + if (getLangOpts().CPlusPlus11 && isPlacementNew && isNonPlacementDeallocationFunction(*this, OperatorDelete)) { - Diag(StartLoc, diag::err_placement_new_non_placement_delete) - << SourceRange(PlaceArgs.front()->getLocStart(), - PlaceArgs.back()->getLocEnd()); - if (!OperatorDelete->isImplicit()) - Diag(OperatorDelete->getLocation(), diag::note_previous_decl) - << DeleteName; - } else { - CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), - Matches[0].first); - } - } - - return false; -} - -/// \brief Find an fitting overload for the allocation function -/// in the specified scope. -/// -/// \param StartLoc The location of the 'new' token. -/// \param Range The range of the placement arguments. -/// \param Name The name of the function ('operator new' or 'operator new[]'). -/// \param Args The placement arguments specified. -/// \param Ctx The scope in which we should search; either a class scope or the -/// translation unit. -/// \param AllowMissing If \c true, report an error if we can't find any -/// allocation functions. Otherwise, succeed but don't fill in \p -/// Operator. -/// \param Operator Filled in with the found allocation function. Unchanged if -/// no allocation function was found. -/// \param Diagnose If \c true, issue errors if the allocation function is not -/// usable. -bool Sema::FindAllocationOverload(SourceLocation StartLoc, SourceRange Range, - DeclarationName Name, MultiExprArg Args, - DeclContext *Ctx, - bool AllowMissing, FunctionDecl *&Operator, - bool Diagnose) { - LookupResult R(*this, Name, StartLoc, LookupOrdinaryName); - LookupQualifiedName(R, Ctx); - if (R.empty()) { - if (AllowMissing || !Diagnose) - return false; - return Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) - << Name << Range; - } - - if (R.isAmbiguous()) - return true; - - R.suppressDiagnostics(); - - OverloadCandidateSet Candidates(StartLoc, OverloadCandidateSet::CSK_Normal); - for (LookupResult::iterator Alloc = R.begin(), AllocEnd = R.end(); - Alloc != AllocEnd; ++Alloc) { - // Even member operator new/delete are implicitly treated as - // static, so don't use AddMemberCandidate. - NamedDecl *D = (*Alloc)->getUnderlyingDecl(); + UsualDeallocFnInfo Info(*this, + DeclAccessPair::make(OperatorDelete, AS_public)); + // Core issue, per mail to core reflector, 2016-10-09: + // If this is a member operator delete, and there is a corresponding + // non-sized member operator delete, this isn't /really/ a sized + // deallocation function, it just happens to have a size_t parameter. + bool IsSizedDelete = Info.HasSizeT; + if (IsSizedDelete && !FoundGlobalDelete) { + auto NonSizedDelete = + resolveDeallocationOverload(*this, FoundDelete, /*WantSize*/false, + /*WantAlign*/Info.HasAlignValT); + if (NonSizedDelete && !NonSizedDelete.HasSizeT && + NonSizedDelete.HasAlignValT == Info.HasAlignValT) + IsSizedDelete = false; + } - if (FunctionTemplateDecl *FnTemplate = dyn_cast<FunctionTemplateDecl>(D)) { - AddTemplateOverloadCandidate(FnTemplate, Alloc.getPair(), - /*ExplicitTemplateArgs=*/nullptr, - Args, Candidates, - /*SuppressUserConversions=*/false); - continue; + if (IsSizedDelete) { + SourceRange R = PlaceArgs.empty() + ? SourceRange() + : SourceRange(PlaceArgs.front()->getLocStart(), + PlaceArgs.back()->getLocEnd()); + Diag(StartLoc, diag::err_placement_new_non_placement_delete) << R; + if (!OperatorDelete->isImplicit()) + Diag(OperatorDelete->getLocation(), diag::note_previous_decl) + << DeleteName; + } } - FunctionDecl *Fn = cast<FunctionDecl>(D); - AddOverloadCandidate(Fn, Alloc.getPair(), Args, Candidates, - /*SuppressUserConversions=*/false); - } - - // Do the resolution. - OverloadCandidateSet::iterator Best; - switch (Candidates.BestViableFunction(*this, StartLoc, Best)) { - case OR_Success: { - // Got one! - FunctionDecl *FnDecl = Best->Function; - if (CheckAllocationAccess(StartLoc, Range, R.getNamingClass(), - Best->FoundDecl, Diagnose) == AR_inaccessible) - return true; + CheckAllocationAccess(StartLoc, Range, FoundDelete.getNamingClass(), + Matches[0].first); + } else if (!Matches.empty()) { + // We found multiple suitable operators. Per [expr.new]p20, that means we + // call no 'operator delete' function, but we should at least warn the user. + // FIXME: Suppress this warning if the construction cannot throw. + Diag(StartLoc, diag::warn_ambiguous_suitable_delete_function_found) + << DeleteName << AllocElemType; - Operator = FnDecl; - return false; + for (auto &Match : Matches) + Diag(Match.second->getLocation(), + diag::note_member_declared_here) << DeleteName; } - case OR_No_Viable_Function: - if (Diagnose) { - Diag(StartLoc, diag::err_ovl_no_viable_function_in_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); - } - return true; - - case OR_Ambiguous: - if (Diagnose) { - Diag(StartLoc, diag::err_ovl_ambiguous_call) - << Name << Range; - Candidates.NoteCandidates(*this, OCD_ViableCandidates, Args); - } - return true; - - case OR_Deleted: { - if (Diagnose) { - Diag(StartLoc, diag::err_ovl_deleted_call) - << Best->Function->isDeleted() - << Name - << getDeletedOrUnavailableSuffix(Best->Function) - << Range; - Candidates.NoteCandidates(*this, OCD_AllCandidates, Args); - } - return true; - } - } - llvm_unreachable("Unreachable, bad result from BestViableFunction"); + return false; } - /// DeclareGlobalNewDelete - Declare the global forms of operator new and /// delete. These are: /// @code @@ -2336,41 +2507,64 @@ void Sema::DeclareGlobalNewDelete() { nullptr); getStdBadAlloc()->setImplicit(true); } + if (!StdAlignValT && getLangOpts().AlignedAllocation) { + // The "std::align_val_t" enum class has not yet been declared, so build it + // implicitly. + auto *AlignValT = EnumDecl::Create( + Context, getOrCreateStdNamespace(), SourceLocation(), SourceLocation(), + &PP.getIdentifierTable().get("align_val_t"), nullptr, true, true, true); + AlignValT->setIntegerType(Context.getSizeType()); + AlignValT->setPromotionType(Context.getSizeType()); + AlignValT->setImplicit(true); + StdAlignValT = AlignValT; + } GlobalNewDeleteDeclared = true; QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_New), - VoidPtr, SizeT, QualType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_New), - VoidPtr, SizeT, QualType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Delete), - Context.VoidTy, VoidPtr); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), - Context.VoidTy, VoidPtr); - if (getLangOpts().SizedDeallocation) { - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Delete), - Context.VoidTy, VoidPtr, Context.getSizeType()); - DeclareGlobalAllocationFunction( - Context.DeclarationNames.getCXXOperatorName(OO_Array_Delete), - Context.VoidTy, VoidPtr, Context.getSizeType()); - } + auto DeclareGlobalAllocationFunctions = [&](OverloadedOperatorKind Kind, + QualType Return, QualType Param) { + llvm::SmallVector<QualType, 3> Params; + Params.push_back(Param); + + // Create up to four variants of the function (sized/aligned). + bool HasSizedVariant = getLangOpts().SizedDeallocation && + (Kind == OO_Delete || Kind == OO_Array_Delete); + bool HasAlignedVariant = getLangOpts().AlignedAllocation; + + int NumSizeVariants = (HasSizedVariant ? 2 : 1); + int NumAlignVariants = (HasAlignedVariant ? 2 : 1); + for (int Sized = 0; Sized < NumSizeVariants; ++Sized) { + if (Sized) + Params.push_back(SizeT); + + for (int Aligned = 0; Aligned < NumAlignVariants; ++Aligned) { + if (Aligned) + Params.push_back(Context.getTypeDeclType(getStdAlignValT())); + + DeclareGlobalAllocationFunction( + Context.DeclarationNames.getCXXOperatorName(Kind), Return, Params); + + if (Aligned) + Params.pop_back(); + } + } + }; + + DeclareGlobalAllocationFunctions(OO_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Array_New, VoidPtr, SizeT); + DeclareGlobalAllocationFunctions(OO_Delete, Context.VoidTy, VoidPtr); + DeclareGlobalAllocationFunctions(OO_Array_Delete, Context.VoidTy, VoidPtr); } /// DeclareGlobalAllocationFunction - Declares a single implicit global /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Param1, QualType Param2) { + ArrayRef<QualType> Params) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); - unsigned NumParams = Param2.isNull() ? 1 : 2; // Check if this function is already declared. DeclContext::lookup_result R = GlobalCtx->lookup(Name); @@ -2379,18 +2573,12 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // Only look at non-template functions, as it is the predefined, // non-templated allocation function we are trying to declare here. if (FunctionDecl *Func = dyn_cast<FunctionDecl>(*Alloc)) { - if (Func->getNumParams() == NumParams) { - QualType InitialParam1Type = - Context.getCanonicalType(Func->getParamDecl(0) - ->getType().getUnqualifiedType()); - QualType InitialParam2Type = - NumParams == 2 - ? Context.getCanonicalType(Func->getParamDecl(1) - ->getType().getUnqualifiedType()) - : QualType(); - // FIXME: Do we need to check for default arguments here? - if (InitialParam1Type == Param1 && - (NumParams == 1 || InitialParam2Type == Param2)) { + if (Func->getNumParams() == Params.size()) { + llvm::SmallVector<QualType, 3> FuncParams; + for (auto *P : Func->parameters()) + FuncParams.push_back( + Context.getCanonicalType(P->getType().getUnqualifiedType())); + if (llvm::makeArrayRef(FuncParams) == Params) { // Make the function visible to name lookup, even if we found it in // an unimported module. It either is an implicitly-declared global // allocation function, or is suppressing that function. @@ -2419,82 +2607,80 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, getLangOpts().CPlusPlus11 ? EST_BasicNoexcept : EST_DynamicNone; } - QualType Params[] = { Param1, Param2 }; - - QualType FnType = Context.getFunctionType( - Return, llvm::makeArrayRef(Params, NumParams), EPI); - FunctionDecl *Alloc = - FunctionDecl::Create(Context, GlobalCtx, SourceLocation(), - SourceLocation(), Name, - FnType, /*TInfo=*/nullptr, SC_None, false, true); - Alloc->setImplicit(); - - // Implicit sized deallocation functions always have default visibility. - Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, - VisibilityAttr::Default)); - - ParmVarDecl *ParamDecls[2]; - for (unsigned I = 0; I != NumParams; ++I) { - ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), - SourceLocation(), nullptr, - Params[I], /*TInfo=*/nullptr, - SC_None, nullptr); - ParamDecls[I]->setImplicit(); - } - Alloc->setParams(llvm::makeArrayRef(ParamDecls, NumParams)); - - Context.getTranslationUnitDecl()->addDecl(Alloc); - IdResolver.tryAddTopLevelDecl(Alloc, Name); + auto CreateAllocationFunctionDecl = [&](Attr *ExtraAttr) { + QualType FnType = Context.getFunctionType(Return, Params, EPI); + FunctionDecl *Alloc = FunctionDecl::Create( + Context, GlobalCtx, SourceLocation(), SourceLocation(), Name, + FnType, /*TInfo=*/nullptr, SC_None, false, true); + Alloc->setImplicit(); + + // Implicit sized deallocation functions always have default visibility. + Alloc->addAttr( + VisibilityAttr::CreateImplicit(Context, VisibilityAttr::Default)); + + llvm::SmallVector<ParmVarDecl *, 3> ParamDecls; + for (QualType T : Params) { + ParamDecls.push_back(ParmVarDecl::Create( + Context, Alloc, SourceLocation(), SourceLocation(), nullptr, T, + /*TInfo=*/nullptr, SC_None, nullptr)); + ParamDecls.back()->setImplicit(); + } + Alloc->setParams(ParamDecls); + if (ExtraAttr) + Alloc->addAttr(ExtraAttr); + Context.getTranslationUnitDecl()->addDecl(Alloc); + IdResolver.tryAddTopLevelDecl(Alloc, Name); + }; + + if (!LangOpts.CUDA) + CreateAllocationFunctionDecl(nullptr); + else { + // Host and device get their own declaration so each can be + // defined or re-declared independently. + CreateAllocationFunctionDecl(CUDAHostAttr::CreateImplicit(Context)); + CreateAllocationFunctionDecl(CUDADeviceAttr::CreateImplicit(Context)); + } } FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, bool CanProvideSize, + bool Overaligned, DeclarationName Name) { DeclareGlobalNewDelete(); LookupResult FoundDelete(*this, Name, StartLoc, LookupOrdinaryName); LookupQualifiedName(FoundDelete, Context.getTranslationUnitDecl()); - // C++ [expr.new]p20: - // [...] Any non-placement deallocation function matches a - // non-placement allocation function. [...] - llvm::SmallVector<FunctionDecl*, 2> Matches; - for (LookupResult::iterator D = FoundDelete.begin(), - DEnd = FoundDelete.end(); - D != DEnd; ++D) { - if (FunctionDecl *Fn = dyn_cast<FunctionDecl>(*D)) - if (isNonPlacementDeallocationFunction(*this, Fn)) - Matches.push_back(Fn); - } - - // C++1y [expr.delete]p?: - // If the type is complete and deallocation function lookup finds both a - // usual deallocation function with only a pointer parameter and a usual - // deallocation function with both a pointer parameter and a size - // parameter, then the selected deallocation function shall be the one - // with two parameters. Otherwise, the selected deallocation function - // shall be the function with one parameter. - if (getLangOpts().SizedDeallocation && Matches.size() == 2) { - unsigned NumArgs = CanProvideSize ? 2 : 1; - if (Matches[0]->getNumParams() != NumArgs) - Matches.erase(Matches.begin()); - else - Matches.erase(Matches.begin() + 1); - assert(Matches[0]->getNumParams() == NumArgs && - "found an unexpected usual deallocation function"); - } + // FIXME: It's possible for this to result in ambiguity, through a + // user-declared variadic operator delete or the enable_if attribute. We + // should probably not consider those cases to be usual deallocation + // functions. But for now we just make an arbitrary choice in that case. + auto Result = resolveDeallocationOverload(*this, FoundDelete, CanProvideSize, + Overaligned); + assert(Result.FD && "operator delete missing from global scope?"); + return Result.FD; +} - if (getLangOpts().CUDA) - EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); +FunctionDecl *Sema::FindDeallocationFunctionForDestructor(SourceLocation Loc, + CXXRecordDecl *RD) { + DeclarationName Name = Context.DeclarationNames.getCXXOperatorName(OO_Delete); - assert(Matches.size() == 1 && - "unexpectedly have multiple usual deallocation functions"); - return Matches.front(); + FunctionDecl *OperatorDelete = nullptr; + if (FindDeallocationFunction(Loc, RD, Name, OperatorDelete)) + return nullptr; + if (OperatorDelete) + return OperatorDelete; + + // If there's no class-specific operator delete, look up the global + // non-array delete. + return FindUsualDeallocationFunction( + Loc, true, hasNewExtendedAlignment(*this, Context.getRecordType(RD)), + Name); } bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, DeclarationName Name, - FunctionDecl* &Operator, bool Diagnose) { + FunctionDecl *&Operator, bool Diagnose) { LookupResult Found(*this, Name, StartLoc, LookupOrdinaryName); // Try to find operator delete/operator delete[] in class scope. LookupQualifiedName(Found, RD); @@ -2504,27 +2690,20 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Found.suppressDiagnostics(); - SmallVector<DeclAccessPair,4> Matches; - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) { - NamedDecl *ND = (*F)->getUnderlyingDecl(); + bool Overaligned = hasNewExtendedAlignment(*this, Context.getRecordType(RD)); - // Ignore template operator delete members from the check for a usual - // deallocation function. - if (isa<FunctionTemplateDecl>(ND)) - continue; + // C++17 [expr.delete]p10: + // If the deallocation functions have class scope, the one without a + // parameter of type std::size_t is selected. + llvm::SmallVector<UsualDeallocFnInfo, 4> Matches; + resolveDeallocationOverload(*this, Found, /*WantSize*/ false, + /*WantAlign*/ Overaligned, &Matches); - if (cast<CXXMethodDecl>(ND)->isUsualDeallocationFunction()) - Matches.push_back(F.getPair()); - } - - if (getLangOpts().CUDA) - EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); - - // There's exactly one suitable operator; pick it. + // If we could find an overload, use it. if (Matches.size() == 1) { - Operator = cast<CXXMethodDecl>(Matches[0]->getUnderlyingDecl()); + Operator = cast<CXXMethodDecl>(Matches[0].FD); + // FIXME: DiagnoseUseOfDecl? if (Operator->isDeleted()) { if (Diagnose) { Diag(StartLoc, diag::err_deleted_function_use); @@ -2534,21 +2713,21 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, } if (CheckAllocationAccess(StartLoc, SourceRange(), Found.getNamingClass(), - Matches[0], Diagnose) == AR_inaccessible) + Matches[0].Found, Diagnose) == AR_inaccessible) return true; return false; + } - // We found multiple suitable operators; complain about the ambiguity. - } else if (!Matches.empty()) { + // We found multiple suitable operators; complain about the ambiguity. + // FIXME: The standard doesn't say to do this; it appears that the intent + // is that this should never happen. + if (!Matches.empty()) { if (Diagnose) { Diag(StartLoc, diag::err_ambiguous_suitable_delete_member_function_found) << Name << RD; - - for (SmallVectorImpl<DeclAccessPair>::iterator - F = Matches.begin(), FEnd = Matches.end(); F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), - diag::note_member_declared_here) << Name; + for (auto &Match : Matches) + Diag(Match.FD->getLocation(), diag::note_member_declared_here) << Name; } return true; } @@ -2560,9 +2739,8 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Diag(StartLoc, diag::err_no_suitable_delete_member_function_found) << Name << RD; - for (LookupResult::iterator F = Found.begin(), FEnd = Found.end(); - F != FEnd; ++F) - Diag((*F)->getUnderlyingDecl()->getLocation(), + for (NamedDecl *D : Found) + Diag(D->getUnderlyingDecl()->getLocation(), diag::note_member_declared_here) << Name; } return true; @@ -2593,7 +2771,7 @@ public: /// translation unit. False, if this is the initial analysis at the point /// delete-expression was encountered. explicit MismatchingNewDeleteDetector(bool EndOfTU) - : IsArrayForm(false), Field(nullptr), EndOfTU(EndOfTU), + : Field(nullptr), IsArrayForm(false), EndOfTU(EndOfTU), HasUndefinedConstructors(false) {} /// \brief Checks whether pointee of a delete-expression is initialized with @@ -2612,11 +2790,11 @@ public: /// \param DeleteWasArrayForm Array form-ness of the delete-expression used /// for deleting the \p Field. MismatchResult analyzeField(FieldDecl *Field, bool DeleteWasArrayForm); + FieldDecl *Field; /// List of mismatching new-expressions used for initialization of the pointee llvm::SmallVector<const CXXNewExpr *, 4> NewExprs; /// Indicates whether delete-expression was in array form. bool IsArrayForm; - FieldDecl *Field; private: const bool EndOfTU; @@ -2921,7 +3099,7 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, QualType PointeeElem = Context.getBaseElementType(Pointee); if (unsigned AddressSpace = Pointee.getAddressSpace()) - return Diag(Ex.get()->getLocStart(), + return Diag(Ex.get()->getLocStart(), diag::err_address_space_qualified_delete) << Pointee.getUnqualifiedType() << AddressSpace; @@ -2973,7 +3151,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, // Otherwise, the usual operator delete[] should be the // function we just found. else if (OperatorDelete && isa<CXXMethodDecl>(OperatorDelete)) - UsualArrayDeleteWantsSize = (OperatorDelete->getNumParams() == 2); + UsualArrayDeleteWantsSize = + UsualDeallocFnInfo(*this, + DeclAccessPair::make(OperatorDelete, AS_public)) + .HasSizeT; } if (!PointeeRD->hasIrrelevantDestructor()) @@ -2990,20 +3171,24 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, SourceLocation()); } - if (!OperatorDelete) + if (!OperatorDelete) { + bool IsComplete = isCompleteType(StartLoc, Pointee); + bool CanProvideSize = + IsComplete && (!ArrayForm || UsualArrayDeleteWantsSize || + Pointee.isDestructedType()); + bool Overaligned = hasNewExtendedAlignment(*this, Pointee); + // Look for a global declaration. - OperatorDelete = FindUsualDeallocationFunction( - StartLoc, isCompleteType(StartLoc, Pointee) && - (!ArrayForm || UsualArrayDeleteWantsSize || - Pointee.isDestructedType()), - DeleteName); + OperatorDelete = FindUsualDeallocationFunction(StartLoc, CanProvideSize, + Overaligned, DeleteName); + } MarkFunctionReferenced(StartLoc, OperatorDelete); // Check access and ambiguity of operator delete and destructor. if (PointeeRD) { if (CXXDestructorDecl *Dtor = LookupDestructor(PointeeRD)) { - CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, + CheckDestructorAccess(Ex.get()->getExprLoc(), Dtor, PDiag(diag::err_access_dtor) << PointeeElem); } } @@ -3234,7 +3419,7 @@ static ExprResult BuildCXXCastArgument(Sema &S, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const ImplicitConversionSequence &ICS, - AssignmentAction Action, + AssignmentAction Action, CheckedConversionKind CCK) { switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: { @@ -3309,6 +3494,10 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, llvm_unreachable("Cannot perform an ellipsis conversion"); case ImplicitConversionSequence::BadConversion: + bool Diagnosed = + DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType, + From->getType(), From, Action); + assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed; return ExprError(); } @@ -3324,16 +3513,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ExprResult Sema::PerformImplicitConversion(Expr *From, QualType ToType, const StandardConversionSequence& SCS, - AssignmentAction Action, + AssignmentAction Action, CheckedConversionKind CCK) { bool CStyle = (CCK == CCK_CStyleCast || CCK == CCK_FunctionalCast); - + // Overall FIXME: we are recomputing too many types here and doing far too // much extra work. What this means is that we need to keep track of more // information that is computed when we try the implicit conversion initially, // so that we don't need to recompute anything here. QualType FromType = From->getType(); - + if (SCS.CopyConstructor) { // FIXME: When can ToType be a reference type? assert(!ToType->isReferenceType()); @@ -3403,13 +3592,13 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Array_To_Pointer: FromType = Context.getArrayDecayedType(FromType); - From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, + From = ImpCastExprToType(From, FromType, CK_ArrayToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Function_To_Pointer: FromType = Context.getPointerType(FromType); - From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, + From = ImpCastExprToType(From, FromType, CK_FunctionToPointerDecay, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3446,16 +3635,6 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing else to do. break; - case ICK_NoReturn_Adjustment: - // If both sides are functions (or pointers/references to them), there could - // be incompatible exception declarations. - if (CheckExceptionSpecCompatibility(From, ToType)) - return ExprError(); - - From = ImpCastExprToType(From, ToType, CK_NoOp, - VK_RValue, /*BasePath=*/nullptr, CCK).get(); - break; - case ICK_Integral_Promotion: case ICK_Integral_Conversion: if (ToType->isBooleanType()) { @@ -3472,7 +3651,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, case ICK_Floating_Promotion: case ICK_Floating_Conversion: - From = ImpCastExprToType(From, ToType, CK_FloatingCast, + From = ImpCastExprToType(From, ToType, CK_FloatingCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3491,22 +3670,22 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } else { CK = CK_IntegralComplexCast; } - From = ImpCastExprToType(From, ToType, CK, + From = ImpCastExprToType(From, ToType, CK, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } case ICK_Floating_Integral: if (ToType->isRealFloatingType()) - From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, + From = ImpCastExprToType(From, ToType, CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); else - From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, + From = ImpCastExprToType(From, ToType, CK_FloatingToIntegral, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; case ICK_Compatible_Conversion: - From = ImpCastExprToType(From, ToType, CK_NoOp, + From = ImpCastExprToType(From, ToType, CK_NoOp, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3528,20 +3707,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, if (From->getType()->isObjCObjectPointerType() && ToType->isObjCObjectPointerType()) EmitRelatedResultTypeNote(From); - } + } else if (getLangOpts().ObjCAutoRefCount && - !CheckObjCARCUnavailableWeakConversion(ToType, + !CheckObjCARCUnavailableWeakConversion(ToType, From->getType())) { if (Action == AA_Initializing) - Diag(From->getLocStart(), + Diag(From->getLocStart(), diag::err_arc_weak_unavailable_assign); else Diag(From->getLocStart(), - diag::err_arc_convesion_of_weak_unavailable) - << (Action == AA_Casting) << From->getType() << ToType + diag::err_arc_convesion_of_weak_unavailable) + << (Action == AA_Casting) << From->getType() << ToType << From->getSourceRange(); } - + CastKind Kind = CK_Invalid; CXXCastPath BasePath; if (CheckPointerConversion(From, ToType, Kind, BasePath, CStyle)) @@ -3589,7 +3768,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } From = ImpCastExprToType(From, Context.BoolTy, - ScalarTypeToBooleanCastKind(FromType), + ScalarTypeToBooleanCastKind(FromType), VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3610,7 +3789,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } case ICK_Vector_Conversion: - From = ImpCastExprToType(From, ToType, CK_BitCast, + From = ImpCastExprToType(From, ToType, CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; @@ -3655,7 +3834,7 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // _Complex x -> x From = ImpCastExprToType(From, ElType, isFloatingComplex ? CK_FloatingComplexToReal - : CK_IntegralComplexToReal, + : CK_IntegralComplexToReal, VK_RValue, /*BasePath=*/nullptr, CCK).get(); // x -> y @@ -3663,23 +3842,23 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // do nothing } else if (ToType->isRealFloatingType()) { From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, + isFloatingComplex ? CK_FloatingCast : CK_IntegralToFloating, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } else { assert(ToType->isIntegerType()); From = ImpCastExprToType(From, ToType, - isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, + isFloatingComplex ? CK_FloatingToIntegral : CK_IntegralCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); } } break; - + case ICK_Block_Pointer_Conversion: { From = ImpCastExprToType(From, ToType.getUnqualifiedType(), CK_BitCast, VK_RValue, /*BasePath=*/nullptr, CCK).get(); break; } - + case ICK_TransparentUnionConversion: { ExprResult FromRes = From; Sema::AssignConvertType ConvTy = @@ -3699,12 +3878,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, From->getValueKind()).get(); break; + case ICK_Zero_Queue_Conversion: + From = ImpCastExprToType(From, ToType, + CK_ZeroToOCLQueue, + From->getValueKind()).get(); + break; + case ICK_Lvalue_To_Rvalue: case ICK_Array_To_Pointer: case ICK_Function_To_Pointer: + case ICK_Function_Conversion: case ICK_Qualification: case ICK_Num_Conversion_Kinds: case ICK_C_Only_Conversion: + case ICK_Incompatible_Pointer_Conversion: llvm_unreachable("Improper second standard conversion"); } @@ -3713,6 +3900,16 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, // Nothing to do. break; + case ICK_Function_Conversion: + // If both sides are functions (or pointers/references to them), there could + // be incompatible exception declarations. + if (CheckExceptionSpecCompatibility(From, ToType)) + return ExprError(); + + From = ImpCastExprToType(From, ToType, CK_NoOp, + VK_RValue, /*BasePath=*/nullptr, CCK).get(); + break; + case ICK_Qualification: { // The qualification keeps the category of the inner expression, unless the // target type isn't a reference. @@ -3882,8 +4079,8 @@ static bool CheckUnaryTypeTraitTypeCompleteness(Sema &S, TypeTrait UTT, static bool HasNoThrowOperator(const RecordType *RT, OverloadedOperatorKind Op, Sema &Self, SourceLocation KeyLoc, ASTContext &C, - bool (CXXRecordDecl::*HasTrivial)() const, - bool (CXXRecordDecl::*HasNonTrivial)() const, + bool (CXXRecordDecl::*HasTrivial)() const, + bool (CXXRecordDecl::*HasNonTrivial)() const, bool (CXXMethodDecl::*IsDesiredOp)() const) { CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); @@ -3979,7 +4176,7 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, return false; } } - + return T->isScalarType(); case UTT_IsCompound: return T->isCompoundType(); @@ -4158,12 +4355,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // false. if (T.isPODType(C) || T->isReferenceType()) return true; - + // Objective-C++ ARC: autorelease types don't require destruction. - if (T->isObjCLifetimeType() && + if (T->isObjCLifetimeType() && T.getObjCLifetime() == Qualifiers::OCL_Autoreleasing) return true; - + if (CXXRecordDecl *RD = C.getBaseElementType(T)->getAsCXXRecordDecl()) return RD->hasTrivialDestructor(); return false; @@ -4345,9 +4542,9 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, // definition for is_constructible, as defined below, is known to call // no operation that is not trivial. // - // The predicate condition for a template specialization - // is_constructible<T, Args...> shall be satisfied if and only if the - // following variable definition would be well-formed for some invented + // The predicate condition for a template specialization + // is_constructible<T, Args...> shall be satisfied if and only if the + // following variable definition would be well-formed for some invented // variable t: // // T t(create<Args>()...); @@ -4361,7 +4558,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, if (ArgTy->isVoidType() || ArgTy->isIncompleteArrayType()) continue; - if (S.RequireCompleteType(KWLoc, ArgTy, + if (S.RequireCompleteType(KWLoc, ArgTy, diag::err_incomplete_type_used_in_type_trait_expr)) return false; } @@ -4391,7 +4588,7 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, for (Expr &E : OpaqueArgExprs) ArgExprs.push_back(&E); - // Perform the initialization in an unevaluated context within a SFINAE + // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); Sema::SFINAETrap SFINAE(S, /*AccessCheckingSFINAE=*/true); @@ -4430,12 +4627,12 @@ static bool evaluateTypeTrait(Sema &S, TypeTrait Kind, SourceLocation KWLoc, } default: llvm_unreachable("not a TT"); } - + return false; } -ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, - ArrayRef<TypeSourceInfo *> Args, +ExprResult Sema::BuildTypeTrait(TypeTrait Kind, SourceLocation KWLoc, + ArrayRef<TypeSourceInfo *> Args, SourceLocation RParenLoc) { QualType ResultType = Context.getLogicalOperationType(); @@ -4464,14 +4661,14 @@ ExprResult Sema::ActOnTypeTrait(TypeTrait Kind, SourceLocation KWLoc, SourceLocation RParenLoc) { SmallVector<TypeSourceInfo *, 4> ConvertedArgs; ConvertedArgs.reserve(Args.size()); - + for (unsigned I = 0, N = Args.size(); I != N; ++I) { TypeSourceInfo *TInfo; QualType T = GetTypeFromParser(Args[I], &TInfo); if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(T, KWLoc); - - ConvertedArgs.push_back(TInfo); + + ConvertedArgs.push_back(TInfo); } return BuildTypeTrait(Kind, KWLoc, ConvertedArgs, RParenLoc); @@ -4505,7 +4702,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // If Base and Derived are class types and are different types // (ignoring possible cv-qualifiers) then Derived shall be a // complete type. - if (Self.RequireCompleteType(KeyLoc, RhsT, + if (Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; @@ -4522,21 +4719,21 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // C++0x [meta.rel]p4: // Given the following function prototype: // - // template <class T> + // template <class T> // typename add_rvalue_reference<T>::type create(); // - // the predicate condition for a template specialization - // is_convertible<From, To> shall be satisfied if and only if - // the return expression in the following code would be + // the predicate condition for a template specialization + // is_convertible<From, To> shall be satisfied if and only if + // the return expression in the following code would be // well-formed, including any implicit conversions to the return // type of the function: // - // To test() { + // To test() { // return create<From>(); // } // - // Access checking is performed as if in a context unrelated to To and - // From. Only the validity of the immediate context of the expression + // Access checking is performed as if in a context unrelated to To and + // From. Only the validity of the immediate context of the expression // of the return-statement (including conversions to the return type) // is considered. // @@ -4565,10 +4762,10 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, OpaqueValueExpr From(KeyLoc, LhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(LhsT)); Expr *FromPtr = &From; - InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, + InitializationKind Kind(InitializationKind::CreateCopy(KeyLoc, SourceLocation())); - - // Perform the initialization in an unevaluated context within a SFINAE + + // Perform the initialization in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); @@ -4590,17 +4787,17 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, // is_assignable, is known to call no operation that is not trivial // // is_assignable is defined as: - // The expression declval<T>() = declval<U>() is well-formed when + // The expression declval<T>() = declval<U>() is well-formed when // treated as an unevaluated operand (Clause 5). // - // For both, T and U shall be complete types, (possibly cv-qualified) + // For both, T and U shall be complete types, (possibly cv-qualified) // void, or arrays of unknown bound. if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, LhsT, + Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() && - Self.RequireCompleteType(KeyLoc, RhsT, + Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr)) return false; @@ -4608,7 +4805,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, if (LhsT->isVoidType() || RhsT->isVoidType()) return false; - // Build expressions that emulate the effect of declval<T>() and + // Build expressions that emulate the effect of declval<T>() and // declval<U>(). if (LhsT->isObjectType() || LhsT->isFunctionType()) LhsT = Self.Context.getRValueReferenceType(LhsT); @@ -4618,8 +4815,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, Expr::getValueKindForType(LhsT)); OpaqueValueExpr Rhs(KeyLoc, RhsT.getNonLValueExprType(Self.Context), Expr::getValueKindForType(RhsT)); - - // Attempt the assignment in an unevaluated context within a SFINAE + + // Attempt the assignment in an unevaluated context within a SFINAE // trap at translation unit scope. EnterExpressionEvaluationContext Unevaluated(Self, Sema::Unevaluated); Sema::SFINAETrap SFINAE(Self, /*AccessCheckingSFINAE=*/true); @@ -4789,11 +4986,14 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, !RHS.get()->getType()->isPlaceholderType() && "placeholders should have been weeded out by now"); - // The LHS undergoes lvalue conversions if this is ->*. - if (isIndirect) { + // The LHS undergoes lvalue conversions if this is ->*, and undergoes the + // temporary materialization conversion otherwise. + if (isIndirect) LHS = DefaultLvalueConversion(LHS.get()); - if (LHS.isInvalid()) return QualType(); - } + else if (LHS.get()->isRValue()) + LHS = TemporaryMaterializationConversion(LHS.get()); + if (LHS.isInvalid()) + return QualType(); // The RHS always undergoes lvalue conversions. RHS = DefaultLvalueConversion(RHS.get()); @@ -5005,8 +5205,7 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, // // This actually refers very narrowly to the lvalue-to-rvalue conversion, not // to the array-to-pointer or function-to-pointer conversions. - if (!TTy->getAs<TagType>()) - TTy = TTy.getUnqualifiedType(); + TTy = TTy.getNonLValueExprType(Self.Context); InitializedEntity Entity = InitializedEntity::InitializeTemporary(TTy); InitializationSequence InitSeq(Self, Entity, Kind, From); @@ -5052,7 +5251,7 @@ static bool FindConditionalOverload(Sema &Self, ExprResult &LHS, ExprResult &RHS Self.MarkFunctionReferenced(QuestionLoc, Best->Function); return false; } - + case OR_No_Viable_Function: // Emit a better diagnostic if one of the expressions is a null pointer @@ -5199,23 +5398,35 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // if both are glvalues of the same value category and the same type except // for cv-qualification, an attempt is made to convert each of those // operands to the type of the other. + // FIXME: + // Resolving a defect in P0012R1: we extend this to cover all cases where + // one of the operands is reference-compatible with the other, in order + // to support conditionals between functions differing in noexcept. ExprValueKind LVK = LHS.get()->getValueKind(); ExprValueKind RVK = RHS.get()->getValueKind(); if (!Context.hasSameType(LTy, RTy) && - Context.hasSameUnqualifiedType(LTy, RTy) && LVK == RVK && LVK != VK_RValue) { - // Since the unqualified types are reference-related and we require the - // result to be as if a reference bound directly, the only conversion - // we can perform is to add cv-qualifiers. - Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers()); - Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers()); - if (RCVR.isStrictSupersetOf(LCVR)) { - LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); - LTy = LHS.get()->getType(); - } - else if (LCVR.isStrictSupersetOf(RCVR)) { + // DerivedToBase was already handled by the class-specific case above. + // FIXME: Should we allow ObjC conversions here? + bool DerivedToBase, ObjCConversion, ObjCLifetimeConversion; + if (CompareReferenceRelationship( + QuestionLoc, LTy, RTy, DerivedToBase, + ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && + !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + // [...] subject to the constraint that the reference must bind + // directly [...] + !RHS.get()->refersToBitField() && + !RHS.get()->refersToVectorElement()) { RHS = ImpCastExprToType(RHS.get(), LTy, CK_NoOp, RVK); RTy = RHS.get()->getType(); + } else if (CompareReferenceRelationship( + QuestionLoc, RTy, LTy, DerivedToBase, + ObjCConversion, ObjCLifetimeConversion) == Ref_Compatible && + !DerivedToBase && !ObjCConversion && !ObjCLifetimeConversion && + !LHS.get()->refersToBitField() && + !LHS.get()->refersToVectorElement()) { + LHS = ImpCastExprToType(LHS.get(), RTy, CK_NoOp, LVK); + LTy = LHS.get()->getType(); } } @@ -5234,6 +5445,20 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (LHS.get()->getObjectKind() == OK_BitField || RHS.get()->getObjectKind() == OK_BitField) OK = OK_BitField; + + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + Qualifiers Qs = LTy.getQualifiers(); + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS, + /*ConvertArgs*/false); + LTy = Context.getQualifiedType(LTy, Qs); + + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + assert(Context.hasSameType(LTy, RTy) && "bad composite pointer type"); + } + return LTy; } @@ -5267,9 +5492,6 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { if (LTy->isRecordType()) { // The operands have class type. Make a temporary copy. - if (RequireNonAbstractType(QuestionLoc, LTy, - diag::err_allocation_of_abstract_type)) - return QualType(); InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); ExprResult LHSCopy = PerformCopyInitialization(Entity, @@ -5288,6 +5510,14 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, RHS = RHSCopy; } + // If we have function pointer types, unify them anyway to unify their + // exception specifications, if any. + if (LTy->isFunctionPointerType() || LTy->isMemberFunctionPointerType()) { + LTy = FindCompositePointerType(QuestionLoc, LHS, RHS); + assert(!LTy.isNull() && "failed to find composite pointer type for " + "canonically equivalent function ptr types"); + } + return LTy; } @@ -5329,19 +5559,9 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, // performed to bring them to a common type, whose cv-qualification // shall match the cv-qualification of either the second or the third // operand. The result is of the common type. - bool NonStandardCompositeType = false; - QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS, - isSFINAEContext() ? nullptr - : &NonStandardCompositeType); - if (!Composite.isNull()) { - if (NonStandardCompositeType) - Diag(QuestionLoc, - diag::ext_typecheck_cond_incompatible_operands_nonstandard) - << LTy << RTy << Composite - << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); - + QualType Composite = FindCompositePointerType(QuestionLoc, LHS, RHS); + if (!Composite.isNull()) return Composite; - } // Similarly, attempt to find composite type of two objective-c pointers. Composite = FindCompositeObjCPointerType(LHS, RHS, QuestionLoc); @@ -5358,90 +5578,176 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, return QualType(); } +static FunctionProtoType::ExceptionSpecInfo +mergeExceptionSpecs(Sema &S, FunctionProtoType::ExceptionSpecInfo ESI1, + FunctionProtoType::ExceptionSpecInfo ESI2, + SmallVectorImpl<QualType> &ExceptionTypeStorage) { + ExceptionSpecificationType EST1 = ESI1.Type; + ExceptionSpecificationType EST2 = ESI2.Type; + + // If either of them can throw anything, that is the result. + if (EST1 == EST_None) return ESI1; + if (EST2 == EST_None) return ESI2; + if (EST1 == EST_MSAny) return ESI1; + if (EST2 == EST_MSAny) return ESI2; + + // If either of them is non-throwing, the result is the other. + if (EST1 == EST_DynamicNone) return ESI2; + if (EST2 == EST_DynamicNone) return ESI1; + if (EST1 == EST_BasicNoexcept) return ESI2; + if (EST2 == EST_BasicNoexcept) return ESI1; + + // If either of them is a non-value-dependent computed noexcept, that + // determines the result. + if (EST2 == EST_ComputedNoexcept && ESI2.NoexceptExpr && + !ESI2.NoexceptExpr->isValueDependent()) + return !ESI2.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI2 : ESI1; + if (EST1 == EST_ComputedNoexcept && ESI1.NoexceptExpr && + !ESI1.NoexceptExpr->isValueDependent()) + return !ESI1.NoexceptExpr->EvaluateKnownConstInt(S.Context) ? ESI1 : ESI2; + // If we're left with value-dependent computed noexcept expressions, we're + // stuck. Before C++17, we can just drop the exception specification entirely, + // since it's not actually part of the canonical type. And this should never + // happen in C++17, because it would mean we were computing the composite + // pointer type of dependent types, which should never happen. + if (EST1 == EST_ComputedNoexcept || EST2 == EST_ComputedNoexcept) { + assert(!S.getLangOpts().CPlusPlus1z && + "computing composite pointer type of dependent types"); + return FunctionProtoType::ExceptionSpecInfo(); + } + + // Switch over the possibilities so that people adding new values know to + // update this function. + switch (EST1) { + case EST_None: + case EST_DynamicNone: + case EST_MSAny: + case EST_BasicNoexcept: + case EST_ComputedNoexcept: + llvm_unreachable("handled above"); + + case EST_Dynamic: { + // This is the fun case: both exception specifications are dynamic. Form + // the union of the two lists. + assert(EST2 == EST_Dynamic && "other cases should already be handled"); + llvm::SmallPtrSet<QualType, 8> Found; + for (auto &Exceptions : {ESI1.Exceptions, ESI2.Exceptions}) + for (QualType E : Exceptions) + if (Found.insert(S.Context.getCanonicalType(E)).second) + ExceptionTypeStorage.push_back(E); + + FunctionProtoType::ExceptionSpecInfo Result(EST_Dynamic); + Result.Exceptions = ExceptionTypeStorage; + return Result; + } + + case EST_Unevaluated: + case EST_Uninstantiated: + case EST_Unparsed: + llvm_unreachable("shouldn't see unresolved exception specifications here"); + } + + llvm_unreachable("invalid ExceptionSpecificationType"); +} + /// \brief Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 -/// and @p E2 according to C++11 5.9p2. It converts both expressions to this +/// and @p E2 according to C++1z 5p14. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. /// /// \param Loc The location of the operator requiring these two expressions to /// be converted to the composite pointer type. /// -/// If \p NonStandardCompositeType is non-NULL, then we are permitted to find -/// a non-standard (but still sane) composite type to which both expressions -/// can be converted. When such a type is chosen, \c *NonStandardCompositeType -/// will be set true. +/// \param ConvertArgs If \c false, do not convert E1 and E2 to the target type. QualType Sema::FindCompositePointerType(SourceLocation Loc, Expr *&E1, Expr *&E2, - bool *NonStandardCompositeType) { - if (NonStandardCompositeType) - *NonStandardCompositeType = false; - + bool ConvertArgs) { assert(getLangOpts().CPlusPlus && "This function assumes C++"); + + // C++1z [expr]p14: + // The composite pointer type of two operands p1 and p2 having types T1 + // and T2 QualType T1 = E1->getType(), T2 = E2->getType(); - // C++11 5.9p2 - // Pointer conversions and qualification conversions are performed on - // pointer operands to bring them to their composite pointer type. If - // one operand is a null pointer constant, the composite pointer type is - // std::nullptr_t if the other operand is also a null pointer constant or, - // if the other operand is a pointer, the type of the other operand. - if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && - !T2->isAnyPointerType() && !T2->isMemberPointerType()) { - if (T1->isNullPtrType() && - E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); - return T1; - } - if (T2->isNullPtrType() && - E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); - return T2; - } + // where at least one is a pointer or pointer to member type or + // std::nullptr_t is: + bool T1IsPointerLike = T1->isAnyPointerType() || T1->isMemberPointerType() || + T1->isNullPtrType(); + bool T2IsPointerLike = T2->isAnyPointerType() || T2->isMemberPointerType() || + T2->isNullPtrType(); + if (!T1IsPointerLike && !T2IsPointerLike) return QualType(); - } - if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - if (T2->isMemberPointerType()) - E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).get(); - else - E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).get(); - return T2; - } - if (E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - if (T1->isMemberPointerType()) - E2 = ImpCastExprToType(E2, T1, CK_NullToMemberPointer).get(); - else - E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).get(); + // - if both p1 and p2 are null pointer constants, std::nullptr_t; + // This can't actually happen, following the standard, but we also use this + // to implement the end of [expr.conv], which hits this case. + // + // - if either p1 or p2 is a null pointer constant, T2 or T1, respectively; + if (T1IsPointerLike && + E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + if (ConvertArgs) + E2 = ImpCastExprToType(E2, T1, T1->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); return T1; } + if (T2IsPointerLike && + E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + if (ConvertArgs) + E1 = ImpCastExprToType(E1, T2, T2->isMemberPointerType() + ? CK_NullToMemberPointer + : CK_NullToPointer).get(); + return T2; + } // Now both have to be pointers or member pointers. - if ((!T1->isPointerType() && !T1->isMemberPointerType()) || - (!T2->isPointerType() && !T2->isMemberPointerType())) + if (!T1IsPointerLike || !T2IsPointerLike) return QualType(); - - // Otherwise, of one of the operands has type "pointer to cv1 void," then - // the other has type "pointer to cv2 T" and the composite pointer type is - // "pointer to cv12 void," where cv12 is the union of cv1 and cv2. - // Otherwise, the composite pointer type is a pointer type similar to the - // type of one of the operands, with a cv-qualification signature that is - // the union of the cv-qualification signatures of the operand types. - // In practice, the first part here is redundant; it's subsumed by the second. - // What we do here is, we build the two possible composite types, and try the - // conversions in both directions. If only one works, or if the two composite - // types are the same, we have succeeded. + assert(!T1->isNullPtrType() && !T2->isNullPtrType() && + "nullptr_t should be a null pointer constant"); + + // - if T1 or T2 is "pointer to cv1 void" and the other type is + // "pointer to cv2 T", "pointer to cv12 void", where cv12 is + // the union of cv1 and cv2; + // - if T1 or T2 is "pointer to noexcept function" and the other type is + // "pointer to function", where the function types are otherwise the same, + // "pointer to function"; + // FIXME: This rule is defective: it should also permit removing noexcept + // from a pointer to member function. As a Clang extension, we also + // permit removing 'noreturn', so we generalize this rule to; + // - [Clang] If T1 and T2 are both of type "pointer to function" or + // "pointer to member function" and the pointee types can be unified + // by a function pointer conversion, that conversion is applied + // before checking the following rules. + // - if T1 is "pointer to cv1 C1" and T2 is "pointer to cv2 C2", where C1 + // is reference-related to C2 or C2 is reference-related to C1 (8.6.3), + // the cv-combined type of T1 and T2 or the cv-combined type of T2 and T1, + // respectively; + // - if T1 is "pointer to member of C1 of type cv1 U1" and T2 is "pointer + // to member of C2 of type cv2 U2" where C1 is reference-related to C2 or + // C2 is reference-related to C1 (8.6.3), the cv-combined type of T2 and + // T1 or the cv-combined type of T1 and T2, respectively; + // - if T1 and T2 are similar types (4.5), the cv-combined type of T1 and + // T2; + // + // If looked at in the right way, these bullets all do the same thing. + // What we do here is, we build the two possible cv-combined types, and try + // the conversions in both directions. If only one works, or if the two + // composite types are the same, we have succeeded. // FIXME: extended qualifiers? - typedef SmallVector<unsigned, 4> QualifierVector; - QualifierVector QualifierUnion; - typedef SmallVector<std::pair<const Type *, const Type *>, 4> - ContainingClassVector; - ContainingClassVector MemberOfClass; - QualType Composite1 = Context.getCanonicalType(T1), - Composite2 = Context.getCanonicalType(T2); + // + // Note that this will fail to find a composite pointer type for "pointer + // to void" and "pointer to function". We can't actually perform the final + // conversion in this case, even though a composite pointer type formally + // exists. + SmallVector<unsigned, 4> QualifierUnion; + SmallVector<std::pair<const Type *, const Type *>, 4> MemberOfClass; + QualType Composite1 = T1; + QualType Composite2 = T2; unsigned NeedConstBefore = 0; - do { + while (true) { const PointerType *Ptr1, *Ptr2; if ((Ptr1 = Composite1->getAs<PointerType>()) && (Ptr2 = Composite2->getAs<PointerType>())) { @@ -5450,8 +5756,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. - if (NonStandardCompositeType && - Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( @@ -5468,8 +5773,7 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // If we're allowed to create a non-standard composite type, keep track // of where we need to fill in additional 'const' qualifiers. - if (NonStandardCompositeType && - Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) + if (Composite1.getCVRQualifiers() != Composite2.getCVRQualifiers()) NeedConstBefore = QualifierUnion.size(); QualifierUnion.push_back( @@ -5483,109 +5787,125 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, // Cannot unwrap any more types. break; - } while (true); + } - if (NeedConstBefore && NonStandardCompositeType) { + // Apply the function pointer conversion to unify the types. We've already + // unwrapped down to the function types, and we want to merge rather than + // just convert, so do this ourselves rather than calling + // IsFunctionConversion. + // + // FIXME: In order to match the standard wording as closely as possible, we + // currently only do this under a single level of pointers. Ideally, we would + // allow this in general, and set NeedConstBefore to the relevant depth on + // the side(s) where we changed anything. + if (QualifierUnion.size() == 1) { + if (auto *FPT1 = Composite1->getAs<FunctionProtoType>()) { + if (auto *FPT2 = Composite2->getAs<FunctionProtoType>()) { + FunctionProtoType::ExtProtoInfo EPI1 = FPT1->getExtProtoInfo(); + FunctionProtoType::ExtProtoInfo EPI2 = FPT2->getExtProtoInfo(); + + // The result is noreturn if both operands are. + bool Noreturn = + EPI1.ExtInfo.getNoReturn() && EPI2.ExtInfo.getNoReturn(); + EPI1.ExtInfo = EPI1.ExtInfo.withNoReturn(Noreturn); + EPI2.ExtInfo = EPI2.ExtInfo.withNoReturn(Noreturn); + + // The result is nothrow if both operands are. + SmallVector<QualType, 8> ExceptionTypeStorage; + EPI1.ExceptionSpec = EPI2.ExceptionSpec = + mergeExceptionSpecs(*this, EPI1.ExceptionSpec, EPI2.ExceptionSpec, + ExceptionTypeStorage); + + Composite1 = Context.getFunctionType(FPT1->getReturnType(), + FPT1->getParamTypes(), EPI1); + Composite2 = Context.getFunctionType(FPT2->getReturnType(), + FPT2->getParamTypes(), EPI2); + } + } + } + + if (NeedConstBefore) { // Extension: Add 'const' to qualifiers that come before the first qualifier // mismatch, so that our (non-standard!) composite type meets the // requirements of C++ [conv.qual]p4 bullet 3. - for (unsigned I = 0; I != NeedConstBefore; ++I) { - if ((QualifierUnion[I] & Qualifiers::Const) == 0) { + for (unsigned I = 0; I != NeedConstBefore; ++I) + if ((QualifierUnion[I] & Qualifiers::Const) == 0) QualifierUnion[I] = QualifierUnion[I] | Qualifiers::Const; - *NonStandardCompositeType = true; - } - } } // Rewrap the composites as pointers or member pointers with the union CVRs. - ContainingClassVector::reverse_iterator MOC - = MemberOfClass.rbegin(); - for (QualifierVector::reverse_iterator - I = QualifierUnion.rbegin(), - E = QualifierUnion.rend(); - I != E; (void)++I, ++MOC) { - Qualifiers Quals = Qualifiers::fromCVRMask(*I); - if (MOC->first && MOC->second) { + auto MOC = MemberOfClass.rbegin(); + for (unsigned CVR : llvm::reverse(QualifierUnion)) { + Qualifiers Quals = Qualifiers::fromCVRMask(CVR); + auto Classes = *MOC++; + if (Classes.first && Classes.second) { // Rebuild member pointer type Composite1 = Context.getMemberPointerType( - Context.getQualifiedType(Composite1, Quals), - MOC->first); + Context.getQualifiedType(Composite1, Quals), Classes.first); Composite2 = Context.getMemberPointerType( - Context.getQualifiedType(Composite2, Quals), - MOC->second); + Context.getQualifiedType(Composite2, Quals), Classes.second); } else { // Rebuild pointer type - Composite1 - = Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); - Composite2 - = Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); + Composite1 = + Context.getPointerType(Context.getQualifiedType(Composite1, Quals)); + Composite2 = + Context.getPointerType(Context.getQualifiedType(Composite2, Quals)); } } - // Try to convert to the first composite pointer type. - InitializedEntity Entity1 - = InitializedEntity::InitializeTemporary(Composite1); - InitializationKind Kind - = InitializationKind::CreateCopy(Loc, SourceLocation()); - InitializationSequence E1ToC1(*this, Entity1, Kind, E1); - InitializationSequence E2ToC1(*this, Entity1, Kind, E2); - - if (E1ToC1 && E2ToC1) { - // Conversion to Composite1 is viable. - if (!Context.hasSameType(Composite1, Composite2)) { - // Composite2 is a different type from Composite1. Check whether - // Composite2 is also viable. - InitializedEntity Entity2 - = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, E1); - InitializationSequence E2ToC2(*this, Entity2, Kind, E2); - if (E1ToC2 && E2ToC2) { - // Both Composite1 and Composite2 are viable and are different; - // this is an ambiguity. - return QualType(); - } - } + struct Conversion { + Sema &S; + Expr *&E1, *&E2; + QualType Composite; + InitializedEntity Entity; + InitializationKind Kind; + InitializationSequence E1ToC, E2ToC; + bool Viable; + + Conversion(Sema &S, SourceLocation Loc, Expr *&E1, Expr *&E2, + QualType Composite) + : S(S), E1(E1), E2(E2), Composite(Composite), + Entity(InitializedEntity::InitializeTemporary(Composite)), + Kind(InitializationKind::CreateCopy(Loc, SourceLocation())), + E1ToC(S, Entity, Kind, E1), E2ToC(S, Entity, Kind, E2), + Viable(E1ToC && E2ToC) {} + + bool perform() { + ExprResult E1Result = E1ToC.Perform(S, Entity, Kind, E1); + if (E1Result.isInvalid()) + return true; + E1 = E1Result.getAs<Expr>(); - // Convert E1 to Composite1 - ExprResult E1Result - = E1ToC1.Perform(*this, Entity1, Kind, E1); - if (E1Result.isInvalid()) - return QualType(); - E1 = E1Result.getAs<Expr>(); + ExprResult E2Result = E2ToC.Perform(S, Entity, Kind, E2); + if (E2Result.isInvalid()) + return true; + E2 = E2Result.getAs<Expr>(); - // Convert E2 to Composite1 - ExprResult E2Result - = E2ToC1.Perform(*this, Entity1, Kind, E2); - if (E2Result.isInvalid()) - return QualType(); - E2 = E2Result.getAs<Expr>(); + return false; + } + }; - return Composite1; + // Try to convert to each composite pointer type. + Conversion C1(*this, Loc, E1, E2, Composite1); + if (C1.Viable && Context.hasSameType(Composite1, Composite2)) { + if (ConvertArgs && C1.perform()) + return QualType(); + return C1.Composite; } + Conversion C2(*this, Loc, E1, E2, Composite2); - // Check whether Composite2 is viable. - InitializedEntity Entity2 - = InitializedEntity::InitializeTemporary(Composite2); - InitializationSequence E1ToC2(*this, Entity2, Kind, E1); - InitializationSequence E2ToC2(*this, Entity2, Kind, E2); - if (!E1ToC2 || !E2ToC2) + if (C1.Viable == C2.Viable) { + // Either Composite1 and Composite2 are viable and are different, or + // neither is viable. + // FIXME: How both be viable and different? return QualType(); + } - // Convert E1 to Composite2 - ExprResult E1Result - = E1ToC2.Perform(*this, Entity2, Kind, E1); - if (E1Result.isInvalid()) - return QualType(); - E1 = E1Result.getAs<Expr>(); - - // Convert E2 to Composite2 - ExprResult E2Result - = E2ToC2.Perform(*this, Entity2, Kind, E2); - if (E2Result.isInvalid()) + // Convert to the chosen type. + if (ConvertArgs && (C1.Viable ? C1 : C2).perform()) return QualType(); - E2 = E2Result.getAs<Expr>(); - return Composite2; + return C1.Viable ? C1.Composite : C2.Composite; } ExprResult Sema::MaybeBindToTemporary(Expr *E) { @@ -5618,14 +5938,14 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { else if (MemberExpr *Mem = dyn_cast<MemberExpr>(Callee)) T = Mem->getMemberDecl()->getType(); } - + if (const PointerType *Ptr = T->getAs<PointerType>()) T = Ptr->getPointeeType(); else if (const BlockPointerType *Ptr = T->getAs<BlockPointerType>()) T = Ptr->getPointeeType(); 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?"); ReturnsRetained = FTy->getExtInfo().getProducesResult(); @@ -6012,7 +6332,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // so adjust the base type to the object type itself. if (BaseType->isObjCObjectPointerType()) BaseType = BaseType->getPointeeType(); - + // C++ [basic.lookup.classref]p2: // [...] If the type of the object expression is of pointer to scalar // type, the unqualified-id is looked up in the context of the complete @@ -6037,7 +6357,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, // The object type must be complete (or dependent), or // C++11 [expr.prim.general]p3: // Unlike the object expression in other contexts, *this is not required to - // be of complete type for purposes of class member access (5.2.5) outside + // be of complete type for purposes of class member access (5.2.5) outside // the member function body. if (!BaseType->isDependentType() && !isThisOutsideMemberFunctionBody(BaseType) && @@ -6053,7 +6373,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, return Base; } -static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, +static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, tok::TokenKind& OpKind, SourceLocation OpLoc) { if (Base->hasPlaceholderType()) { ExprResult result = S.CheckPlaceholderExpr(Base); @@ -6129,9 +6449,9 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, DestructedTypeStart); Destructed = PseudoDestructorTypeStorage(DestructedTypeInfo); - } else if (DestructedType.getObjCLifetime() != + } else if (DestructedType.getObjCLifetime() != ObjectType.getObjCLifetime()) { - + if (DestructedType.getObjCLifetime() == Qualifiers::OCL_None) { // Okay: just pretend that the user provided the correctly-qualified // type. @@ -6140,7 +6460,7 @@ ExprResult Sema::BuildPseudoDestructorExpr(Expr *Base, << ObjectType << DestructedType << Base->getSourceRange() << DestructedTypeInfo->getTypeLoc().getLocalSourceRange(); } - + // Recover by setting the destructed type to the object type. DestructedType = ObjectType; DestructedTypeInfo = Context.getTrivialTypeSourceInfo(ObjectType, @@ -6324,7 +6644,7 @@ ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, ExprResult Sema::ActOnPseudoDestructorExpr(Scope *S, Expr *Base, SourceLocation OpLoc, tok::TokenKind OpKind, - SourceLocation TildeLoc, + SourceLocation TildeLoc, const DeclSpec& DS) { QualType ObjectType; if (CheckArrow(*this, ObjectType, Base, OpKind, OpLoc)) @@ -6519,7 +6839,17 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { if (Res.isInvalid()) return E; E = Res.get(); - } + } + + // C++1z: + // If the expression is a prvalue after this optional conversion, the + // temporary materialization conversion is applied. + // + // We skip this step: IR generation is able to synthesize the storage for + // itself in the aggregate case, and adding the extra node to the AST is + // just clutter. + // FIXME: We don't emit lifetime markers for the temporaries due to this. + // FIXME: Do any other AST consumers care about this? return E; } @@ -6549,13 +6879,13 @@ ExprResult Sema::IgnoredValueConversions(Expr *E) { // we can unambiguously check if the variable is a constant expression. // - if the initializer is not value dependent - we can determine whether // it can be used to initialize a constant expression. If Init can not -// be used to initialize a constant expression we conclude that Var can +// be used to initialize a constant expression we conclude that Var can // never be a constant expression. // - FXIME: if the initializer is dependent, we can still do some analysis and // identify certain cases unambiguously as non-const by using a Visitor: // - such as those that involve odr-use of a ParmVarDecl, involve a new // delete, lambda-expr, dynamic-cast, reinterpret-cast etc... -static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, +static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, ASTContext &Context) { if (isa<ParmVarDecl>(Var)) return true; const VarDecl *DefVD = nullptr; @@ -6575,14 +6905,14 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, return false; } - return !IsVariableAConstantExpression(Var, Context); + return !IsVariableAConstantExpression(Var, Context); } -/// \brief Check if the current lambda has any potential captures -/// that must be captured by any of its enclosing lambdas that are ready to -/// capture. If there is a lambda that can capture a nested -/// potential-capture, go ahead and do so. Also, check to see if any -/// variables are uncaptureable or do not involve an odr-use so do not +/// \brief Check if the current lambda has any potential captures +/// that must be captured by any of its enclosing lambdas that are ready to +/// capture. If there is a lambda that can capture a nested +/// potential-capture, go ahead and do so. Also, check to see if any +/// variables are uncaptureable or do not involve an odr-use so do not /// need to be captured. static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( @@ -6603,7 +6933,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( ArrayRef<const FunctionScopeInfo *> FunctionScopesArrayRef( S.FunctionScopes.data(), S.FunctionScopes.size()); - + // All the potentially captureable variables in the current nested // lambda (within a generic outer lambda), must be captured by an // outer lambda that is enclosed within a non-dependent context. @@ -6614,7 +6944,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( VarDecl *Var = nullptr; CurrentLSI->getPotentialVariableCapture(I, Var, VarExpr); // If the variable is clearly identified as non-odr-used and the full - // expression is not instantiation dependent, only then do we not + // expression is not instantiation dependent, only then do we not // need to check enclosing lambda's for speculative captures. // For e.g.: // Even though 'x' is not odr-used, it should be captured. @@ -6636,27 +6966,27 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( const unsigned FunctionScopeIndexOfCapturableLambda = Index.getValue(); MarkVarDeclODRUsed(Var, VarExpr->getExprLoc(), S, &FunctionScopeIndexOfCapturableLambda); - } - const bool IsVarNeverAConstantExpression = + } + const bool IsVarNeverAConstantExpression = VariableCanNeverBeAConstantExpression(Var, S.Context); if (!IsFullExprInstantiationDependent || IsVarNeverAConstantExpression) { // This full expression is not instantiation dependent or the variable - // can not be used in a constant expression - which means - // this variable must be odr-used here, so diagnose a + // can not be used in a constant expression - which means + // this variable must be odr-used here, so diagnose a // capture violation early, if the variable is un-captureable. // This is purely for diagnosing errors early. Otherwise, this // error would get diagnosed when the lambda becomes capture ready. QualType CaptureType, DeclRefType; SourceLocation ExprLoc = VarExpr->getExprLoc(); if (S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/false, CaptureType, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/false, CaptureType, DeclRefType, nullptr)) { // We will never be able to capture this variable, and we need // to be able to in any and all instantiations, so diagnose it. S.tryCaptureVariable(Var, ExprLoc, S.TryCapture_Implicit, - /*EllipsisLoc*/ SourceLocation(), - /*BuildAndDiagnose*/true, CaptureType, + /*EllipsisLoc*/ SourceLocation(), + /*BuildAndDiagnose*/true, CaptureType, DeclRefType, nullptr); } } @@ -6983,15 +7313,15 @@ Sema::CorrectDelayedTyposInExpr(Expr *E, VarDecl *InitDecl, ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, bool DiscardedValue, - bool IsConstexpr, + bool IsConstexpr, bool IsLambdaInitCaptureInitializer) { ExprResult FullExpr = FE; if (!FullExpr.get()) return ExprError(); - - // If we are an init-expression in a lambdas init-capture, we should not - // diagnose an unexpanded pack now (will be diagnosed once lambda-expr + + // If we are an init-expression in a lambdas init-capture, we should not + // diagnose an unexpanded pack now (will be diagnosed once lambda-expr // containing full-expression is done). // template<class ... Ts> void test(Ts ... t) { // test([&a(t)]() { <-- (t) is an init-expr that shouldn't be diagnosed now. @@ -7005,7 +7335,7 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // lambda where we've entered the introducer but not the body, or represent a // lambda where we've entered the body, depending on where the // parser/instantiation has got to). - if (!IsLambdaInitCaptureInitializer && + if (!IsLambdaInitCaptureInitializer && DiagnoseUnexpandedParameterPack(FullExpr.get())) return ExprError(); @@ -7033,13 +7363,13 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, CheckCompletedExpr(FullExpr.get(), CC, IsConstexpr); - // At the end of this full expression (which could be a deeply nested - // lambda), if there is a potential capture within the nested lambda, + // At the end of this full expression (which could be a deeply nested + // lambda), if there is a potential capture within the nested lambda, // have the outer capture-able lambda try and capture it. // Consider the following code: // void f(int, int); // void f(const int&, double); - // void foo() { + // void foo() { // const int x = 10, y = 20; // auto L = [=](auto a) { // auto M = [=](auto b) { @@ -7049,35 +7379,35 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // }; // } - // FIXME: Also consider what happens for something like this that involves - // the gnu-extension statement-expressions or even lambda-init-captures: + // FIXME: Also consider what happens for something like this that involves + // the gnu-extension statement-expressions or even lambda-init-captures: // void f() { // const int n = 0; // auto L = [&](auto a) { // +n + ({ 0; a; }); // }; // } - // - // Here, we see +n, and then the full-expression 0; ends, so we don't - // capture n (and instead remove it from our list of potential captures), - // and then the full-expression +n + ({ 0; }); ends, but it's too late + // + // Here, we see +n, and then the full-expression 0; ends, so we don't + // capture n (and instead remove it from our list of potential captures), + // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. LambdaScopeInfo *const CurrentLSI = getCurLambda(/*IgnoreCapturedRegions=*/true); - // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer + // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report - // for an example of the code that might cause this asynchrony. + // for an example of the code that might cause this asynchrony. // By ensuring we are in the context of a lambda's call operator // we can fix the bug (we only need to check whether we need to capture - // if we are within a lambda's body); but per the comments in that + // if we are within a lambda's body); but per the comments in that // PR, a proper fix would entail : // "Alternative suggestion: - // - Add to Sema an integer holding the smallest (outermost) scope - // index that we are *lexically* within, and save/restore/set to - // FunctionScopes.size() in InstantiatingTemplate's + // - Add to Sema an integer holding the smallest (outermost) scope + // index that we are *lexically* within, and save/restore/set to + // FunctionScopes.size() in InstantiatingTemplate's // constructor/destructor. - // - Teach the handful of places that iterate over FunctionScopes to + // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." DeclContext *DC = CurContext; while (DC && isa<CapturedDecl>(DC)) @@ -7096,34 +7426,34 @@ StmtResult Sema::ActOnFinishFullStmt(Stmt *FullStmt) { return MaybeCreateStmtWithCleanups(FullStmt); } -Sema::IfExistsResult +Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, CXXScopeSpec &SS, const DeclarationNameInfo &TargetNameInfo) { DeclarationName TargetName = TargetNameInfo.getName(); if (!TargetName) return IER_DoesNotExist; - + // If the name itself is dependent, then the result is dependent. if (TargetName.isDependentName()) return IER_Dependent; - + // Do the redeclaration lookup in the current scope. LookupResult R(*this, TargetNameInfo, Sema::LookupAnyName, Sema::NotForRedeclaration); LookupParsedName(R, S, &SS); R.suppressDiagnostics(); - + switch (R.getResultKind()) { case LookupResult::Found: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: case LookupResult::Ambiguous: return IER_Exists; - + case LookupResult::NotFound: return IER_DoesNotExist; - + case LookupResult::NotFoundInCurrentInstantiation: return IER_Dependent; } @@ -7131,23 +7461,17 @@ Sema::CheckMicrosoftIfExistsSymbol(Scope *S, llvm_unreachable("Invalid LookupResult Kind!"); } -Sema::IfExistsResult +Sema::IfExistsResult Sema::CheckMicrosoftIfExistsSymbol(Scope *S, SourceLocation KeywordLoc, bool IsIfExists, CXXScopeSpec &SS, UnqualifiedId &Name) { DeclarationNameInfo TargetNameInfo = GetNameFromUnqualifiedId(Name); - - // Check for unexpanded parameter packs. - SmallVector<UnexpandedParameterPack, 4> Unexpanded; - collectUnexpandedParameterPacks(SS, Unexpanded); - collectUnexpandedParameterPacks(TargetNameInfo, Unexpanded); - if (!Unexpanded.empty()) { - DiagnoseUnexpandedParameterPacks(KeywordLoc, - IsIfExists? UPPC_IfExists - : UPPC_IfNotExists, - Unexpanded); + + // Check for an unexpanded parameter pack. + auto UPPC = IsIfExists ? UPPC_IfExists : UPPC_IfNotExists; + if (DiagnoseUnexpandedParameterPack(SS, UPPC) || + DiagnoseUnexpandedParameterPack(TargetNameInfo, UPPC)) return IER_Error; - } - + return CheckMicrosoftIfExistsSymbol(S, SS, TargetNameInfo); } diff --git a/lib/Sema/SemaExprMember.cpp b/lib/Sema/SemaExprMember.cpp index 283621889f802..806a3d813ee87 100644 --- a/lib/Sema/SemaExprMember.cpp +++ b/lib/Sema/SemaExprMember.cpp @@ -269,6 +269,20 @@ Sema::BuildPossibleImplicitMemberExpr(const CXXScopeSpec &SS, llvm_unreachable("unexpected instance member access kind"); } +/// Determine whether input char is from rgba component set. +static bool +IsRGBA(char c) { + switch (c) { + case 'r': + case 'g': + case 'b': + case 'a': + return true; + default: + return false; + } +} + /// Check an ext-vector component access expression. /// /// VK should be set in advance to the value kind of the base @@ -308,11 +322,25 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, HalvingSwizzle = true; } else if (!HexSwizzle && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1) { + bool HasRGBA = IsRGBA(*compStr); do { + // Ensure that xyzw and rgba components don't intermingle. + if (HasRGBA != IsRGBA(*compStr)) + break; if (HasIndex[Idx]) HasRepeated = true; HasIndex[Idx] = true; compStr++; } while (*compStr && (Idx = vecType->getPointAccessorIdx(*compStr)) != -1); + + // Emit a warning if an rgba selector is used earlier than OpenCL 2.2 + if (HasRGBA || (*compStr && IsRGBA(*compStr))) { + if (S.getLangOpts().OpenCL && S.getLangOpts().OpenCLVersion < 220) { + const char *DiagBegin = HasRGBA ? CompName->getNameStart() : compStr; + S.Diag(OpLoc, diag::ext_opencl_ext_vector_type_rgba_selector) + << StringRef(DiagBegin, 1) + << S.getLangOpts().OpenCLVersion << SourceRange(CompLoc); + } + } } else { if (HexSwizzle) compStr++; while ((Idx = vecType->getNumericAccessorIdx(*compStr)) != -1) { @@ -339,7 +367,7 @@ CheckExtVectorComponent(Sema &S, QualType baseType, ExprValueKind &VK, compStr++; while (*compStr) { - if (!vecType->isAccessorWithinNumElements(*compStr++)) { + if (!vecType->isAccessorWithinNumElements(*compStr++, HexSwizzle)) { S.Diag(OpLoc, diag::err_ext_vector_component_exceeds_length) << baseType << SourceRange(CompLoc); return QualType(); @@ -743,12 +771,6 @@ Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType, false, ExtraArgs); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo); - ExprResult Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, SourceLocation loc, @@ -834,7 +856,7 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, // Make a nameInfo that properly uses the anonymous name. DeclarationNameInfo memberNameInfo(field->getDeclName(), loc); - result = BuildFieldReferenceExpr(*this, result, baseObjectIsPointer, + result = BuildFieldReferenceExpr(result, baseObjectIsPointer, SourceLocation(), EmptySS, field, foundDecl, memberNameInfo).get(); if (!result) @@ -855,9 +877,10 @@ Sema::BuildAnonymousStructUnionMemberReference(const CXXScopeSpec &SS, DeclAccessPair::make(field, field->getAccess()); result = - BuildFieldReferenceExpr(*this, result, /*isarrow*/ false, - SourceLocation(), (FI == FEnd ? SS : EmptySS), - field, fakeFoundDecl, memberNameInfo).get(); + BuildFieldReferenceExpr(result, /*isarrow*/ false, SourceLocation(), + (FI == FEnd ? SS : EmptySS), field, + fakeFoundDecl, memberNameInfo) + .get(); } return result; @@ -946,6 +969,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, BaseType = BaseType->castAs<PointerType>()->getPointeeType(); } R.setBaseObjectType(BaseType); + + // C++1z [expr.ref]p2: + // For the first option (dot) the first expression shall be a glvalue [...] + if (!IsArrow && BaseExpr->isRValue()) { + ExprResult Converted = TemporaryMaterializationConversion(BaseExpr); + if (Converted.isInvalid()) + return ExprError(); + BaseExpr = Converted.get(); + } LambdaScopeInfo *const CurLSI = getCurLambda(); // If this is an implicit member reference and the overloaded @@ -1125,8 +1157,8 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, return ExprError(); if (FieldDecl *FD = dyn_cast<FieldDecl>(MemberDecl)) - return BuildFieldReferenceExpr(*this, BaseExpr, IsArrow, OpLoc, SS, FD, - FoundDecl, MemberNameInfo); + return BuildFieldReferenceExpr(BaseExpr, IsArrow, OpLoc, SS, FD, FoundDecl, + MemberNameInfo); if (MSPropertyDecl *PD = dyn_cast<MSPropertyDecl>(MemberDecl)) return BuildMSPropertyRefExpr(*this, BaseExpr, IsArrow, SS, PD, @@ -1371,10 +1403,17 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, // Figure out the class that declares the ivar. assert(!ClassDeclared); + Decl *D = cast<Decl>(IV->getDeclContext()); - if (ObjCCategoryDecl *CAT = dyn_cast<ObjCCategoryDecl>(D)) - D = CAT->getClassInterface(); - ClassDeclared = cast<ObjCInterfaceDecl>(D); + if (auto *Category = dyn_cast<ObjCCategoryDecl>(D)) + D = Category->getClassInterface(); + + if (auto *Implementation = dyn_cast<ObjCImplementationDecl>(D)) + ClassDeclared = Implementation->getClassInterface(); + else if (auto *Interface = dyn_cast<ObjCInterfaceDecl>(D)) + ClassDeclared = Interface; + + assert(ClassDeclared && "cannot query interface"); } else { if (IsArrow && IDecl->FindPropertyDeclaration( @@ -1426,11 +1465,11 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (IV->getAccessControl() == ObjCIvarDecl::Private) { if (!declaresSameEntity(ClassDeclared, IDecl) || !declaresSameEntity(ClassOfMethodDecl, ClassDeclared)) - S.Diag(MemberLoc, diag::error_private_ivar_access) + S.Diag(MemberLoc, diag::err_private_ivar_access) << IV->getDeclName(); } else if (!IDecl->isSuperClassOf(ClassOfMethodDecl)) // @protected - S.Diag(MemberLoc, diag::error_protected_ivar_access) + S.Diag(MemberLoc, diag::err_protected_ivar_access) << IV->getDeclName(); } } @@ -1443,7 +1482,7 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, if (DeclRefExpr *DE = dyn_cast<DeclRefExpr>(BaseExp)) if (DE->getType().getObjCLifetime() == Qualifiers::OCL_Weak) { - S.Diag(DE->getLocation(), diag::error_arc_weak_ivar_access); + S.Diag(DE->getLocation(), diag::err_arc_weak_ivar_access); warn = false; } } @@ -1729,11 +1768,11 @@ ExprResult Sema::ActOnMemberAccessExpr(Scope *S, Expr *Base, NameInfo, TemplateArgs, S, &ExtraArgs); } -static ExprResult -BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, - SourceLocation OpLoc, const CXXScopeSpec &SS, - FieldDecl *Field, DeclAccessPair FoundDecl, - const DeclarationNameInfo &MemberNameInfo) { +ExprResult +Sema::BuildFieldReferenceExpr(Expr *BaseExpr, bool IsArrow, + SourceLocation OpLoc, const CXXScopeSpec &SS, + FieldDecl *Field, DeclAccessPair FoundDecl, + const DeclarationNameInfo &MemberNameInfo) { // x.a is an l-value if 'a' has a reference type. Otherwise: // x.a is an l-value/x-value/pr-value if the base is (and note // that *x is always an l-value), except that if the base isn't @@ -1767,36 +1806,34 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, // except that 'mutable' members don't pick up 'const'. if (Field->isMutable()) BaseQuals.removeConst(); - Qualifiers MemberQuals - = S.Context.getCanonicalType(MemberType).getQualifiers(); + Qualifiers MemberQuals = + Context.getCanonicalType(MemberType).getQualifiers(); assert(!MemberQuals.hasAddressSpace()); - Qualifiers Combined = BaseQuals + MemberQuals; if (Combined != MemberQuals) - MemberType = S.Context.getQualifiedType(MemberType, Combined); + MemberType = Context.getQualifiedType(MemberType, Combined); } - S.UnusedPrivateFields.remove(Field); + UnusedPrivateFields.remove(Field); - ExprResult Base = - S.PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), - FoundDecl, Field); + ExprResult Base = PerformObjectMemberConversion(BaseExpr, SS.getScopeRep(), + FoundDecl, Field); if (Base.isInvalid()) return ExprError(); MemberExpr *ME = - BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS, + BuildMemberExpr(*this, Context, Base.get(), IsArrow, OpLoc, SS, /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, MemberNameInfo, MemberType, VK, OK); // Build a reference to a private copy for non-static data members in // non-static member functions, privatized by OpenMP constructs. - if (S.getLangOpts().OpenMP && IsArrow && - !S.CurContext->isDependentContext() && + if (getLangOpts().OpenMP && IsArrow && + !CurContext->isDependentContext() && isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) { - if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field)) - return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); + if (auto *PrivateCopy = IsOpenMPCapturedDecl(Field)) + return getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); } return ME; } diff --git a/lib/Sema/SemaExprObjC.cpp b/lib/Sema/SemaExprObjC.cpp index 8f0d4ff695769..7dbd660f53ec6 100644 --- a/lib/Sema/SemaExprObjC.cpp +++ b/lib/Sema/SemaExprObjC.cpp @@ -1112,7 +1112,7 @@ static bool HelperToDiagnoseMismatchedMethodsInGlobalPool(Sema &S, MatchingMethodDecl, Sema::MMS_loose)) { if (!Warned) { Warned = true; - S.Diag(AtLoc, diag::warning_multiple_selectors) + S.Diag(AtLoc, diag::warn_multiple_selectors) << Method->getSelector() << FixItHint::CreateInsertion(LParenLoc, "(") << FixItHint::CreateInsertion(RParenLoc, ")"); S.Diag(Method->getLocation(), diag::note_method_declared_at) @@ -1131,7 +1131,7 @@ static void DiagnoseMismatchedSelectors(Sema &S, SourceLocation AtLoc, SourceLocation RParenLoc, bool WarnMultipleSelectors) { if (!WarnMultipleSelectors || - S.Diags.isIgnored(diag::warning_multiple_selectors, SourceLocation())) + S.Diags.isIgnored(diag::warn_multiple_selectors, SourceLocation())) return; bool Warned = false; for (Sema::GlobalMethodPool::iterator b = S.MethodPool.begin(), @@ -1534,7 +1534,7 @@ bool Sema::CheckMessageArgumentTypes(QualType ReceiverType, const ObjCMethodDecl *OMD = SelectorsForTypoCorrection(Sel, ReceiverType); if (OMD && !OMD->isInvalidDecl()) { if (getLangOpts().ObjCAutoRefCount) - DiagID = diag::error_method_not_found_with_typo; + DiagID = diag::err_method_not_found_with_typo; else DiagID = isClassMessage ? diag::warn_class_method_not_found_with_typo : diag::warn_instance_method_not_found_with_typo; @@ -1956,7 +1956,7 @@ ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, if (CurMethod->isInstanceMethod()) { if (SuperType.isNull()) { // The current class does not have a superclass. - Diag(receiverNameLoc, diag::error_root_class_cannot_use_super) + Diag(receiverNameLoc, diag::err_root_class_cannot_use_super) << CurMethod->getClassInterface()->getIdentifier(); return ExprError(); } @@ -2165,7 +2165,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, ObjCInterfaceDecl *Class = Method->getClassInterface(); if (!Class) { - Diag(SuperLoc, diag::error_no_super_class_message) + Diag(SuperLoc, diag::err_no_super_class_message) << Method->getDeclName(); return ExprError(); } @@ -2173,7 +2173,7 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, QualType SuperTy(Class->getSuperClassType(), 0); if (SuperTy.isNull()) { // The current class does not have a superclass. - Diag(SuperLoc, diag::error_root_class_cannot_use_super) + Diag(SuperLoc, diag::err_root_class_cannot_use_super) << Class->getIdentifier(); return ExprError(); } @@ -2539,6 +2539,10 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, SourceLocation RBracLoc, MultiExprArg ArgsIn, bool isImplicit) { + assert((Receiver || SuperLoc.isValid()) && "If the Receiver is null, the " + "SuperLoc must be valid so we can " + "use it instead."); + // The location of the receiver. SourceLocation Loc = SuperLoc.isValid()? SuperLoc : Receiver->getLocStart(); SourceRange RecRange = @@ -2645,7 +2649,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/, true/*CheckTheOther*/, typeBound); if (!Methods.empty()) { - // We chose the first method as the initial condidate, then try to + // We choose the first method as the initial candidate, then try to // select a better one. Method = Methods[0]; @@ -2701,7 +2705,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, false/*InstanceFirst*/, true/*CheckTheOther*/); if (!Methods.empty()) { - // We chose the first method as the initial condidate, then try + // We choose the first method as the initial candidate, then try // to select a better one. Method = Methods[0]; @@ -2789,7 +2793,7 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, true/*InstanceFirst*/, false/*CheckTheOther*/); if (!Methods.empty()) { - // We chose the first method as the initial condidate, then try + // We choose the first method as the initial candidate, then try // to select a better one. Method = Methods[0]; diff --git a/lib/Sema/SemaInit.cpp b/lib/Sema/SemaInit.cpp index 060ee3eef212f..befee05713e0c 100644 --- a/lib/Sema/SemaInit.cpp +++ b/lib/Sema/SemaInit.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Initialization.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/ExprCXX.h" @@ -19,13 +18,13 @@ #include "clang/AST/TypeLoc.h" #include "clang/Basic/TargetInfo.h" #include "clang/Sema/Designator.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/SemaInternal.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" -#include <map> using namespace clang; @@ -470,9 +469,14 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, SemaRef.Diag(Entity.getDecl()->getLocation(), diag::note_in_omitted_aggregate_initializer) << /*field*/1 << Entity.getDecl(); - else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) + else if (Entity.getKind() == InitializedEntity::EK_ArrayElement) { + bool IsTrailingArrayNewMember = + Entity.getParent() && + Entity.getParent()->isVariableLengthArrayNew(); SemaRef.Diag(Loc, diag::note_in_omitted_aggregate_initializer) - << /*array element*/0 << Entity.getElementIndex(); + << (IsTrailingArrayNewMember ? 2 : /*array element*/0) + << Entity.getElementIndex(); + } } return ExprError(); } @@ -686,8 +690,12 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, unsigned NumElements = NumInits; if (const ArrayType *AType = SemaRef.Context.getAsArrayType(ILE->getType())) { ElementType = AType->getElementType(); - if (const ConstantArrayType *CAType = dyn_cast<ConstantArrayType>(AType)) + if (const auto *CAType = dyn_cast<ConstantArrayType>(AType)) NumElements = CAType->getSize().getZExtValue(); + // For an array new with an unknown bound, ask for one additional element + // in order to populate the array filler. + if (Entity.isVariableLengthArrayNew()) + ++NumElements; ElementEntity = InitializedEntity::InitializeElement(SemaRef.Context, 0, Entity); } else if (const VectorType *VType = ILE->getType()->getAs<VectorType>()) { @@ -937,6 +945,7 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: case InitializedEntity::EK_BlockElement: + case InitializedEntity::EK_Binding: llvm_unreachable("unexpected braced scalar init"); } @@ -1229,8 +1238,9 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // subaggregate, brace elision is assumed and the initializer is // considered for the initialization of the first member of // the subaggregate. - if (!SemaRef.getLangOpts().OpenCL && - (ElemType->isAggregateType() || ElemType->isVectorType())) { + // OpenCL vector initializer is handled elsewhere. + if ((!SemaRef.getLangOpts().OpenCL && ElemType->isVectorType()) || + ElemType->isAggregateType()) { CheckImplicitInitList(Entity, IList, ElemType, Index, StructuredList, StructuredIndex); ++StructuredIndex; @@ -1685,10 +1695,13 @@ void InitListChecker::CheckArrayType(const InitializedEntity &Entity, ArrayType::Normal, 0); } if (!hadError && VerifyOnly) { - // Check if there are any members of the array that get value-initialized. - // If so, check if doing that is possible. + // If there are any members of the array that get value-initialized, check + // that is possible. That happens if we know the bound and don't have + // enough elements, or if we're performing an array new with an unknown + // bound. // FIXME: This needs to detect holes left by designated initializers too. - if (maxElementsKnown && elementIndex < maxElements) + if ((maxElementsKnown && elementIndex < maxElements) || + Entity.isVariableLengthArrayNew()) CheckEmptyInitializable(InitializedEntity::InitializeElement( SemaRef.Context, 0, Entity), IList->getLocEnd()); @@ -2896,7 +2909,8 @@ DeclarationName InitializedEntity::getName() const { case EK_Variable: case EK_Member: - return VariableOrMember->getDeclName(); + case EK_Binding: + return Variable.VariableOrMember->getDeclName(); case EK_LambdaCapture: return DeclarationName(Capture.VarID); @@ -2919,11 +2933,12 @@ DeclarationName InitializedEntity::getName() const { llvm_unreachable("Invalid EntityKind!"); } -DeclaratorDecl *InitializedEntity::getDecl() const { +ValueDecl *InitializedEntity::getDecl() const { switch (getKind()) { case EK_Variable: case EK_Member: - return VariableOrMember; + case EK_Binding: + return Variable.VariableOrMember; case EK_Parameter: case EK_Parameter_CF_Audited: @@ -2958,6 +2973,7 @@ bool InitializedEntity::allowsNRVO() const { case EK_Parameter: case EK_Parameter_CF_Audited: case EK_Member: + case EK_Binding: case EK_New: case EK_Temporary: case EK_CompoundLiteralInit: @@ -2989,6 +3005,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { case EK_Result: OS << "Result"; break; case EK_Exception: OS << "Exception"; break; case EK_Member: OS << "Member"; break; + case EK_Binding: OS << "Binding"; break; case EK_New: OS << "New"; break; case EK_Temporary: OS << "Temporary"; break; case EK_CompoundLiteralInit: OS << "CompoundLiteral";break; @@ -3005,9 +3022,9 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { break; } - if (Decl *D = getDecl()) { + if (auto *D = getDecl()) { OS << " "; - cast<NamedDecl>(D)->printQualifiedName(OS); + D->printQualifiedName(OS); } OS << " '" << getType().getAsString() << "'\n"; @@ -3031,6 +3048,7 @@ void InitializationSequence::Step::Destroy() { case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_FinalCopy: case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionRValue: @@ -3047,7 +3065,10 @@ void InitializationSequence::Step::Destroy() { case SK_CAssignment: case SK_StringInit: case SK_ObjCObjectConversion: + case SK_ArrayLoopIndex: + case SK_ArrayLoopInit: case SK_ArrayInit: + case SK_GNUArrayInit: case SK_ParenthesizedArrayInit: case SK_PassByIndirectCopyRestore: case SK_PassByIndirectRestore: @@ -3056,6 +3077,7 @@ void InitializationSequence::Step::Destroy() { case SK_StdInitializerListConstructorCall: case SK_OCLSamplerInit: case SK_OCLZeroEvent: + case SK_OCLZeroQueue: break; case SK_ConversionSequence: @@ -3065,7 +3087,14 @@ void InitializationSequence::Step::Destroy() { } bool InitializationSequence::isDirectReferenceBinding() const { - return !Steps.empty() && Steps.back().Kind == SK_BindReference; + // There can be some lvalue adjustments after the SK_BindReference step. + for (auto I = Steps.rbegin(); I != Steps.rend(); ++I) { + if (I->Kind == SK_BindReference) + return true; + if (I->Kind == SK_BindReferenceToTemporary) + return false; + } + return false; } bool InitializationSequence::isAmbiguous() const { @@ -3082,6 +3111,8 @@ bool InitializationSequence::isAmbiguous() const { case FK_IncompatWideStringIntoWideChar: case FK_AddressOfOverloadFailed: // FIXME: Could do better case FK_NonConstLValueReferenceBindingToTemporary: + case FK_NonConstLValueReferenceBindingToBitfield: + case FK_NonConstLValueReferenceBindingToVectorElement: case FK_NonConstLValueReferenceBindingToUnrelated: case FK_RValueReferenceBindingToLValue: case FK_ReferenceInitDropsQualifiers: @@ -3150,6 +3181,13 @@ void InitializationSequence::AddReferenceBindingStep(QualType T, Steps.push_back(S); } +void InitializationSequence::AddFinalCopy(QualType T) { + Step S; + S.Kind = SK_FinalCopy; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::AddExtraneousCopyToTemporary(QualType T) { Step S; S.Kind = SK_ExtraneousCopyToTemporary; @@ -3266,9 +3304,20 @@ void InitializationSequence::AddObjCObjectConversionStep(QualType T) { Steps.push_back(S); } -void InitializationSequence::AddArrayInitStep(QualType T) { +void InitializationSequence::AddArrayInitStep(QualType T, bool IsGNUExtension) { Step S; - S.Kind = SK_ArrayInit; + S.Kind = IsGNUExtension ? SK_GNUArrayInit : SK_ArrayInit; + S.Type = T; + Steps.push_back(S); +} + +void InitializationSequence::AddArrayInitLoopStep(QualType T, QualType EltT) { + Step S; + S.Kind = SK_ArrayLoopIndex; + S.Type = EltT; + Steps.insert(Steps.begin(), S); + + S.Kind = SK_ArrayLoopInit; S.Type = T; Steps.push_back(S); } @@ -3317,6 +3366,13 @@ void InitializationSequence::AddOCLZeroEventStep(QualType T) { Steps.push_back(S); } +void InitializationSequence::AddOCLZeroQueueStep(QualType T) { + Step S; + S.Kind = SK_OCLZeroQueue; + S.Type = T; + Steps.push_back(S); +} + void InitializationSequence::RewrapReferenceInitList(QualType T, InitListExpr *Syntactic) { assert(Syntactic->getNumInits() == 1 && @@ -3434,6 +3490,23 @@ static bool TryInitializerListConstruction(Sema &S, return true; } +/// Determine if the constructor has the signature of a copy or move +/// constructor for the type T of the class in which it was found. That is, +/// determine if its first parameter is of type T or reference to (possibly +/// cv-qualified) T. +static bool hasCopyOrMoveCtorParam(ASTContext &Ctx, + const ConstructorInfo &Info) { + if (Info.Constructor->getNumParams() == 0) + return false; + + QualType ParmT = + Info.Constructor->getParamDecl(0)->getType().getNonReferenceType(); + QualType ClassT = + Ctx.getRecordType(cast<CXXRecordDecl>(Info.FoundDecl->getDeclContext())); + + return Ctx.hasSameUnqualifiedType(ParmT, ClassT); +} + static OverloadingResult ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, MultiExprArg Args, @@ -3441,59 +3514,56 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, DeclContext::lookup_result Ctors, OverloadCandidateSet::iterator &Best, bool CopyInitializing, bool AllowExplicit, - bool OnlyListConstructors, bool IsListInit) { + bool OnlyListConstructors, bool IsListInit, + bool SecondStepOfCopyInit = false) { CandidateSet.clear(); for (NamedDecl *D : Ctors) { auto Info = getConstructorInfo(D); - if (!Info.Constructor) + if (!Info.Constructor || Info.Constructor->isInvalidDecl()) continue; - bool SuppressUserConversions = false; - - if (!Info.ConstructorTmpl) { - // C++11 [over.best.ics]p4: - // ... and the constructor or user-defined conversion function is a - // candidate by - // - 13.3.1.3, when the argument is the temporary in the second step - // of a class copy-initialization, or - // - 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), - // user-defined conversion sequences are not considered. - // FIXME: This breaks backward compatibility, e.g. PR12117. As a - // temporary fix, let's re-instate the third bullet above until - // there is a resolution in the standard, i.e., - // - 13.3.1.7 when the initializer list has exactly one element that is - // itself an initializer list and a conversion to some class X or - // reference to (possibly cv-qualified) X is considered for the first - // parameter of a constructor of X. - if ((CopyInitializing || - (IsListInit && Args.size() == 1 && isa<InitListExpr>(Args[0]))) && - Info.Constructor->isCopyOrMoveConstructor()) - SuppressUserConversions = true; - } - - if (!Info.Constructor->isInvalidDecl() && - (AllowExplicit || !Info.Constructor->isExplicit()) && - (!OnlyListConstructors || S.isInitListConstructor(Info.Constructor))) { - if (Info.ConstructorTmpl) - S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, - /*ExplicitArgs*/ nullptr, Args, - CandidateSet, SuppressUserConversions); - else { - // C++ [over.match.copy]p1: - // - When initializing a temporary to be bound to the first parameter - // of a constructor that takes a reference to possibly cv-qualified - // T as its first argument, called with a single argument in the - // context of direct-initialization, explicit conversion functions - // are also considered. - bool AllowExplicitConv = AllowExplicit && !CopyInitializing && - Args.size() == 1 && - Info.Constructor->isCopyOrMoveConstructor(); - S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args, - CandidateSet, SuppressUserConversions, - /*PartialOverloading=*/false, - /*AllowExplicit=*/AllowExplicitConv); - } + if (!AllowExplicit && Info.Constructor->isExplicit()) + continue; + + if (OnlyListConstructors && !S.isInitListConstructor(Info.Constructor)) + continue; + + // C++11 [over.best.ics]p4: + // ... and the constructor or user-defined conversion function is a + // candidate by + // - 13.3.1.3, when the argument is the temporary in the second step + // of a class copy-initialization, or + // - 13.3.1.4, 13.3.1.5, or 13.3.1.6 (in all cases), [not handled here] + // - the second phase of 13.3.1.7 when the initializer list has exactly + // one element that is itself an initializer list, and the target is + // the first parameter of a constructor of class X, and the conversion + // is to X or reference to (possibly cv-qualified X), + // user-defined conversion sequences are not considered. + bool SuppressUserConversions = + SecondStepOfCopyInit || + (IsListInit && Args.size() == 1 && isa<InitListExpr>(Args[0]) && + hasCopyOrMoveCtorParam(S.Context, Info)); + + if (Info.ConstructorTmpl) + S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, + /*ExplicitArgs*/ nullptr, Args, + CandidateSet, SuppressUserConversions); + else { + // C++ [over.match.copy]p1: + // - When initializing a temporary to be bound to the first parameter + // of a constructor [for type T] that takes a reference to possibly + // cv-qualified T as its first argument, called with a single + // argument in the context of direct-initialization, explicit + // conversion functions are also considered. + // FIXME: What if a constructor template instantiates to such a signature? + bool AllowExplicitConv = AllowExplicit && !CopyInitializing && + Args.size() == 1 && + hasCopyOrMoveCtorParam(S.Context, Info); + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args, + CandidateSet, SuppressUserConversions, + /*PartialOverloading=*/false, + /*AllowExplicit=*/AllowExplicitConv); } } @@ -3504,6 +3574,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, /// \brief Attempt initialization by constructor (C++ [dcl.init]), which /// enumerates the constructors of the initialized entity and performs overload /// resolution to select the best. +/// \param DestType The destination class type. +/// \param DestArrayType The destination type, which is either DestType or +/// a (possibly multidimensional) array of DestType. /// \param IsListInit Is this list-initialization? /// \param IsInitListCopy Is this non-list-initialization resulting from a /// list-initialization from {x} where x is the same @@ -3512,11 +3585,18 @@ static void TryConstructorInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, QualType DestType, + QualType DestArrayType, InitializationSequence &Sequence, bool IsListInit = false, bool IsInitListCopy = false) { - assert((!IsListInit || (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && - "IsListInit must come with a single initializer list argument."); + assert(((!IsListInit && !IsInitListCopy) || + (Args.size() == 1 && isa<InitListExpr>(Args[0]))) && + "IsListInit/IsInitListCopy must come with a single initializer list " + "argument."); + InitListExpr *ILE = + (IsListInit || IsInitListCopy) ? cast<InitListExpr>(Args[0]) : nullptr; + MultiExprArg UnwrappedArgs = + ILE ? MultiExprArg(ILE->getInits(), ILE->getNumInits()) : Args; // The type we're constructing needs to be complete. if (!S.isCompleteType(Kind.getLocation(), DestType)) { @@ -3524,6 +3604,25 @@ static void TryConstructorInitialization(Sema &S, return; } + // C++1z [dcl.init]p17: + // - If the initializer expression is a prvalue and the cv-unqualified + // version of the source type is the same class as the class of the + // destination, the initializer expression is used to initialize the + // destination object. + // Per DR (no number yet), this does not apply when initializing a base + // class or delegating to another constructor from a mem-initializer. + if (S.getLangOpts().CPlusPlus1z && + Entity.getKind() != InitializedEntity::EK_Base && + Entity.getKind() != InitializedEntity::EK_Delegating && + UnwrappedArgs.size() == 1 && UnwrappedArgs[0]->isRValue() && + S.Context.hasSameUnqualifiedType(UnwrappedArgs[0]->getType(), DestType)) { + // Convert qualifications if necessary. + Sequence.AddQualificationConversionStep(DestType, VK_RValue); + if (ILE) + Sequence.RewrapReferenceInitList(DestType, ILE); + return; + } + const RecordType *DestRecordType = DestType->getAs<RecordType>(); assert(DestRecordType && "Constructor initialization requires record type"); CXXRecordDecl *DestRecordDecl @@ -3557,20 +3656,16 @@ static void TryConstructorInitialization(Sema &S, // constructors of the class T and the argument list consists of the // initializer list as a single argument. if (IsListInit) { - InitListExpr *ILE = cast<InitListExpr>(Args[0]); AsInitializerList = true; // If the initializer list has no elements and T has a default constructor, // the first phase is omitted. - if (ILE->getNumInits() != 0 || !DestRecordDecl->hasDefaultConstructor()) + if (!(UnwrappedArgs.empty() && DestRecordDecl->hasDefaultConstructor())) Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructor=*/true, IsListInit); - - // Time to unwrap the init list. - Args = MultiExprArg(ILE->getInits(), ILE->getNumInits()); } // C++11 [over.match.list]p1: @@ -3580,7 +3675,7 @@ static void TryConstructorInitialization(Sema &S, // elements of the initializer list. if (Result == OR_No_Viable_Function) { AsInitializerList = false; - Result = ResolveConstructorOverload(S, Kind.getLocation(), Args, + Result = ResolveConstructorOverload(S, Kind.getLocation(), UnwrappedArgs, CandidateSet, Ctors, Best, CopyInitialization, AllowExplicit, /*OnlyListConstructors=*/false, @@ -3624,7 +3719,7 @@ static void TryConstructorInitialization(Sema &S, // subsumed by the initialization. bool HadMultipleCandidates = (CandidateSet.size() > 1); Sequence.AddConstructorInitializationStep( - Best->FoundDecl, CtorDecl, DestType, HadMultipleCandidates, + Best->FoundDecl, CtorDecl, DestArrayType, HadMultipleCandidates, IsListInit | IsInitListCopy, AsInitializerList); } @@ -3790,10 +3885,11 @@ static void TryListInitialization(Sema &S, QualType InitType = InitList->getInit(0)->getType(); if (S.Context.hasSameUnqualifiedType(InitType, DestType) || S.IsDerivedFrom(InitList->getLocStart(), InitType, DestType)) { - Expr *InitAsExpr = InitList->getInit(0); - TryConstructorInitialization(S, Entity, Kind, InitAsExpr, DestType, - Sequence, /*InitListSyntax*/ false, - /*IsInitListCopy*/ true); + Expr *InitListAsExpr = InitList; + TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, + DestType, Sequence, + /*InitListSyntax*/false, + /*IsInitListCopy*/true); return; } } @@ -3848,7 +3944,7 @@ static void TryListInitialization(Sema &S, // - Otherwise, if T is a class type, constructors are considered. Expr *InitListAsExpr = InitList; TryConstructorInitialization(S, Entity, Kind, InitListAsExpr, DestType, - Sequence, /*InitListSyntax*/ true); + DestType, Sequence, /*InitListSyntax*/true); } else Sequence.SetFailed(InitializationSequence::FK_InitListBadDestinationType); return; @@ -3940,12 +4036,10 @@ static void TryListInitialization(Sema &S, /// \brief Try a reference initialization that involves calling a conversion /// function. -static OverloadingResult TryRefInitWithConversionFunction(Sema &S, - const InitializedEntity &Entity, - const InitializationKind &Kind, - Expr *Initializer, - bool AllowRValues, - InitializationSequence &Sequence) { +static OverloadingResult TryRefInitWithConversionFunction( + Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, + Expr *Initializer, bool AllowRValues, bool IsLValueRef, + InitializationSequence &Sequence) { QualType DestType = Entity.getType(); QualType cv1T1 = DestType->getAs<ReferenceType>()->getPointeeType(); QualType T1 = cv1T1.getUnqualifiedType(); @@ -4061,58 +4155,68 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, // use this initialization. Mark it as referenced. Function->setReferenced(); - // Compute the returned type of the conversion. + // Compute the returned type and value kind of the conversion. + QualType cv3T3; if (isa<CXXConversionDecl>(Function)) - T2 = Function->getReturnType(); + cv3T3 = Function->getReturnType(); else - T2 = cv1T1; - - // Add the user-defined conversion step. - bool HadMultipleCandidates = (CandidateSet.size() > 1); - Sequence.AddUserConversionStep(Function, Best->FoundDecl, - T2.getNonLValueExprType(S.Context), - HadMultipleCandidates); + cv3T3 = T1; - // Determine whether we need to perform derived-to-base or - // cv-qualification adjustments. ExprValueKind VK = VK_RValue; - if (T2->isLValueReferenceType()) + if (cv3T3->isLValueReferenceType()) VK = VK_LValue; - else if (const RValueReferenceType *RRef = T2->getAs<RValueReferenceType>()) + else if (const auto *RRef = cv3T3->getAs<RValueReferenceType>()) VK = RRef->getPointeeType()->isFunctionType() ? VK_LValue : VK_XValue; + cv3T3 = cv3T3.getNonLValueExprType(S.Context); + + // Add the user-defined conversion step. + bool HadMultipleCandidates = (CandidateSet.size() > 1); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, cv3T3, + HadMultipleCandidates); + // Determine whether we'll need to perform derived-to-base adjustments or + // other conversions. bool NewDerivedToBase = false; bool NewObjCConversion = false; bool NewObjCLifetimeConversion = false; Sema::ReferenceCompareResult NewRefRelationship - = S.CompareReferenceRelationship(DeclLoc, T1, - T2.getNonLValueExprType(S.Context), + = S.CompareReferenceRelationship(DeclLoc, T1, cv3T3, NewDerivedToBase, NewObjCConversion, NewObjCLifetimeConversion); + + // Add the final conversion sequence, if necessary. if (NewRefRelationship == Sema::Ref_Incompatible) { - // If the type we've converted to is not reference-related to the - // type we're looking for, then there is another conversion step - // we need to perform to produce a temporary of the right type - // that we'll be binding to. + assert(!isa<CXXConstructorDecl>(Function) && + "should not have conversion after constructor"); + ImplicitConversionSequence ICS; ICS.setStandard(); ICS.Standard = Best->FinalConversion; - T2 = ICS.Standard.getToType(2); - Sequence.AddConversionSequenceStep(ICS, T2); - } else if (NewDerivedToBase) - Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, - T2.getNonReferenceType().getQualifiers()), - VK); - else if (NewObjCConversion) - Sequence.AddObjCObjectConversionStep( - S.Context.getQualifiedType(T1, - T2.getNonReferenceType().getQualifiers())); + Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2)); + + // Every implicit conversion results in a prvalue, except for a glvalue + // derived-to-base conversion, which we handle below. + cv3T3 = ICS.Standard.getToType(2); + VK = VK_RValue; + } - if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers()) - Sequence.AddQualificationConversionStep(cv1T1, VK); + // If the converted initializer is a prvalue, its type T4 is adjusted to + // type "cv1 T4" and the temporary materialization conversion is applied. + // + // We adjust the cv-qualifications to match the reference regardless of + // whether we have a prvalue so that the AST records the change. In this + // case, T4 is "cv3 T3". + QualType cv1T4 = S.Context.getQualifiedType(cv3T3, cv1T1.getQualifiers()); + if (cv1T4.getQualifiers() != cv3T3.getQualifiers()) + Sequence.AddQualificationConversionStep(cv1T4, VK); + Sequence.AddReferenceBindingStep(cv1T4, VK == VK_RValue); + VK = IsLValueRef ? VK_LValue : VK_XValue; + + if (NewDerivedToBase) + Sequence.AddDerivedToBaseCastStep(cv1T1, VK); + else if (NewObjCConversion) + Sequence.AddObjCObjectConversionStep(cv1T1); - Sequence.AddReferenceBindingStep(cv1T1, !T2->isReferenceType()); return OR_Success; } @@ -4146,54 +4250,11 @@ static void TryReferenceInitialization(Sema &S, T1Quals, cv2T2, T2, T2Quals, Sequence); } -/// Converts the target of reference initialization so that it has the -/// appropriate qualifiers and value kind. -/// -/// In this case, 'x' is an 'int' lvalue, but it needs to be 'const int'. -/// \code -/// int x; -/// const int &r = x; -/// \endcode -/// -/// In this case the reference is binding to a bitfield lvalue, which isn't -/// valid. Perform a load to create a lifetime-extended temporary instead. -/// \code -/// const int &r = someStruct.bitfield; -/// \endcode -static ExprValueKind -convertQualifiersAndValueKindIfNecessary(Sema &S, - InitializationSequence &Sequence, - Expr *Initializer, - QualType cv1T1, - Qualifiers T1Quals, - Qualifiers T2Quals, - bool IsLValueRef) { - bool IsNonAddressableType = Initializer->refersToBitField() || - Initializer->refersToVectorElement(); - - if (IsNonAddressableType) { - // C++11 [dcl.init.ref]p5: [...] Otherwise, the reference shall be an - // lvalue reference to a non-volatile const type, or the reference shall be - // an rvalue reference. - // - // If not, we can't make a temporary and bind to that. Give up and allow the - // error to be diagnosed later. - if (IsLValueRef && (!T1Quals.hasConst() || T1Quals.hasVolatile())) { - assert(Initializer->isGLValue()); - return Initializer->getValueKind(); - } - - // Force a load so we can materialize a temporary. - Sequence.AddLValueToRValueStep(cv1T1.getUnqualifiedType()); - return VK_RValue; - } - - if (T1Quals != T2Quals) { - Sequence.AddQualificationConversionStep(cv1T1, - Initializer->getValueKind()); - } - - return Initializer->getValueKind(); +/// Determine whether an expression is a non-referenceable glvalue (one to +/// which a reference can never bind). Attemting to bind a reference to +/// such a glvalue will always create a temporary. +static bool isNonReferenceableGLValue(Expr *E) { + return E->refersToBitField() || E->refersToVectorElement(); } /// \brief Reference initialization without resolving overloaded functions. @@ -4231,31 +4292,28 @@ static void TryReferenceInitializationCore(Sema &S, OverloadingResult ConvOvlResult = OR_Success; bool T1Function = T1->isFunctionType(); if (isLValueRef || T1Function) { - if (InitCategory.isLValue() && - (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + if (InitCategory.isLValue() && !isNonReferenceableGLValue(Initializer) && + (RefRelationship == Sema::Ref_Compatible || (Kind.isCStyleOrFunctionalCast() && RefRelationship == Sema::Ref_Related))) { // - is an lvalue (but is not a bit-field), and "cv1 T1" is // reference-compatible with "cv2 T2," or - // - // Per C++ [over.best.ics]p2, we don't diagnose whether the lvalue is a - // bit-field when we're determining whether the reference initialization - // can occur. However, we do pay attention to whether it is a bit-field - // to decide whether we're actually binding to a temporary created from - // the bit-field. + if (T1Quals != T2Quals) + // Convert to cv1 T2. This should only add qualifiers unless this is a + // c-style cast. The removal of qualifiers in that case notionally + // happens after the reference binding, but that doesn't matter. + Sequence.AddQualificationConversionStep( + S.Context.getQualifiedType(T2, T1Quals), + Initializer->getValueKind()); if (DerivedToBase) - Sequence.AddDerivedToBaseCastStep( - S.Context.getQualifiedType(T1, T2Quals), - VK_LValue); + Sequence.AddDerivedToBaseCastStep(cv1T1, VK_LValue); else if (ObjCConversion) - Sequence.AddObjCObjectConversionStep( - S.Context.getQualifiedType(T1, T2Quals)); - - ExprValueKind ValueKind = - convertQualifiersAndValueKindIfNecessary(S, Sequence, Initializer, - cv1T1, T1Quals, T2Quals, - isLValueRef); - Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); + Sequence.AddObjCObjectConversionStep(cv1T1); + + // We only create a temporary here when binding a reference to a + // bit-field or vector element. Those cases are't supposed to be + // handled by this bullet, but the outcome is the same either way. + Sequence.AddReferenceBindingStep(cv1T1, false); return; } @@ -4270,7 +4328,8 @@ static void TryReferenceInitializationCore(Sema &S, if (RefRelationship == Sema::Ref_Incompatible && T2->isRecordType() && (isLValueRef || InitCategory.isRValue())) { ConvOvlResult = TryRefInitWithConversionFunction( - S, Entity, Kind, Initializer, /*AllowRValues*/isRValueRef, Sequence); + S, Entity, Kind, Initializer, /*AllowRValues*/ isRValueRef, + /*IsLValueRef*/ isLValueRef, Sequence); if (ConvOvlResult == OR_Success) return; if (ConvOvlResult != OR_No_Viable_Function) @@ -4290,28 +4349,51 @@ static void TryReferenceInitializationCore(Sema &S, Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, ConvOvlResult); - else - Sequence.SetFailed(InitCategory.isLValue() - ? (RefRelationship == Sema::Ref_Related - ? InitializationSequence::FK_ReferenceInitDropsQualifiers - : InitializationSequence::FK_NonConstLValueReferenceBindingToUnrelated) - : InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); - + else if (!InitCategory.isLValue()) + Sequence.SetFailed( + InitializationSequence::FK_NonConstLValueReferenceBindingToTemporary); + else { + InitializationSequence::FailureKind FK; + switch (RefRelationship) { + case Sema::Ref_Compatible: + if (Initializer->refersToBitField()) + FK = InitializationSequence:: + FK_NonConstLValueReferenceBindingToBitfield; + else if (Initializer->refersToVectorElement()) + FK = InitializationSequence:: + FK_NonConstLValueReferenceBindingToVectorElement; + else + llvm_unreachable("unexpected kind of compatible initializer"); + break; + case Sema::Ref_Related: + FK = InitializationSequence::FK_ReferenceInitDropsQualifiers; + break; + case Sema::Ref_Incompatible: + FK = InitializationSequence:: + FK_NonConstLValueReferenceBindingToUnrelated; + break; + } + Sequence.SetFailed(FK); + } return; } // - If the initializer expression - // - is an xvalue, class prvalue, array prvalue, or function lvalue and - // "cv1 T1" is reference-compatible with "cv2 T2" - // Note: functions are handled below. + // - is an + // [<=14] xvalue (but not a bit-field), class prvalue, array prvalue, or + // [1z] rvalue (but not a bit-field) or + // function lvalue and "cv1 T1" is reference-compatible with "cv2 T2" + // + // Note: functions are handled above and below rather than here... if (!T1Function && - (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification || + (RefRelationship == Sema::Ref_Compatible || (Kind.isCStyleOrFunctionalCast() && RefRelationship == Sema::Ref_Related)) && - (InitCategory.isXValue() || - (InitCategory.isPRValue() && T2->isRecordType()) || - (InitCategory.isPRValue() && T2->isArrayType()))) { - ExprValueKind ValueKind = InitCategory.isXValue()? VK_XValue : VK_RValue; + ((InitCategory.isXValue() && !isNonReferenceableGLValue(Initializer)) || + (InitCategory.isPRValue() && + (S.getLangOpts().CPlusPlus1z || T2->isRecordType() || + T2->isArrayType())))) { + ExprValueKind ValueKind = InitCategory.isXValue() ? VK_XValue : VK_RValue; if (InitCategory.isPRValue() && T2->isRecordType()) { // The corresponding bullet in C++03 [dcl.init.ref]p5 gives the // compiler the freedom to perform a copy here or bind to the @@ -4328,19 +4410,22 @@ static void TryReferenceInitializationCore(Sema &S, CheckCXX98CompatAccessibleCopy(S, Entity, Initializer); } + // C++1z [dcl.init.ref]/5.2.1.2: + // If the converted initializer is a prvalue, its type T4 is adjusted + // to type "cv1 T4" and the temporary materialization conversion is + // applied. + QualType cv1T4 = S.Context.getQualifiedType(cv2T2, T1Quals); + if (T1Quals != T2Quals) + Sequence.AddQualificationConversionStep(cv1T4, ValueKind); + Sequence.AddReferenceBindingStep(cv1T4, ValueKind == VK_RValue); + ValueKind = isLValueRef ? VK_LValue : VK_XValue; + + // In any case, the reference is bound to the resulting glvalue (or to + // an appropriate base class subobject). if (DerivedToBase) - Sequence.AddDerivedToBaseCastStep(S.Context.getQualifiedType(T1, T2Quals), - ValueKind); + Sequence.AddDerivedToBaseCastStep(cv1T1, ValueKind); else if (ObjCConversion) - Sequence.AddObjCObjectConversionStep( - S.Context.getQualifiedType(T1, T2Quals)); - - ValueKind = convertQualifiersAndValueKindIfNecessary(S, Sequence, - Initializer, cv1T1, - T1Quals, T2Quals, - isLValueRef); - - Sequence.AddReferenceBindingStep(cv1T1, ValueKind == VK_RValue); + Sequence.AddObjCObjectConversionStep(cv1T1); return; } @@ -4353,7 +4438,8 @@ static void TryReferenceInitializationCore(Sema &S, if (T2->isRecordType()) { if (RefRelationship == Sema::Ref_Incompatible) { ConvOvlResult = TryRefInitWithConversionFunction( - S, Entity, Kind, Initializer, /*AllowRValues*/true, Sequence); + S, Entity, Kind, Initializer, /*AllowRValues*/ true, + /*IsLValueRef*/ isLValueRef, Sequence); if (ConvOvlResult) Sequence.SetOverloadFailure( InitializationSequence::FK_ReferenceInitOverloadFailed, @@ -4362,8 +4448,7 @@ static void TryReferenceInitializationCore(Sema &S, return; } - if ((RefRelationship == Sema::Ref_Compatible || - RefRelationship == Sema::Ref_Compatible_With_Added_Qualification) && + if (RefRelationship == Sema::Ref_Compatible && isRValueRef && InitCategory.isLValue()) { Sequence.SetFailed( InitializationSequence::FK_RValueReferenceBindingToLValue); @@ -4462,23 +4547,21 @@ static void TryValueInitialization(Sema &S, if (const RecordType *RT = T->getAs<RecordType>()) { if (CXXRecordDecl *ClassDecl = dyn_cast<CXXRecordDecl>(RT->getDecl())) { bool NeedZeroInitialization = true; - if (!S.getLangOpts().CPlusPlus11) { - // C++98: - // -- if T is a class type (clause 9) with a user-declared constructor - // (12.1), then the default constructor for T is called (and the - // initialization is ill-formed if T has no accessible default - // constructor); - if (ClassDecl->hasUserDeclaredConstructor()) - NeedZeroInitialization = false; - } else { - // C++11: - // -- if T is a class type (clause 9) with either no default constructor - // (12.1 [class.ctor]) or a default constructor that is user-provided - // or deleted, then the object is default-initialized; - CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); - if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) - NeedZeroInitialization = false; - } + // C++98: + // -- if T is a class type (clause 9) with a user-declared constructor + // (12.1), then the default constructor for T is called (and the + // initialization is ill-formed if T has no accessible default + // constructor); + // C++11: + // -- if T is a class type (clause 9) with either no default constructor + // (12.1 [class.ctor]) or a default constructor that is user-provided + // or deleted, then the object is default-initialized; + // + // Note that the C++11 rule is the same as the C++98 rule if there are no + // defaulted or deleted constructors, so we just use it unconditionally. + CXXConstructorDecl *CD = S.LookupDefaultConstructor(ClassDecl); + if (!CD || !CD->getCanonicalDecl()->isDefaulted() || CD->isDeleted()) + NeedZeroInitialization = false; // -- if T is a (possibly cv-qualified) non-union class type without a // user-provided or deleted default constructor, then the object is @@ -4512,8 +4595,10 @@ static void TryValueInitialization(Sema &S, MultiExprArg Args(&InitListAsExpr, InitList ? 1 : 0); bool InitListSyntax = InitList; - return TryConstructorInitialization(S, Entity, Kind, Args, T, Sequence, - InitListSyntax); + // FIXME: Instead of creating a CXXConstructExpr of array type here, + // wrap a class-typed CXXConstructExpr in an ArrayInitLoopExpr. + return TryConstructorInitialization( + S, Entity, Kind, Args, T, Entity.getType(), Sequence, InitListSyntax); } } @@ -4536,7 +4621,8 @@ static void TryDefaultInitialization(Sema &S, // constructor for T is called (and the initialization is ill-formed if // T has no accessible default constructor); if (DestType->isRecordType() && S.getLangOpts().CPlusPlus) { - TryConstructorInitialization(S, Entity, Kind, None, DestType, Sequence); + TryConstructorInitialization(S, Entity, Kind, None, DestType, + Entity.getType(), Sequence); return; } @@ -4680,26 +4766,55 @@ static void TryUserDefinedConversion(Sema &S, Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType.getUnqualifiedType(), HadMultipleCandidates); + + // C++14 and before: + // - if the function is a constructor, the call initializes a temporary + // of the cv-unqualified version of the destination type. The [...] + // temporary [...] is then used to direct-initialize, according to the + // rules above, the object that is the destination of the + // copy-initialization. + // Note that this just performs a simple object copy from the temporary. + // + // C++1z: + // - if the function is a constructor, the call is a prvalue of the + // cv-unqualified version of the destination type whose return object + // is initialized by the constructor. The call is used to + // direct-initialize, according to the rules above, the object that + // is the destination of the copy-initialization. + // Therefore we need to do nothing further. + // + // FIXME: Mark this copy as extraneous. + if (!S.getLangOpts().CPlusPlus1z) + Sequence.AddFinalCopy(DestType); + else if (DestType.hasQualifiers()) + Sequence.AddQualificationConversionStep(DestType, VK_RValue); return; } // Add the user-defined conversion step that calls the conversion function. QualType ConvType = Function->getCallResultType(); + Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType, + HadMultipleCandidates); + if (ConvType->getAs<RecordType>()) { - // If we're converting to a class type, there may be an copy of - // the resulting temporary object (possible to create an object of - // a base class type). That copy is not a separate conversion, so - // we just make a note of the actual destination type (possibly a - // base class of the type returned by the conversion function) and - // let the user-defined conversion step handle the conversion. - Sequence.AddUserConversionStep(Function, Best->FoundDecl, DestType, - HadMultipleCandidates); + // The call is used to direct-initialize [...] the object that is the + // destination of the copy-initialization. + // + // In C++1z, this does not call a constructor if we enter /17.6.1: + // - If the initializer expression is a prvalue and the cv-unqualified + // version of the source type is the same as the class of the + // destination [... do not make an extra copy] + // + // FIXME: Mark this copy as extraneous. + if (!S.getLangOpts().CPlusPlus1z || + Function->getReturnType()->isReferenceType() || + !S.Context.hasSameUnqualifiedType(ConvType, DestType)) + Sequence.AddFinalCopy(DestType); + else if (!S.Context.hasSameType(ConvType, DestType)) + Sequence.AddQualificationConversionStep(DestType, VK_RValue); return; } - Sequence.AddUserConversionStep(Function, Best->FoundDecl, ConvType, - HadMultipleCandidates); - // If the conversion following the call to the conversion function // is interesting, add it as a separate step. if (Best->FinalConversion.First || Best->FinalConversion.Second || @@ -4886,7 +5001,8 @@ static bool TryOCLSamplerInitialization(Sema &S, QualType DestType, Expr *Initializer) { if (!S.getLangOpts().OpenCL || !DestType->isSamplerT() || - !Initializer->isIntegerConstantExpr(S.getASTContext())) + (!Initializer->isIntegerConstantExpr(S.Context) && + !Initializer->getType()->isSamplerT())) return false; Sequence.AddOCLSamplerInitStep(DestType); @@ -4914,6 +5030,20 @@ static bool TryOCLZeroEventInitialization(Sema &S, return true; } +static bool TryOCLZeroQueueInitialization(Sema &S, + InitializationSequence &Sequence, + QualType DestType, + Expr *Initializer) { + if (!S.getLangOpts().OpenCL || S.getLangOpts().OpenCLVersion < 200 || + !DestType->isQueueT() || + !Initializer->isIntegerConstantExpr(S.getASTContext()) || + (Initializer->EvaluateKnownConstInt(S.getASTContext()) != 0)) + return false; + + Sequence.AddOCLZeroQueueStep(DestType); + return true; +} + InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -4936,6 +5066,42 @@ static bool isExprAnUnaddressableFunction(Sema &S, const Expr *E) { cast<FunctionDecl>(DRE->getDecl())); } +/// Determine whether we can perform an elementwise array copy for this kind +/// of entity. +static bool canPerformArrayCopy(const InitializedEntity &Entity) { + switch (Entity.getKind()) { + case InitializedEntity::EK_LambdaCapture: + // C++ [expr.prim.lambda]p24: + // For array members, the array elements are direct-initialized in + // increasing subscript order. + return true; + + case InitializedEntity::EK_Variable: + // C++ [dcl.decomp]p1: + // [...] each element is copy-initialized or direct-initialized from the + // corresponding element of the assignment-expression [...] + return isa<DecompositionDecl>(Entity.getDecl()); + + case InitializedEntity::EK_Member: + // C++ [class.copy.ctor]p14: + // - if the member is an array, each element is direct-initialized with + // the corresponding subobject of x + return Entity.isImplicitMemberInitializer(); + + case InitializedEntity::EK_ArrayElement: + // All the above cases are intended to apply recursively, even though none + // of them actually say that. + if (auto *E = Entity.getParent()) + return canPerformArrayCopy(*E); + break; + + default: + break; + } + + return false; +} + void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, @@ -5058,6 +5224,34 @@ void InitializationSequence::InitializeFrom(Sema &S, } } + // Some kinds of initialization permit an array to be initialized from + // another array of the same type, and perform elementwise initialization. + if (Initializer && isa<ConstantArrayType>(DestAT) && + S.Context.hasSameUnqualifiedType(Initializer->getType(), + Entity.getType()) && + canPerformArrayCopy(Entity)) { + // If source is a prvalue, use it directly. + if (Initializer->getValueKind() == VK_RValue) { + AddArrayInitStep(DestType, /*IsGNUExtension*/false); + return; + } + + // Emit element-at-a-time copy loop. + InitializedEntity Element = + InitializedEntity::InitializeElement(S.Context, 0, Entity); + QualType InitEltT = + Context.getAsArrayType(Initializer->getType())->getElementType(); + OpaqueValueExpr OVE(Initializer->getExprLoc(), InitEltT, + Initializer->getValueKind(), + Initializer->getObjectKind()); + Expr *OVEAsExpr = &OVE; + InitializeFrom(S, Element, Kind, OVEAsExpr, TopLevelOfInitList, + TreatUnavailableAsInvalid); + if (!Failed()) + AddArrayInitLoopStep(Entity.getType(), InitEltT); + return; + } + // Note: as an GNU C extension, we allow initialization of an // array from a compound literal that creates an array of the same // type, so long as the initializer has no side effects. @@ -5071,7 +5265,7 @@ void InitializationSequence::InitializeFrom(Sema &S, else if (Initializer->HasSideEffects(S.Context)) SetFailed(FK_NonConstantArrayInit); else { - AddArrayInitStep(DestType); + AddArrayInitStep(DestType, /*IsGNUExtension*/true); } } // Note: as a GNU C++ extension, we allow list-initialization of a @@ -5112,6 +5306,9 @@ void InitializationSequence::InitializeFrom(Sema &S, if (TryOCLZeroEventInitialization(S, *this, DestType, Initializer)) return; + if (TryOCLZeroQueueInitialization(S, *this, DestType, Initializer)) + return; + // Handle initialization in C AddCAssignmentStep(DestType); MaybeProduceObjCObject(S, *this, Entity); @@ -5131,7 +5328,7 @@ void InitializationSequence::InitializeFrom(Sema &S, (Context.hasSameUnqualifiedType(SourceType, DestType) || S.IsDerivedFrom(Initializer->getLocStart(), SourceType, DestType)))) TryConstructorInitialization(S, Entity, Kind, Args, - DestType, *this); + DestType, DestType, *this); // - Otherwise (i.e., for the remaining copy-initialization cases), // user-defined conversion sequences that can convert from the source // type to the destination type or (when a conversion function is @@ -5270,6 +5467,7 @@ getAssignmentAction(const InitializedEntity &Entity, bool Diagnose = false) { return Sema::AA_Casting; case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_ArrayElement: case InitializedEntity::EK_VectorElement: case InitializedEntity::EK_ComplexElement: @@ -5305,6 +5503,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { case InitializedEntity::EK_Parameter_CF_Audited: case InitializedEntity::EK_Temporary: case InitializedEntity::EK_RelatedResult: + case InitializedEntity::EK_Binding: return true; } @@ -5313,7 +5512,7 @@ static bool shouldBindAsTemporary(const InitializedEntity &Entity) { /// \brief Whether the given entity, when initialized with an object /// created for that initialization, requires destruction. -static bool shouldDestroyTemporary(const InitializedEntity &Entity) { +static bool shouldDestroyEntity(const InitializedEntity &Entity) { switch (Entity.getKind()) { case InitializedEntity::EK_Result: case InitializedEntity::EK_New: @@ -5326,6 +5525,7 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { return false; case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_Variable: case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: @@ -5340,50 +5540,6 @@ static bool shouldDestroyTemporary(const InitializedEntity &Entity) { llvm_unreachable("missed an InitializedEntity kind?"); } -/// \brief Look for copy and move constructors and constructor templates, for -/// copying an object via direct-initialization (per C++11 [dcl.init]p16). -static void LookupCopyAndMoveConstructors(Sema &S, - OverloadCandidateSet &CandidateSet, - CXXRecordDecl *Class, - Expr *CurInitExpr) { - DeclContext::lookup_result R = S.LookupConstructors(Class); - // The container holding the constructors can under certain conditions - // be changed while iterating (e.g. because of deserialization). - // To be safe we copy the lookup results to a new container. - SmallVector<NamedDecl*, 16> Ctors(R.begin(), R.end()); - for (SmallVectorImpl<NamedDecl *>::iterator - CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) { - NamedDecl *D = *CI; - auto Info = getConstructorInfo(D); - if (!Info.Constructor) - continue; - - if (!Info.ConstructorTmpl) { - // Handle copy/move constructors, only. - if (Info.Constructor->isInvalidDecl() || - !Info.Constructor->isCopyOrMoveConstructor() || - !Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) - continue; - - S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, - CurInitExpr, CandidateSet); - continue; - } - - // Handle constructor templates. - if (Info.ConstructorTmpl->isInvalidDecl()) - continue; - - if (!Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) - continue; - - // FIXME: Do we need to limit this to copy-constructor-like - // candidates? - S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, - nullptr, CurInitExpr, CandidateSet, true); - } -} - /// \brief Get the location at which initialization diagnostics should appear. static SourceLocation getInitializationLoc(const InitializedEntity &Entity, Expr *Initializer) { @@ -5395,6 +5551,7 @@ static SourceLocation getInitializationLoc(const InitializedEntity &Entity, return Entity.getThrowLoc(); case InitializedEntity::EK_Variable: + case InitializedEntity::EK_Binding: return Entity.getDecl()->getLocation(); case InitializedEntity::EK_LambdaCapture: @@ -5453,39 +5610,24 @@ static ExprResult CopyObject(Sema &S, if (!Class) return CurInit; - // C++0x [class.copy]p32: - // When certain criteria are met, an implementation is allowed to - // omit the copy/move construction of a class object, even if the - // copy/move constructor and/or destructor for the object have - // side effects. [...] - // - when a temporary class object that has not been bound to a - // reference (12.2) would be copied/moved to a class object - // with the same cv-unqualified type, the copy/move operation - // can be omitted by constructing the temporary object - // directly into the target of the omitted copy/move - // - // Note that the other three bullets are handled elsewhere. Copy - // elision for return statements and throw expressions are handled as part - // of constructor initialization, while copy elision for exception handlers - // is handled by the run-time. - bool Elidable = CurInitExpr->isTemporaryObject(S.Context, Class); SourceLocation Loc = getInitializationLoc(Entity, CurInit.get()); // Make sure that the type we are copying is complete. if (S.RequireCompleteType(Loc, T, diag::err_temp_copy_incomplete)) return CurInit; - // Perform overload resolution using the class's copy/move constructors. - // Only consider constructors and constructor templates. Per - // C++0x [dcl.init]p16, second bullet to class types, this initialization + // Perform overload resolution using the class's constructors. Per + // C++11 [dcl.init]p16, second bullet for class types, this initialization // is direct-initialization. OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); - LookupCopyAndMoveConstructors(S, CandidateSet, Class, CurInitExpr); - - bool HadMultipleCandidates = (CandidateSet.size() > 1); + DeclContext::lookup_result Ctors = S.LookupConstructors(Class); OverloadCandidateSet::iterator Best; - switch (CandidateSet.BestViableFunction(S, Loc, Best)) { + switch (ResolveConstructorOverload( + S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + /*CopyInitializing=*/false, /*AllowExplicit=*/true, + /*OnlyListConstructors=*/false, /*IsListInit=*/false, + /*SecondStepOfCopyInit=*/true)) { case OR_Success: break; @@ -5515,6 +5657,8 @@ static ExprResult CopyObject(Sema &S, return ExprError(); } + bool HadMultipleCandidates = CandidateSet.size() > 1; + CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(Best->Function); SmallVector<Expr*, 8> ConstructorArgs; CurInit.get(); // Ownership transferred into MultiExprArg, below. @@ -5554,6 +5698,31 @@ static ExprResult CopyObject(Sema &S, if (S.CompleteConstructorCall(Constructor, CurInitExpr, Loc, ConstructorArgs)) return ExprError(); + // C++0x [class.copy]p32: + // When certain criteria are met, an implementation is allowed to + // omit the copy/move construction of a class object, even if the + // copy/move constructor and/or destructor for the object have + // side effects. [...] + // - when a temporary class object that has not been bound to a + // reference (12.2) would be copied/moved to a class object + // with the same cv-unqualified type, the copy/move operation + // can be omitted by constructing the temporary object + // directly into the target of the omitted copy/move + // + // Note that the other three bullets are handled elsewhere. Copy + // elision for return statements and throw expressions are handled as part + // of constructor initialization, while copy elision for exception handlers + // is handled by the run-time. + // + // FIXME: If the function parameter is not the same type as the temporary, we + // should still be able to elide the copy, but we don't have a way to + // represent in the AST how much should be elided in this case. + bool Elidable = + CurInitExpr->isTemporaryObject(S.Context, Class) && + S.Context.hasSameUnqualifiedType( + Best->Function->getParamDecl(0)->getType().getNonReferenceType(), + CurInitExpr->getType()); + // Actually perform the constructor call. CurInit = S.BuildCXXConstructExpr(Loc, T, Best->FoundDecl, Constructor, Elidable, @@ -5589,12 +5758,16 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, // Find constructors which would have been considered. OverloadCandidateSet CandidateSet(Loc, OverloadCandidateSet::CSK_Normal); - LookupCopyAndMoveConstructors( - S, CandidateSet, cast<CXXRecordDecl>(Record->getDecl()), CurInitExpr); + DeclContext::lookup_result Ctors = + S.LookupConstructors(cast<CXXRecordDecl>(Record->getDecl())); // Perform overload resolution. OverloadCandidateSet::iterator Best; - OverloadingResult OR = CandidateSet.BestViableFunction(S, Loc, Best); + OverloadingResult OR = ResolveConstructorOverload( + S, Loc, CurInitExpr, CandidateSet, Ctors, Best, + /*CopyInitializing=*/false, /*AllowExplicit=*/true, + /*OnlyListConstructors=*/false, /*IsListInit=*/false, + /*SecondStepOfCopyInit=*/true); PartialDiagnostic Diag = S.PDiag(diag::warn_cxx98_compat_temp_copy) << OR << (int)Entity.getKind() << CurInitExpr->getType() @@ -5643,11 +5816,6 @@ void InitializationSequence::PrintInitLocationNote(Sema &S, << Entity.getMethodDecl()->getDeclName(); } -static bool isReferenceBinding(const InitializationSequence::Step &s) { - return s.Kind == InitializationSequence::SK_BindReference || - s.Kind == InitializationSequence::SK_BindReferenceToTemporary; -} - /// Returns true if the parameters describe a constructor initialization of /// an explicit temporary object, e.g. "Point(x, y)". static bool isExplicitTemporary(const InitializedEntity &Entity, @@ -5714,9 +5882,10 @@ PerformConstructorInitialization(Sema &S, // T as its first argument, called with a single argument in the // context of direct-initialization, explicit conversion functions // are also considered. - bool AllowExplicitConv = Kind.AllowExplicit() && !Kind.isCopyInit() && - Args.size() == 1 && - Constructor->isCopyOrMoveConstructor(); + bool AllowExplicitConv = + Kind.AllowExplicit() && !Kind.isCopyInit() && Args.size() == 1 && + hasCopyOrMoveCtorParam(S.Context, + getConstructorInfo(Step.Function.FoundDecl)); // Determine the arguments required to actually perform the constructor // call. @@ -5776,7 +5945,7 @@ PerformConstructorInitialization(Sema &S, // If the entity allows NRVO, mark the construction as elidable // unconditionally. if (Entity.allowsNRVO()) - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + CurInit = S.BuildCXXConstructExpr(Loc, Step.Type, Step.Function.FoundDecl, Constructor, /*Elidable=*/true, ConstructorArgs, @@ -5787,7 +5956,7 @@ PerformConstructorInitialization(Sema &S, ConstructKind, ParenOrBraceRange); else - CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + CurInit = S.BuildCXXConstructExpr(Loc, Step.Type, Step.Function.FoundDecl, Constructor, ConstructorArgs, @@ -5826,6 +5995,7 @@ InitializedEntityOutlivesFullExpression(const InitializedEntity &Entity) { case InitializedEntity::EK_Result: case InitializedEntity::EK_Exception: case InitializedEntity::EK_Member: + case InitializedEntity::EK_Binding: case InitializedEntity::EK_New: case InitializedEntity::EK_Base: case InitializedEntity::EK_Delegating: @@ -5875,6 +6045,11 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension( // ctor-initializer persists until the constructor exits. return Entity; + case InitializedEntity::EK_Binding: + // Per [dcl.decomp]p3, the binding is treated as a variable of reference + // type. + return Entity; + case InitializedEntity::EK_Parameter: case InitializedEntity::EK_Parameter_CF_Audited: // -- A temporary bound to a reference parameter in a function call @@ -5949,10 +6124,7 @@ performReferenceExtension(Expr *Init, // Step over any subobject adjustments; we may have a materialized // temporary inside them. - SmallVector<const Expr *, 2> CommaLHSs; - SmallVector<SubobjectAdjustment, 2> Adjustments; - Init = const_cast<Expr *>( - Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); + Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments()); // Per current approach for DR1376, look through casts to reference type // when performing lifetime extension. @@ -5960,9 +6132,10 @@ performReferenceExtension(Expr *Init, if (CE->getSubExpr()->isGLValue()) Init = CE->getSubExpr(); - // FIXME: Per DR1213, subscripting on an array temporary produces an xvalue. - // It's unclear if binding a reference to that xvalue extends the array - // temporary. + // Per the current approach for DR1299, look through array element access + // when performing lifetime extension. + if (auto *ASE = dyn_cast<ArraySubscriptExpr>(Init)) + Init = ASE->getBase(); } while (Init != Old); if (MaterializeTemporaryExpr *ME = dyn_cast<MaterializeTemporaryExpr>(Init)) { @@ -5982,10 +6155,7 @@ performReferenceExtension(Expr *Init, static void performLifetimeExtension(Expr *Init, const InitializedEntity *ExtendingEntity) { // Dig out the expression which constructs the extended temporary. - SmallVector<const Expr *, 2> CommaLHSs; - SmallVector<SubobjectAdjustment, 2> Adjustments; - Init = const_cast<Expr *>( - Init->skipRValueSubobjectAdjustments(CommaLHSs, Adjustments)); + Init = const_cast<Expr *>(Init->skipRValueSubobjectAdjustments()); if (CXXBindTemporaryExpr *BTE = dyn_cast<CXXBindTemporaryExpr>(Init)) Init = BTE->getSubExpr(); @@ -6204,6 +6374,24 @@ Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, return MTE; } +ExprResult Sema::TemporaryMaterializationConversion(Expr *E) { + // In C++98, we don't want to implicitly create an xvalue. + // FIXME: This means that AST consumers need to deal with "prvalues" that + // denote materialized temporaries. Maybe we should add another ValueKind + // for "xvalue pretending to be a prvalue" for C++98 support. + if (!E->isRValue() || !getLangOpts().CPlusPlus11) + return E; + + // C++1z [conv.rval]/1: T shall be a complete type. + // FIXME: Does this ever matter (can we form a prvalue of incomplete type)? + // If so, we should check for a non-abstract class type here too. + QualType T = E->getType(); + if (RequireCompleteType(E->getExprLoc(), T, diag::err_incomplete_type)) + return ExprError(); + + return CreateMaterializeTemporaryExpr(E->getType(), E, false); +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -6250,7 +6438,7 @@ InitializationSequence::Perform(Sema &S, SourceRange Brackets; // Scavange the location of the brackets from the entity, if we can. - if (DeclaratorDecl *DD = Entity.getDecl()) { + if (auto *DD = dyn_cast_or_null<DeclaratorDecl>(Entity.getDecl())) { if (TypeSourceInfo *TInfo = DD->getTypeSourceInfo()) { TypeLoc TL = TInfo->getTypeLoc(); if (IncompleteArrayTypeLoc ArrayLoc = @@ -6302,7 +6490,9 @@ InitializationSequence::Perform(Sema &S, if (Args.size() == 1 && Args[0]->getType()->isArrayType() && Entity.getType()->isPointerType() && InitializedEntityOutlivesFullExpression(Entity)) { - Expr *Init = Args[0]; + const Expr *Init = Args[0]->skipRValueSubobjectAdjustments(); + if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) + Init = MTE->GetTemporaryExpr(); Expr::LValueClassification Kind = Init->ClassifyLValue(S.Context); if (Kind == Expr::LV_ClassTemporary || Kind == Expr::LV_ArrayTemporary) S.Diag(Init->getLocStart(), diag::warn_temporary_array_to_pointer_decay) @@ -6318,6 +6508,7 @@ InitializationSequence::Perform(Sema &S, Entity.getType(); ExprResult CurInit((Expr *)nullptr); + SmallVector<Expr*, 4> ArrayLoopCommonExprs; // For initialization steps that start with a single initializer, // grab the only argument out the Args and place it into the "current" @@ -6329,6 +6520,7 @@ InitializationSequence::Perform(Sema &S, case SK_CastDerivedToBaseLValue: case SK_BindReference: case SK_BindReferenceToTemporary: + case SK_FinalCopy: case SK_ExtraneousCopyToTemporary: case SK_UserConversion: case SK_QualificationConversionLValue: @@ -6344,14 +6536,18 @@ InitializationSequence::Perform(Sema &S, case SK_CAssignment: case SK_StringInit: case SK_ObjCObjectConversion: + case SK_ArrayLoopIndex: + case SK_ArrayLoopInit: case SK_ArrayInit: + case SK_GNUArrayInit: case SK_ParenthesizedArrayInit: case SK_PassByIndirectCopyRestore: case SK_PassByIndirectRestore: case SK_ProduceObjCObject: case SK_StdInitializerList: case SK_OCLSamplerInit: - case SK_OCLZeroEvent: { + case SK_OCLZeroEvent: + case SK_OCLZeroQueue: { assert(Args.size() == 1); CurInit = Args[0]; if (!CurInit.get()) return ExprError(); @@ -6365,6 +6561,17 @@ InitializationSequence::Perform(Sema &S, break; } + // C++ [class.abstract]p2: + // no objects of an abstract class can be created except as subobjects + // of a class derived from it + auto checkAbstractType = [&](QualType T) -> bool { + if (Entity.getKind() == InitializedEntity::EK_Base || + Entity.getKind() == InitializedEntity::EK_Delegating) + return false; + return S.RequireNonAbstractType(Kind.getLocation(), T, + diag::err_allocation_of_abstract_type); + }; + // Walk through the computed steps for the initialization sequence, // performing the specified conversions along the way. bool ConstructorInitRequiresZeroInit = false; @@ -6416,30 +6623,6 @@ InitializationSequence::Perform(Sema &S, } case SK_BindReference: - // References cannot bind to bit-fields (C++ [dcl.init.ref]p5). - if (CurInit.get()->refersToBitField()) { - // We don't necessarily have an unambiguous source bit-field. - FieldDecl *BitField = CurInit.get()->getSourceBitField(); - S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) - << Entity.getType().isVolatileQualified() - << (BitField ? BitField->getDeclName() : DeclarationName()) - << (BitField != nullptr) - << CurInit.get()->getSourceRange(); - if (BitField) - S.Diag(BitField->getLocation(), diag::note_bitfield_decl); - - return ExprError(); - } - - if (CurInit.get()->refersToVectorElement()) { - // References cannot bind to vector elements. - S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) - << Entity.getType().isVolatileQualified() - << CurInit.get()->getSourceRange(); - PrintInitLocationNote(S, Entity); - return ExprError(); - } - // Reference binding does not have any corresponding ASTs. // Check exception specifications @@ -6469,15 +6652,15 @@ InitializationSequence::Perform(Sema &S, // Materialize the temporary into memory. MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr( - Entity.getType().getNonReferenceType(), CurInit.get(), - Entity.getType()->isLValueReferenceType()); + Step->Type, CurInit.get(), Entity.getType()->isLValueReferenceType()); // Maybe lifetime-extend the temporary's subobjects to match the // entity's lifetime. if (const InitializedEntity *ExtendingEntity = getEntityForTemporaryLifetimeExtension(&Entity)) if (performReferenceExtension(MTE, ExtendingEntity)) - warnOnLifetimeExtension(S, Entity, CurInit.get(), /*IsInitializerList=*/false, + warnOnLifetimeExtension(S, Entity, CurInit.get(), + /*IsInitializerList=*/false, ExtendingEntity->getDecl()); // If we're binding to an Objective-C object that has lifetime, we @@ -6494,6 +6677,21 @@ InitializationSequence::Perform(Sema &S, break; } + case SK_FinalCopy: + if (checkAbstractType(Step->Type)) + return ExprError(); + + // If the overall initialization is initializing a temporary, we already + // bound our argument if it was necessary to do so. If not (if we're + // ultimately initializing a non-temporary), our argument needs to be + // bound since it's initializing a function parameter. + // FIXME: This is a mess. Rationalize temporary destruction. + if (!shouldBindAsTemporary(Entity)) + CurInit = S.MaybeBindToTemporary(CurInit.get()); + CurInit = CopyObject(S, Step->Type, Entity, CurInit, + /*IsExtraneousCopy=*/false); + break; + case SK_ExtraneousCopyToTemporary: CurInit = CopyObject(S, Step->Type, Entity, CurInit, /*IsExtraneousCopy=*/true); @@ -6503,7 +6701,6 @@ InitializationSequence::Perform(Sema &S, // We have a user-defined conversion that invokes either a constructor // or a conversion function. CastKind CastKind; - bool IsCopy = false; FunctionDecl *Fn = Step->Function.Function; DeclAccessPair FoundFn = Step->Function.FoundDecl; bool HadMultipleCandidates = Step->Function.HadMultipleCandidates; @@ -6512,7 +6709,6 @@ InitializationSequence::Perform(Sema &S, // Build a call to the selected constructor. SmallVector<Expr*, 8> ConstructorArgs; SourceLocation Loc = CurInit.get()->getLocStart(); - CurInit.get(); // Ownership transferred into MultiExprArg, below. // Determine the arguments required to actually perform the constructor // call. @@ -6541,11 +6737,6 @@ InitializationSequence::Perform(Sema &S, return ExprError(); CastKind = CK_ConstructorConversion; - QualType Class = S.Context.getTypeDeclType(Constructor->getParent()); - if (S.Context.hasSameUnqualifiedType(SourceType, Class) || - S.IsDerivedFrom(Loc, SourceType, Class)) - IsCopy = true; - CreatedObject = true; } else { // Build a call to the conversion function. @@ -6558,29 +6749,38 @@ InitializationSequence::Perform(Sema &S, // FIXME: Should we move this initialization into a separate // derived-to-base conversion? I believe the answer is "no", because // we don't want to turn off access control here for c-style casts. - ExprResult CurInitExprRes = - S.PerformObjectArgumentInitialization(CurInit.get(), - /*Qualifier=*/nullptr, - FoundFn, Conversion); - if(CurInitExprRes.isInvalid()) + CurInit = S.PerformObjectArgumentInitialization(CurInit.get(), + /*Qualifier=*/nullptr, + FoundFn, Conversion); + if (CurInit.isInvalid()) return ExprError(); - CurInit = CurInitExprRes; // Build the actual call to the conversion function. CurInit = S.BuildCXXMemberCallExpr(CurInit.get(), FoundFn, Conversion, HadMultipleCandidates); - if (CurInit.isInvalid() || !CurInit.get()) + if (CurInit.isInvalid()) return ExprError(); CastKind = CK_UserDefinedConversion; - CreatedObject = Conversion->getReturnType()->isRecordType(); } - bool RequiresCopy = !IsCopy && !isReferenceBinding(Steps.back()); - bool MaybeBindToTemp = RequiresCopy || shouldBindAsTemporary(Entity); + if (CreatedObject && checkAbstractType(CurInit.get()->getType())) + return ExprError(); + + CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), + CastKind, CurInit.get(), nullptr, + CurInit.get()->getValueKind()); - if (!MaybeBindToTemp && CreatedObject && shouldDestroyTemporary(Entity)) { + if (shouldBindAsTemporary(Entity)) + // The overall entity is temporary, so this expression should be + // destroyed at the end of its full-expression. + CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>()); + else if (CreatedObject && shouldDestroyEntity(Entity)) { + // The object outlasts the full-expression, but we need to prepare for + // a destructor being run on it. + // FIXME: It makes no sense to do this here. This should happen + // regardless of how we initialized the entity. QualType T = CurInit.get()->getType(); if (const RecordType *Record = T->getAs<RecordType>()) { CXXDestructorDecl *Destructor @@ -6592,15 +6792,6 @@ InitializationSequence::Perform(Sema &S, return ExprError(); } } - - CurInit = ImplicitCastExpr::Create(S.Context, CurInit.get()->getType(), - CastKind, CurInit.get(), nullptr, - CurInit.get()->getValueKind()); - if (MaybeBindToTemp) - CurInit = S.MaybeBindToTemporary(CurInit.getAs<Expr>()); - if (RequiresCopy) - CurInit = CopyObject(S, Entity.getType().getNonReferenceType(), Entity, - CurInit, /*IsExtraneousCopy=*/false); break; } @@ -6645,16 +6836,23 @@ InitializationSequence::Perform(Sema &S, getAssignmentAction(Entity), CCK); if (CurInitExprRes.isInvalid()) return ExprError(); + + S.DiscardMisalignedMemberAddress(Step->Type.getTypePtr(), CurInit.get()); + CurInit = CurInitExprRes; if (Step->Kind == SK_ConversionSequenceNoNarrowing && - S.getLangOpts().CPlusPlus && !CurInit.get()->isValueDependent()) + S.getLangOpts().CPlusPlus) DiagnoseNarrowingInInitList(S, *Step->ICS, SourceType, Entity.getType(), CurInit.get()); + break; } case SK_ListInitialization: { + if (checkAbstractType(Step->Type)) + return ExprError(); + InitListExpr *InitList = cast<InitListExpr>(CurInit.get()); // If we're not initializing the top-level entity, we need to create an // InitializeTemporary entity for our target type. @@ -6691,6 +6889,9 @@ InitializationSequence::Perform(Sema &S, } case SK_ConstructorInitializationFromList: { + if (checkAbstractType(Step->Type)) + return ExprError(); + // When an initializer list is passed for a parameter of type "reference // to object", we don't get an EK_Temporary entity, but instead an // EK_Parameter entity with reference type. @@ -6734,6 +6935,9 @@ InitializationSequence::Perform(Sema &S, case SK_ConstructorInitialization: case SK_StdInitializerListConstructorCall: { + if (checkAbstractType(Step->Type)) + return ExprError(); + // When an initializer list is passed for a parameter of type "reference // to object", we don't get an EK_Temporary entity, but instead an // EK_Parameter entity with reference type. @@ -6745,13 +6949,15 @@ InitializationSequence::Perform(Sema &S, bool UseTemporary = Entity.getType()->isReferenceType(); bool IsStdInitListInit = Step->Kind == SK_StdInitializerListConstructorCall; + Expr *Source = CurInit.get(); CurInit = PerformConstructorInitialization( - S, UseTemporary ? TempEntity : Entity, Kind, Args, *Step, + S, UseTemporary ? TempEntity : Entity, Kind, + Source ? MultiExprArg(Source) : Args, *Step, ConstructorInitRequiresZeroInit, - /*IsListInitialization*/IsStdInitListInit, - /*IsStdInitListInitialization*/IsStdInitListInit, - /*LBraceLoc*/SourceLocation(), - /*RBraceLoc*/SourceLocation()); + /*IsListInitialization*/ IsStdInitListInit, + /*IsStdInitListInitialization*/ IsStdInitListInit, + /*LBraceLoc*/ SourceLocation(), + /*RBraceLoc*/ SourceLocation()); break; } @@ -6830,13 +7036,36 @@ InitializationSequence::Perform(Sema &S, CurInit.get()->getValueKind()); break; - case SK_ArrayInit: + case SK_ArrayLoopIndex: { + Expr *Cur = CurInit.get(); + Expr *BaseExpr = new (S.Context) + OpaqueValueExpr(Cur->getExprLoc(), Cur->getType(), + Cur->getValueKind(), Cur->getObjectKind(), Cur); + Expr *IndexExpr = + new (S.Context) ArrayInitIndexExpr(S.Context.getSizeType()); + CurInit = S.CreateBuiltinArraySubscriptExpr( + BaseExpr, Kind.getLocation(), IndexExpr, Kind.getLocation()); + ArrayLoopCommonExprs.push_back(BaseExpr); + break; + } + + case SK_ArrayLoopInit: { + assert(!ArrayLoopCommonExprs.empty() && + "mismatched SK_ArrayLoopIndex and SK_ArrayLoopInit"); + Expr *Common = ArrayLoopCommonExprs.pop_back_val(); + CurInit = new (S.Context) ArrayInitLoopExpr(Step->Type, Common, + CurInit.get()); + break; + } + + case SK_GNUArrayInit: // Okay: we checked everything before creating this step. Note that // this is a GNU extension. S.Diag(Kind.getLocation(), diag::ext_array_init_copy) << Step->Type << CurInit.get()->getType() << CurInit.get()->getSourceRange(); - + LLVM_FALLTHROUGH; + case SK_ArrayInit: // If the destination type is an incomplete array type, update the // type accordingly. if (ResultType) { @@ -6904,19 +7133,93 @@ InitializationSequence::Perform(Sema &S, } case SK_OCLSamplerInit: { - assert(Step->Type->isSamplerT() && + // Sampler initialzation have 5 cases: + // 1. function argument passing + // 1a. argument is a file-scope variable + // 1b. argument is a function-scope variable + // 1c. argument is one of caller function's parameters + // 2. variable initialization + // 2a. initializing a file-scope variable + // 2b. initializing a function-scope variable + // + // For file-scope variables, since they cannot be initialized by function + // call of __translate_sampler_initializer in LLVM IR, their references + // need to be replaced by a cast from their literal initializers to + // sampler type. Since sampler variables can only be used in function + // calls as arguments, we only need to replace them when handling the + // argument passing. + assert(Step->Type->isSamplerT() && "Sampler initialization on non-sampler type."); - - QualType SourceType = CurInit.get()->getType(); - + Expr *Init = CurInit.get(); + QualType SourceType = Init->getType(); + // Case 1 if (Entity.isParameterKind()) { - if (!SourceType->isSamplerT()) + if (!SourceType->isSamplerT()) { S.Diag(Kind.getLocation(), diag::err_sampler_argument_required) << SourceType; - } else if (Entity.getKind() != InitializedEntity::EK_Variable) { - llvm_unreachable("Invalid EntityKind!"); + break; + } else if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Init)) { + auto Var = cast<VarDecl>(DRE->getDecl()); + // Case 1b and 1c + // No cast from integer to sampler is needed. + if (!Var->hasGlobalStorage()) { + CurInit = ImplicitCastExpr::Create(S.Context, Step->Type, + CK_LValueToRValue, Init, + /*BasePath=*/nullptr, VK_RValue); + break; + } + // Case 1a + // For function call with a file-scope sampler variable as argument, + // get the integer literal. + // Do not diagnose if the file-scope variable does not have initializer + // since this has already been diagnosed when parsing the variable + // declaration. + if (!Var->getInit() || !isa<ImplicitCastExpr>(Var->getInit())) + break; + Init = cast<ImplicitCastExpr>(const_cast<Expr*>( + Var->getInit()))->getSubExpr(); + SourceType = Init->getType(); + } + } else { + // Case 2 + // Check initializer is 32 bit integer constant. + // If the initializer is taken from global variable, do not diagnose since + // this has already been done when parsing the variable declaration. + if (!Init->isConstantInitializer(S.Context, false)) + break; + + if (!SourceType->isIntegerType() || + 32 != S.Context.getIntWidth(SourceType)) { + S.Diag(Kind.getLocation(), diag::err_sampler_initializer_not_integer) + << SourceType; + break; + } + + llvm::APSInt Result; + Init->EvaluateAsInt(Result, S.Context); + const uint64_t SamplerValue = Result.getLimitedValue(); + // 32-bit value of sampler's initializer is interpreted as + // bit-field with the following structure: + // |unspecified|Filter|Addressing Mode| Normalized Coords| + // |31 6|5 4|3 1| 0| + // This structure corresponds to enum values of sampler properties + // defined in SPIR spec v1.2 and also opencl-c.h + unsigned AddressingMode = (0x0E & SamplerValue) >> 1; + unsigned FilterMode = (0x30 & SamplerValue) >> 4; + if (FilterMode != 1 && FilterMode != 2) + S.Diag(Kind.getLocation(), + diag::warn_sampler_initializer_invalid_bits) + << "Filter Mode"; + if (AddressingMode > 4) + S.Diag(Kind.getLocation(), + diag::warn_sampler_initializer_invalid_bits) + << "Addressing Mode"; } + // Cases 1a, 2a and 2b + // Insert cast from integer to sampler. + CurInit = S.ImpCastExprToType(Init, S.Context.OCLSamplerTy, + CK_IntToOCLSampler); break; } case SK_OCLZeroEvent: { @@ -6928,6 +7231,15 @@ InitializationSequence::Perform(Sema &S, CurInit.get()->getValueKind()); break; } + case SK_OCLZeroQueue: { + assert(Step->Type->isQueueT() && + "Event initialization on non queue type."); + + CurInit = S.ImpCastExprToType(CurInit.get(), Step->Type, + CK_ZeroToOCLQueue, + CurInit.get()->getValueKind()); + break; + } } } @@ -7190,6 +7502,25 @@ bool InitializationSequence::Diagnose(Sema &S, << Args[0]->getSourceRange(); break; + case FK_NonConstLValueReferenceBindingToBitfield: { + // We don't necessarily have an unambiguous source bit-field. + FieldDecl *BitField = Args[0]->getSourceBitField(); + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_bitfield) + << DestType.isVolatileQualified() + << (BitField ? BitField->getDeclName() : DeclarationName()) + << (BitField != nullptr) + << Args[0]->getSourceRange(); + if (BitField) + S.Diag(BitField->getLocation(), diag::note_bitfield_decl); + break; + } + + case FK_NonConstLValueReferenceBindingToVectorElement: + S.Diag(Kind.getLocation(), diag::err_reference_bind_to_vector_element) + << DestType.isVolatileQualified() + << Args[0]->getSourceRange(); + break; + case FK_RValueReferenceBindingToLValue: S.Diag(Kind.getLocation(), diag::err_lvalue_to_rvalue_ref) << DestType.getNonReferenceType() << Args[0]->getType() @@ -7487,6 +7818,14 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "non-const lvalue reference bound to temporary"; break; + case FK_NonConstLValueReferenceBindingToBitfield: + OS << "non-const lvalue reference bound to bit-field"; + break; + + case FK_NonConstLValueReferenceBindingToVectorElement: + OS << "non-const lvalue reference bound to vector element"; + break; + case FK_NonConstLValueReferenceBindingToUnrelated: OS << "non-const lvalue reference bound to unrelated type"; break; @@ -7583,15 +7922,15 @@ void InitializationSequence::dump(raw_ostream &OS) const { break; case SK_CastDerivedToBaseRValue: - OS << "derived-to-base case (rvalue" << S->Type.getAsString() << ")"; + OS << "derived-to-base (rvalue)"; break; case SK_CastDerivedToBaseXValue: - OS << "derived-to-base case (xvalue" << S->Type.getAsString() << ")"; + OS << "derived-to-base (xvalue)"; break; case SK_CastDerivedToBaseLValue: - OS << "derived-to-base case (lvalue" << S->Type.getAsString() << ")"; + OS << "derived-to-base (lvalue)"; break; case SK_BindReference: @@ -7602,6 +7941,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "bind reference to a temporary"; break; + case SK_FinalCopy: + OS << "final copy in class direct-initialization"; + break; + case SK_ExtraneousCopyToTemporary: OS << "extraneous C++03 copy to temporary"; break; @@ -7678,10 +8021,22 @@ void InitializationSequence::dump(raw_ostream &OS) const { OS << "Objective-C object conversion"; break; + case SK_ArrayLoopIndex: + OS << "indexing for array initialization loop"; + break; + + case SK_ArrayLoopInit: + OS << "array initialization loop"; + break; + case SK_ArrayInit: OS << "array initialization"; break; + case SK_GNUArrayInit: + OS << "array initialization (GNU extension)"; + break; + case SK_ParenthesizedArrayInit: OS << "parenthesized array initialization"; break; @@ -7713,6 +8068,10 @@ void InitializationSequence::dump(raw_ostream &OS) const { case SK_OCLZeroEvent: OS << "OpenCL event_t from zero"; break; + + case SK_OCLZeroQueue: + OS << "OpenCL queue_t from zero"; + break; } OS << " [" << S->Type.getAsString() << ']'; @@ -7750,6 +8109,7 @@ static void DiagnoseNarrowingInInitList(Sema &S, switch (SCS->getNarrowingKind(S.Context, PostInit, ConstantValue, ConstantType)) { case NK_Not_Narrowing: + case NK_Dependent_Narrowing: // No narrowing occurred. return; diff --git a/lib/Sema/SemaLambda.cpp b/lib/Sema/SemaLambda.cpp index 0b3af262cd615..3bae69164ffd3 100644 --- a/lib/Sema/SemaLambda.cpp +++ b/lib/Sema/SemaLambda.cpp @@ -238,7 +238,7 @@ getGenericLambdaTemplateParameterList(LambdaScopeInfo *LSI, Sema &SemaRef) { /*Template kw loc*/ SourceLocation(), LAngleLoc, llvm::makeArrayRef((NamedDecl *const *)LSI->AutoTemplateParams.data(), LSI->AutoTemplateParams.size()), - RAngleLoc); + RAngleLoc, nullptr); } return LSI->GLTemplateParameterList; } @@ -361,7 +361,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, SourceRange IntroducerRange, TypeSourceInfo *MethodTypeInfo, SourceLocation EndLoc, - ArrayRef<ParmVarDecl *> Params) { + ArrayRef<ParmVarDecl *> Params, + const bool IsConstexprSpecified) { QualType MethodType = MethodTypeInfo->getType(); TemplateParameterList *TemplateParams = getGenericLambdaTemplateParameterList(getCurLambda(), *this); @@ -398,7 +399,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, MethodType, MethodTypeInfo, SC_None, /*isInline=*/true, - /*isConstExpr=*/false, + IsConstexprSpecified, EndLoc); Method->setAccess(AS_public); @@ -883,14 +884,20 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo, KnownDependent, Intro.Default); - CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range, - MethodTyInfo, EndLoc, Params); + CXXMethodDecl *Method = + startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params, + ParamInfo.getDeclSpec().isConstexprSpecified()); if (ExplicitParams) CheckCXXDefaultArguments(Method); // 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. + if (getLangOpts().CUDA) + CUDASetLambdaAttrs(Method); + // Introduce the function call operator as the current declaration context. PushDeclContext(CurScope, Method); @@ -1148,14 +1155,16 @@ void Sema::ActOnLambdaError(SourceLocation StartLoc, Scope *CurScope, /// \brief Add a lambda's conversion to function pointer, as described in /// C++11 [expr.prim.lambda]p6. -static void addFunctionPointerConversion(Sema &S, +static void addFunctionPointerConversion(Sema &S, SourceRange IntroducerRange, CXXRecordDecl *Class, CXXMethodDecl *CallOperator) { // This conversion is explicitly disabled if the lambda's function has // pass_object_size attributes on any of its parameters. - if (llvm::any_of(CallOperator->parameters(), - std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>))) + auto HasPassObjectSizeAttr = [](const ParmVarDecl *P) { + return P->hasAttr<PassObjectSizeAttr>(); + }; + if (llvm::any_of(CallOperator->parameters(), HasPassObjectSizeAttr)) return; // Add the conversion to function pointer. @@ -1375,10 +1384,7 @@ static void addBlockPointerConversion(Sema &S, } static ExprResult performLambdaVarCaptureInitialization( - Sema &S, LambdaScopeInfo::Capture &Capture, - FieldDecl *Field, - SmallVectorImpl<VarDecl *> &ArrayIndexVars, - SmallVectorImpl<unsigned> &ArrayIndexStarts) { + Sema &S, LambdaScopeInfo::Capture &Capture, FieldDecl *Field) { assert(Capture.isVariableCapture() && "not a variable capture"); auto *Var = Capture.getVariable(); @@ -1402,69 +1408,11 @@ static ExprResult performLambdaVarCaptureInitialization( return ExprError(); Expr *Ref = RefResult.get(); - QualType FieldType = Field->getType(); - - // When the variable has array type, create index variables for each - // dimension of the array. We use these index variables to subscript - // the source array, and other clients (e.g., CodeGen) will perform - // the necessary iteration with these index variables. - // - // FIXME: This is dumb. Add a proper AST representation for array - // copy-construction and use it here. - SmallVector<VarDecl *, 4> IndexVariables; - QualType BaseType = FieldType; - QualType SizeType = S.Context.getSizeType(); - ArrayIndexStarts.push_back(ArrayIndexVars.size()); - while (const ConstantArrayType *Array - = S.Context.getAsConstantArrayType(BaseType)) { - // Create the iteration variable for this array index. - IdentifierInfo *IterationVarName = nullptr; - { - SmallString<8> Str; - llvm::raw_svector_ostream OS(Str); - OS << "__i" << IndexVariables.size(); - IterationVarName = &S.Context.Idents.get(OS.str()); - } - VarDecl *IterationVar = VarDecl::Create( - S.Context, S.CurContext, Loc, Loc, IterationVarName, SizeType, - S.Context.getTrivialTypeSourceInfo(SizeType, Loc), SC_None); - IterationVar->setImplicit(); - IndexVariables.push_back(IterationVar); - ArrayIndexVars.push_back(IterationVar); - - // Create a reference to the iteration variable. - ExprResult IterationVarRef = - S.BuildDeclRefExpr(IterationVar, SizeType, VK_LValue, Loc); - assert(!IterationVarRef.isInvalid() && - "Reference to invented variable cannot fail!"); - IterationVarRef = S.DefaultLvalueConversion(IterationVarRef.get()); - assert(!IterationVarRef.isInvalid() && - "Conversion of invented variable cannot fail!"); - - // Subscript the array with this iteration variable. - ExprResult Subscript = - S.CreateBuiltinArraySubscriptExpr(Ref, Loc, IterationVarRef.get(), Loc); - if (Subscript.isInvalid()) - return ExprError(); - - Ref = Subscript.get(); - BaseType = Array->getElementType(); - } - - // Construct the entity that we will be initializing. For an array, this - // will be first element in the array, which may require several levels - // of array-subscript entities. - SmallVector<InitializedEntity, 4> Entities; - Entities.reserve(1 + IndexVariables.size()); - Entities.push_back(InitializedEntity::InitializeLambdaCapture( - Var->getIdentifier(), FieldType, Loc)); - for (unsigned I = 0, N = IndexVariables.size(); I != N; ++I) - Entities.push_back( - InitializedEntity::InitializeElement(S.Context, 0, Entities.back())); - + auto Entity = InitializedEntity::InitializeLambdaCapture( + Var->getIdentifier(), Field->getType(), Loc); InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); - InitializationSequence Init(S, Entities.back(), InitKind, Ref); - return Init.Perform(S, Entities.back(), InitKind, Ref); + InitializationSequence Init(S, Entity, InitKind, Ref); + return Init.Perform(S, Entity, InitKind, Ref); } ExprResult Sema::ActOnLambdaExpr(SourceLocation StartLoc, Stmt *Body, @@ -1505,8 +1453,6 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, bool ExplicitResultType; CleanupInfo LambdaCleanup; bool ContainsUnexpandedParameterPack; - SmallVector<VarDecl *, 4> ArrayIndexVars; - SmallVector<unsigned, 4> ArrayIndexStarts; { CallOperator = LSI->CallOperator; Class = LSI->Lambda; @@ -1540,14 +1486,12 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, LambdaCapture(From.getLocation(), IsImplicit, From.isCopyCapture() ? LCK_StarThis : LCK_This)); CaptureInits.push_back(From.getInitExpr()); - ArrayIndexStarts.push_back(ArrayIndexVars.size()); continue; } if (From.isVLATypeCapture()) { Captures.push_back( LambdaCapture(From.getLocation(), IsImplicit, LCK_VLAType)); CaptureInits.push_back(nullptr); - ArrayIndexStarts.push_back(ArrayIndexVars.size()); continue; } @@ -1557,13 +1501,11 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, Var, From.getEllipsisLoc())); Expr *Init = From.getInitExpr(); if (!Init) { - auto InitResult = performLambdaVarCaptureInitialization( - *this, From, *CurField, ArrayIndexVars, ArrayIndexStarts); + auto InitResult = + performLambdaVarCaptureInitialization(*this, From, *CurField); if (InitResult.isInvalid()) return ExprError(); Init = InitResult.get(); - } else { - ArrayIndexStarts.push_back(ArrayIndexVars.size()); } CaptureInits.push_back(Init); } @@ -1600,9 +1542,22 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CaptureDefault, CaptureDefaultLoc, Captures, ExplicitParams, ExplicitResultType, - CaptureInits, ArrayIndexVars, - ArrayIndexStarts, EndLoc, + CaptureInits, EndLoc, ContainsUnexpandedParameterPack); + // If the lambda expression's call operator is not explicitly marked constexpr + // and we are not in a dependent context, analyze the call operator to infer + // its constexpr-ness, supressing diagnostics while doing so. + if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() && + !CallOperator->isConstexpr() && + !Class->getDeclContext()->isDependentContext()) { + TentativeAnalysisScope DiagnosticScopeGuard(*this); + CallOperator->setConstexpr( + CheckConstexprFunctionDecl(CallOperator) && + CheckConstexprFunctionBody(CallOperator, CallOperator->getBody())); + } + + // Emit delayed shadowing warnings now that the full capture list is known. + DiagnoseShadowingLambdaDecls(LSI); if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { diff --git a/lib/Sema/SemaLookup.cpp b/lib/Sema/SemaLookup.cpp index e2550824fb69b..38a7b8c127ccb 100644 --- a/lib/Sema/SemaLookup.cpp +++ b/lib/Sema/SemaLookup.cpp @@ -12,9 +12,7 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/Lookup.h" #include "clang/AST/ASTContext.h" -#include "clang/AST/ASTMutationListener.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclCXX.h" @@ -29,6 +27,7 @@ #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" +#include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -37,17 +36,13 @@ #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TypoCorrection.h" #include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/SetVector.h" #include "llvm/ADT/SmallPtrSet.h" -#include "llvm/ADT/StringMap.h" #include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/edit_distance.h" #include "llvm/Support/ErrorHandling.h" #include <algorithm> #include <iterator> -#include <limits> #include <list> -#include <map> #include <set> #include <utility> #include <vector> @@ -455,15 +450,18 @@ static bool canHideTag(NamedDecl *D) { // Given a set of declarations in a single declarative region [...] // exactly one declaration shall declare a class name or enumeration name // that is not a typedef name and the other declarations shall all refer to - // the same variable or enumerator, or all refer to functions and function - // templates; in this case the class name or enumeration name is hidden. + // the same variable, non-static data member, or enumerator, or all refer + // to functions and function templates; in this case the class name or + // enumeration name is hidden. // C++ [basic.scope.hiding]p2: // A class name or enumeration name can be hidden by the name of a // variable, data member, function, or enumerator declared in the same // scope. + // An UnresolvedUsingValueDecl always instantiates to one of these. D = D->getUnderlyingDecl(); return isa<VarDecl>(D) || isa<EnumConstantDecl>(D) || isa<FunctionDecl>(D) || - isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D); + isa<FunctionTemplateDecl>(D) || isa<FieldDecl>(D) || + isa<UnresolvedUsingValueDecl>(D); } /// Resolves the result kind of this lookup. @@ -1298,7 +1296,7 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { // If we have a context, and it's not a context stashed in the // template parameter scope for an out-of-line definition, also // look into that context. - if (!(Found && S && S->isTemplateParamScope())) { + if (!(Found && S->isTemplateParamScope())) { assert(Ctx->isFileContext() && "We should have been looking only at file context here already."); @@ -1372,8 +1370,9 @@ Module *Sema::getOwningModule(Decl *Entity) { auto &SrcMgr = PP.getSourceManager(); SourceLocation StartLoc = SrcMgr.getLocForStartOfFile(SrcMgr.getMainFileID()); - auto &TopLevel = - VisibleModulesStack.empty() ? VisibleModules : VisibleModulesStack[0]; + auto &TopLevel = ModuleScopes.empty() + ? VisibleModules + : ModuleScopes[0].OuterVisibleModules; TopLevel.setVisible(CachedFakeTopLevelModule, StartLoc); } @@ -1542,12 +1541,17 @@ bool LookupResult::isVisibleSlow(Sema &SemaRef, NamedDecl *D) { // If this declaration is not at namespace scope nor module-private, // then it is visible if its lexical parent has a visible definition. DeclContext *DC = D->getLexicalDeclContext(); - if (!D->isModulePrivate() && - DC && !DC->isFileContext() && !isa<LinkageSpecDecl>(DC)) { + if (!D->isModulePrivate() && DC && !DC->isFileContext() && + !isa<LinkageSpecDecl>(DC) && !isa<ExportDecl>(DC)) { // For a parameter, check whether our current template declaration's // lexical context is visible, not whether there's some other visible // definition of it, because parameters aren't "within" the definition. - if ((D->isTemplateParameter() || isa<ParmVarDecl>(D)) + // + // In C++ we need to check for a visible definition due to ODR merging, + // and in C we must not because each declaration of a function gets its own + // set of declarations for tags in prototype scope. + if ((D->isTemplateParameter() || isa<ParmVarDecl>(D) + || (isa<FunctionDecl>(DC) && !SemaRef.getLangOpts().CPlusPlus)) ? isVisible(SemaRef, cast<NamedDecl>(DC)) : SemaRef.hasVisibleDefinition(cast<NamedDecl>(DC))) { if (SemaRef.ActiveTemplateInstantiations.empty() && @@ -5081,6 +5085,10 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, if (PrevNote.getDiagID() && ChosenDecl) Diag(ChosenDecl->getLocation(), PrevNote) << CorrectedQuotedStr << (ErrorRecovery ? FixItHint() : FixTypo); + + // Add any extra diagnostics. + for (const PartialDiagnostic &PD : Correction.getExtraDiagnostics()) + Diag(Correction.getCorrectionRange().getBegin(), PD); } TypoExpr *Sema::createDelayedTypo(std::unique_ptr<TypoCorrectionConsumer> TCC, diff --git a/lib/Sema/SemaObjCProperty.cpp b/lib/Sema/SemaObjCProperty.cpp index 5e38751f44a50..3481b82679c2a 100644 --- a/lib/Sema/SemaObjCProperty.cpp +++ b/lib/Sema/SemaObjCProperty.cpp @@ -753,7 +753,7 @@ static void checkARCPropertyImpl(Sema &S, SourceLocation propertyImplLoc, break; case Qualifiers::OCL_Weak: - S.Diag(ivar->getLocation(), diag::error_weak_property) + S.Diag(ivar->getLocation(), diag::err_weak_property) << property->getDeclName() << ivar->getDeclName(); break; @@ -904,7 +904,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, dyn_cast<ObjCContainerDecl>(CurContext); // Make sure we have a context for the property implementation declaration. if (!ClassImpDecl) { - Diag(AtLoc, diag::error_missing_property_context); + Diag(AtLoc, diag::err_missing_property_context); return nullptr; } if (PropertyIvarLoc.isInvalid()) @@ -928,11 +928,11 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Look for this property declaration in the @implementation's @interface property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind); if (!property) { - Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); + Diag(PropertyLoc, diag::err_bad_property_decl) << IDecl->getDeclName(); return nullptr; } if (property->isClassProperty() && Synthesize) { - Diag(PropertyLoc, diag::error_synthesize_on_class_property) << PropertyId; + Diag(PropertyLoc, diag::err_synthesize_on_class_property) << PropertyId; return nullptr; } unsigned PIkind = property->getPropertyAttributesAsWritten(); @@ -948,7 +948,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (const ObjCCategoryDecl *CD = dyn_cast<ObjCCategoryDecl>(property->getDeclContext())) { if (!CD->IsClassExtension()) { - Diag(PropertyLoc, diag::error_category_property) << CD->getDeclName(); + Diag(PropertyLoc, diag::err_category_property) << CD->getDeclName(); Diag(property->getLocation(), diag::note_property_declare); return nullptr; } @@ -992,12 +992,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } else if ((CatImplClass = dyn_cast<ObjCCategoryImplDecl>(ClassImpDecl))) { if (Synthesize) { - Diag(AtLoc, diag::error_synthesize_category_decl); + Diag(AtLoc, diag::err_synthesize_category_decl); return nullptr; } IDecl = CatImplClass->getClassInterface(); if (!IDecl) { - Diag(AtLoc, diag::error_missing_property_interface); + Diag(AtLoc, diag::err_missing_property_interface); return nullptr; } ObjCCategoryDecl *Category = @@ -1010,12 +1010,12 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // Look for this property declaration in @implementation's category property = Category->FindPropertyDeclaration(PropertyId, QueryKind); if (!property) { - Diag(PropertyLoc, diag::error_bad_category_property_decl) + Diag(PropertyLoc, diag::err_bad_category_property_decl) << Category->getDeclName(); return nullptr; } } else { - Diag(AtLoc, diag::error_bad_property_context); + Diag(AtLoc, diag::err_bad_property_context); return nullptr; } ObjCIvarDecl *Ivar = nullptr; @@ -1146,20 +1146,22 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, diag::err_abstract_type_in_decl, AbstractSynthesizedIvarType)) { Diag(property->getLocation(), diag::note_property_declare); + // An abstract type is as bad as an incomplete type. + CompleteTypeErr = true; + } + if (CompleteTypeErr) Ivar->setInvalidDecl(); - } else if (CompleteTypeErr) - Ivar->setInvalidDecl(); ClassImpDecl->addDecl(Ivar); IDecl->makeDeclVisibleInContext(Ivar); if (getLangOpts().ObjCRuntime.isFragile()) - Diag(PropertyDiagLoc, diag::error_missing_property_ivar_decl) + Diag(PropertyDiagLoc, diag::err_missing_property_ivar_decl) << PropertyId; // Note! I deliberately want it to fall thru so, we have a // a property implementation and to avoid future warnings. } else if (getLangOpts().ObjCRuntime.isNonFragile() && !declaresSameEntity(ClassDeclared, IDecl)) { - Diag(PropertyDiagLoc, diag::error_ivar_in_superclass_use) + Diag(PropertyDiagLoc, diag::err_ivar_in_superclass_use) << property->getDeclName() << Ivar->getDeclName() << ClassDeclared->getDeclName(); Diag(Ivar->getLocation(), diag::note_previous_access_declaration) @@ -1184,7 +1186,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, == Compatible); } if (!compat) { - Diag(PropertyDiagLoc, diag::error_property_ivar_type) + Diag(PropertyDiagLoc, diag::err_property_ivar_type) << property->getDeclName() << PropType << Ivar->getDeclName() << IvarType; Diag(Ivar->getLocation(), diag::note_ivar_decl); @@ -1199,7 +1201,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, QualType rhsType =Context.getCanonicalType(IvarType).getUnqualifiedType(); if (lhsType != rhsType && lhsType->isArithmeticType()) { - Diag(PropertyDiagLoc, diag::error_property_ivar_type) + Diag(PropertyDiagLoc, diag::err_property_ivar_type) << property->getDeclName() << PropType << Ivar->getDeclName() << IvarType; Diag(Ivar->getLocation(), diag::note_ivar_decl); @@ -1209,7 +1211,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // __weak is explicit. So it works on Canonical type. if ((PropType.isObjCGCWeak() && !IvarType.isObjCGCWeak() && getLangOpts().getGC() != LangOptions::NonGC)) { - Diag(PropertyDiagLoc, diag::error_weak_property) + Diag(PropertyDiagLoc, diag::err_weak_property) << property->getDeclName() << Ivar->getDeclName(); Diag(Ivar->getLocation(), diag::note_ivar_decl); // Fall thru - see previous comment @@ -1218,7 +1220,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if ((property->getType()->isObjCObjectPointerType() || PropType.isObjCGCStrong()) && IvarType.isObjCGCWeak() && getLangOpts().getGC() != LangOptions::NonGC) { - Diag(PropertyDiagLoc, diag::error_strong_property) + Diag(PropertyDiagLoc, diag::err_strong_property) << property->getDeclName() << Ivar->getDeclName(); // Fall thru - see previous comment } @@ -1228,7 +1230,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, checkARCPropertyImpl(*this, PropertyLoc, property, Ivar); } else if (PropertyIvar) // @dynamic - Diag(PropertyDiagLoc, diag::error_dynamic_property_ivar_decl); + Diag(PropertyDiagLoc, diag::err_dynamic_property_ivar_decl); assert (property && "ActOnPropertyImplDecl - property declaration missing"); ObjCPropertyImplDecl *PIDecl = @@ -1348,7 +1350,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = IC->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyLoc, diag::error_duplicate_ivar_use) + Diag(PropertyLoc, diag::err_duplicate_ivar_use) << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() << PropertyIvar; Diag(PPIDecl->getLocation(), diag::note_previous_use); @@ -1356,7 +1358,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (ObjCPropertyImplDecl *PPIDecl = IC->FindPropertyImplDecl(PropertyId, QueryKind)) { - Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; + Diag(PropertyLoc, diag::err_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return nullptr; } @@ -1387,7 +1389,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (Synthesize) if (ObjCPropertyImplDecl *PPIDecl = CatImplClass->FindPropertyImplIvarDecl(PropertyIvar)) { - Diag(PropertyDiagLoc, diag::error_duplicate_ivar_use) + Diag(PropertyDiagLoc, diag::err_duplicate_ivar_use) << PropertyId << PPIDecl->getPropertyDecl()->getIdentifier() << PropertyIvar; Diag(PPIDecl->getLocation(), diag::note_previous_use); @@ -1395,7 +1397,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (ObjCPropertyImplDecl *PPIDecl = CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) { - Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId; + Diag(PropertyDiagLoc, diag::err_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return nullptr; } @@ -1505,7 +1507,7 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr); else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType) != Compatible) { - Diag(Loc, diag::error_property_accessor_type) + Diag(Loc, diag::err_property_accessor_type) << property->getDeclName() << PropertyRValueType << GetterMethod->getSelector() << GetterType; Diag(GetterMethod->getLocation(), diag::note_declared_at); diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index b7ac48583e1a9..804aadc0ff77e 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -72,8 +72,13 @@ private: typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy; typedef std::pair<unsigned, VarDecl *> LCDeclInfo; typedef llvm::DenseMap<ValueDecl *, LCDeclInfo> LoopControlVariablesMapTy; - typedef llvm::DenseMap< - ValueDecl *, OMPClauseMappableExprCommon::MappableExprComponentLists> + /// Struct that associates a component with the clause kind where they are + /// found. + struct MappedExprComponentTy { + OMPClauseMappableExprCommon::MappableExprComponentLists Components; + OpenMPClauseKind Kind = OMPC_unknown; + }; + typedef llvm::DenseMap<ValueDecl *, MappedExprComponentTy> MappedExprComponentsTy; typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>> CriticalsWithHintsTy; @@ -123,7 +128,7 @@ private: typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; - DSAVarData getDSA(StackTy::reverse_iterator& Iter, ValueDecl *D); + DSAVarData getDSA(StackTy::reverse_iterator &Iter, ValueDecl *D); /// \brief Checks if the variable is a local for OpenMP region. bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter); @@ -293,9 +298,7 @@ public: Stack[Stack.size() - 2].CancelRegion || Cancel; } /// \brief Return true if current region has inner cancel construct. - bool isCancelRegion() const { - return Stack.back().CancelRegion; - } + bool isCancelRegion() const { return Stack.back().CancelRegion; } /// \brief Set collapse value for the region. void setAssociatedLoops(unsigned Val) { Stack.back().AssociatedLoops = Val; } @@ -323,12 +326,13 @@ public: Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } - // Do the check specified in \a Check to all component lists and return true - // if any issue is found. + /// Do the check specified in \a Check to all component lists and return true + /// if any issue is found. bool checkMappableExprComponentListsForDecl( ValueDecl *VD, bool CurrentRegionOnly, - const llvm::function_ref<bool( - OMPClauseMappableExprCommon::MappableExprComponentListRef)> &Check) { + const llvm::function_ref< + bool(OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind)> &Check) { auto SI = Stack.rbegin(); auto SE = Stack.rend(); @@ -344,24 +348,26 @@ public: for (; SI != SE; ++SI) { auto MI = SI->MappedExprComponents.find(VD); if (MI != SI->MappedExprComponents.end()) - for (auto &L : MI->second) - if (Check(L)) + for (auto &L : MI->second.Components) + if (Check(L, MI->second.Kind)) return true; } return false; } - // Create a new mappable expression component list associated with a given - // declaration and initialize it with the provided list of components. + /// Create a new mappable expression component list associated with a given + /// declaration and initialize it with the provided list of components. void addMappableExpressionComponents( ValueDecl *VD, - OMPClauseMappableExprCommon::MappableExprComponentListRef Components) { + OMPClauseMappableExprCommon::MappableExprComponentListRef Components, + OpenMPClauseKind WhereFoundClauseKind) { assert(Stack.size() > 1 && "Not expecting to retrieve components from a empty stack!"); auto &MEC = Stack.back().MappedExprComponents[VD]; // Create new entry and append the new components there. - MEC.resize(MEC.size() + 1); - MEC.back().append(Components.begin(), Components.end()); + MEC.Components.resize(MEC.Components.size() + 1); + MEC.Components.back().append(Components.begin(), Components.end()); + MEC.Kind = WhereFoundClauseKind; } unsigned getNestingLevel() const { @@ -393,7 +399,7 @@ bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { static ValueDecl *getCanonicalDecl(ValueDecl *D) { auto *VD = dyn_cast<VarDecl>(D); auto *FD = dyn_cast<FieldDecl>(D); - if (VD != nullptr) { + if (VD != nullptr) { VD = VD->getCanonicalDecl(); D = VD; } else { @@ -404,7 +410,7 @@ static ValueDecl *getCanonicalDecl(ValueDecl *D) { return D; } -DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator& Iter, +DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator &Iter, ValueDecl *D) { D = getCanonicalDecl(D); auto *VD = dyn_cast<VarDecl>(D); @@ -771,18 +777,12 @@ DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( D = getCanonicalDecl(D); auto StartI = std::next(Stack.rbegin()); auto EndI = Stack.rend(); - if (FromParent && StartI != EndI) { + if (FromParent && StartI != EndI) StartI = std::next(StartI); - } - for (auto I = StartI, EE = EndI; I != EE; ++I) { - if (!DPred(I->Directive)) - break; - DSAVarData DVar = getDSA(I, D); - if (CPred(DVar.CKind)) - return DVar; + if (StartI == EndI || !DPred(StartI->Directive)) return DSAVarData(); - } - return DSAVarData(); + DSAVarData DVar = getDSA(StartI, D); + return CPred(DVar.CKind) ? DVar : DSAVarData(); } bool DSAStackTy::hasExplicitDSA( @@ -903,7 +903,6 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { // array section, the runtime library may pass the NULL value to the // device instead of the value passed to it by the compiler. - if (Ty->isReferenceType()) Ty = Ty->castAs<ReferenceType>()->getPointeeType(); @@ -916,7 +915,13 @@ bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { DSAStack->checkMappableExprComponentListsForDecl( D, /*CurrentRegionOnly=*/true, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef - MapExprComponents) { + MapExprComponents, + OpenMPClauseKind WhereFoundClauseKind) { + // Only the map clause information influences how a variable is + // captured. E.g. is_device_ptr does not require changing the default + // behavior. + if (WhereFoundClauseKind != OMPC_map) + return false; auto EI = MapExprComponents.rbegin(); auto EE = MapExprComponents.rend(); @@ -1062,7 +1067,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { // clause requires an accessible, unambiguous default constructor for the // class type, unless the list item is also specified in a firstprivate // clause. - if (auto D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { + if (auto *D = dyn_cast_or_null<OMPExecutableDirective>(CurDirective)) { for (auto *C : D->clauses()) { if (auto *Clause = dyn_cast<OMPLastprivateClause>(C)) { SmallVector<Expr *, 8> PrivateCopies; @@ -1121,7 +1126,7 @@ public: explicit VarDeclFilterCCC(Sema &S) : SemaRef(S) {} bool ValidateCandidate(const TypoCorrection &Candidate) override { NamedDecl *ND = Candidate.getCorrectionDecl(); - if (VarDecl *VD = dyn_cast_or_null<VarDecl>(ND)) { + if (auto *VD = dyn_cast_or_null<VarDecl>(ND)) { return VD->hasGlobalStorage() && SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), SemaRef.getCurScope()); @@ -1290,7 +1295,7 @@ class LocalVarRefChecker : public ConstStmtVisitor<LocalVarRefChecker, bool> { public: bool VisitDeclRefExpr(const DeclRefExpr *E) { - if (auto VD = dyn_cast<VarDecl>(E->getDecl())) { + if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { if (VD->hasLocalStorage()) { SemaRef.Diag(E->getLocStart(), diag::err_omp_local_var_in_threadprivate_init) @@ -1471,7 +1476,8 @@ public: auto DVar = Stack->getTopDSA(VD, false); // Check if the variable has explicit DSA set and stop analysis if it so. - if (DVar.RefExpr) return; + if (DVar.RefExpr) + return; auto ELoc = E->getExprLoc(); auto DKind = Stack->getCurrentDirective(); @@ -1550,7 +1556,8 @@ public: !Stack->isLoopControlVariable(FD).first) ImplicitFirstprivate.push_back(E); } - } + } else + Visit(E->getBase()); } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { for (auto *C : S->clauses()) { @@ -1587,7 +1594,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_parallel_for: case OMPD_parallel_for_simd: case OMPD_parallel_sections: - case OMPD_teams: { + case OMPD_teams: + case OMPD_target_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1616,7 +1624,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_target: case OMPD_target_parallel: case OMPD_target_parallel_for: - case OMPD_target_parallel_for_simd: { + case OMPD_target_parallel_for_simd: + case OMPD_target_simd: { Sema::CapturedParamNameType Params[] = { std::make_pair(StringRef(), QualType()) // __context with shared vars }; @@ -1685,7 +1694,13 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { } case OMPD_distribute_parallel_for_simd: case OMPD_distribute_simd: - case OMPD_distribute_parallel_for: { + case OMPD_distribute_parallel_for: + case OMPD_teams_distribute: + case OMPD_teams_distribute_simd: + case OMPD_teams_distribute_parallel_for_simd: + case OMPD_teams_distribute_parallel_for: + case OMPD_target_teams_distribute: + case OMPD_target_teams_distribute_parallel_for: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1740,7 +1755,8 @@ static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, } WithInit = true; } - auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty); + auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty, + CaptureExpr->getLocStart()); if (!WithInit) CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange())); S.CurContext->addHiddenDecl(CED); @@ -1868,1241 +1884,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, const DeclarationNameInfo &CurrentName, OpenMPDirectiveKind CancelRegion, SourceLocation StartLoc) { - // Allowed nesting of constructs - // +------------------+-----------------+------------------------------------+ - // | Parent directive | Child directive | Closely (!), No-Closely(+), Both(*)| - // +------------------+-----------------+------------------------------------+ - // | parallel | parallel | * | - // | parallel | for | * | - // | parallel | for simd | * | - // | parallel | master | * | - // | parallel | critical | * | - // | parallel | simd | * | - // | parallel | sections | * | - // | parallel | section | + | - // | parallel | single | * | - // | parallel | parallel for | * | - // | parallel |parallel for simd| * | - // | parallel |parallel sections| * | - // | parallel | task | * | - // | parallel | taskyield | * | - // | parallel | barrier | * | - // | parallel | taskwait | * | - // | parallel | taskgroup | * | - // | parallel | flush | * | - // | parallel | ordered | + | - // | parallel | atomic | * | - // | parallel | target | * | - // | parallel | target parallel | * | - // | parallel | target parallel | * | - // | | for | | - // | parallel | target enter | * | - // | | data | | - // | parallel | target exit | * | - // | | data | | - // | parallel | teams | + | - // | parallel | cancellation | | - // | | point | ! | - // | parallel | cancel | ! | - // | parallel | taskloop | * | - // | parallel | taskloop simd | * | - // | parallel | distribute | + | - // | parallel | distribute | + | - // | | parallel for | | - // | parallel | distribute | + | - // | |parallel for simd| | - // | parallel | distribute simd | + | - // +------------------+-----------------+------------------------------------+ - // | for | parallel | * | - // | for | for | + | - // | for | for simd | + | - // | for | master | + | - // | for | critical | * | - // | for | simd | * | - // | for | sections | + | - // | for | section | + | - // | for | single | + | - // | for | parallel for | * | - // | for |parallel for simd| * | - // | for |parallel sections| * | - // | for | task | * | - // | for | taskyield | * | - // | for | barrier | + | - // | for | taskwait | * | - // | for | taskgroup | * | - // | for | flush | * | - // | for | ordered | * (if construct is ordered) | - // | for | atomic | * | - // | for | target | * | - // | for | target parallel | * | - // | for | target parallel | * | - // | | for | | - // | for | target enter | * | - // | | data | | - // | for | target exit | * | - // | | data | | - // | for | teams | + | - // | for | cancellation | | - // | | point | ! | - // | for | cancel | ! | - // | for | taskloop | * | - // | for | taskloop simd | * | - // | for | distribute | + | - // | for | distribute | + | - // | | parallel for | | - // | for | distribute | + | - // | |parallel for simd| | - // | for | distribute simd | + | - // | for | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | master | parallel | * | - // | master | for | + | - // | master | for simd | + | - // | master | master | * | - // | master | critical | * | - // | master | simd | * | - // | master | sections | + | - // | master | section | + | - // | master | single | + | - // | master | parallel for | * | - // | master |parallel for simd| * | - // | master |parallel sections| * | - // | master | task | * | - // | master | taskyield | * | - // | master | barrier | + | - // | master | taskwait | * | - // | master | taskgroup | * | - // | master | flush | * | - // | master | ordered | + | - // | master | atomic | * | - // | master | target | * | - // | master | target parallel | * | - // | master | target parallel | * | - // | | for | | - // | master | target enter | * | - // | | data | | - // | master | target exit | * | - // | | data | | - // | master | teams | + | - // | master | cancellation | | - // | | point | | - // | master | cancel | | - // | master | taskloop | * | - // | master | taskloop simd | * | - // | master | distribute | + | - // | master | distribute | + | - // | | parallel for | | - // | master | distribute | + | - // | |parallel for simd| | - // | master | distribute simd | + | - // | master | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | critical | parallel | * | - // | critical | for | + | - // | critical | for simd | + | - // | critical | master | * | - // | critical | critical | * (should have different names) | - // | critical | simd | * | - // | critical | sections | + | - // | critical | section | + | - // | critical | single | + | - // | critical | parallel for | * | - // | critical |parallel for simd| * | - // | critical |parallel sections| * | - // | critical | task | * | - // | critical | taskyield | * | - // | critical | barrier | + | - // | critical | taskwait | * | - // | critical | taskgroup | * | - // | critical | ordered | + | - // | critical | atomic | * | - // | critical | target | * | - // | critical | target parallel | * | - // | critical | target parallel | * | - // | | for | | - // | critical | target enter | * | - // | | data | | - // | critical | target exit | * | - // | | data | | - // | critical | teams | + | - // | critical | cancellation | | - // | | point | | - // | critical | cancel | | - // | critical | taskloop | * | - // | critical | taskloop simd | * | - // | critical | distribute | + | - // | critical | distribute | + | - // | | parallel for | | - // | critical | distribute | + | - // | |parallel for simd| | - // | critical | distribute simd | + | - // | critical | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | simd | parallel | | - // | simd | for | | - // | simd | for simd | | - // | simd | master | | - // | simd | critical | | - // | simd | simd | * | - // | simd | sections | | - // | simd | section | | - // | simd | single | | - // | simd | parallel for | | - // | simd |parallel for simd| | - // | simd |parallel sections| | - // | simd | task | | - // | simd | taskyield | | - // | simd | barrier | | - // | simd | taskwait | | - // | simd | taskgroup | | - // | simd | flush | | - // | simd | ordered | + (with simd clause) | - // | simd | atomic | | - // | simd | target | | - // | simd | target parallel | | - // | simd | target parallel | | - // | | for | | - // | simd | target enter | | - // | | data | | - // | simd | target exit | | - // | | data | | - // | simd | teams | | - // | simd | cancellation | | - // | | point | | - // | simd | cancel | | - // | simd | taskloop | | - // | simd | taskloop simd | | - // | simd | distribute | | - // | simd | distribute | | - // | | parallel for | | - // | simd | distribute | | - // | |parallel for simd| | - // | simd | distribute simd | | - // | simd | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | for simd | parallel | | - // | for simd | for | | - // | for simd | for simd | | - // | for simd | master | | - // | for simd | critical | | - // | for simd | simd | * | - // | for simd | sections | | - // | for simd | section | | - // | for simd | single | | - // | for simd | parallel for | | - // | for simd |parallel for simd| | - // | for simd |parallel sections| | - // | for simd | task | | - // | for simd | taskyield | | - // | for simd | barrier | | - // | for simd | taskwait | | - // | for simd | taskgroup | | - // | for simd | flush | | - // | for simd | ordered | + (with simd clause) | - // | for simd | atomic | | - // | for simd | target | | - // | for simd | target parallel | | - // | for simd | target parallel | | - // | | for | | - // | for simd | target enter | | - // | | data | | - // | for simd | target exit | | - // | | data | | - // | for simd | teams | | - // | for simd | cancellation | | - // | | point | | - // | for simd | cancel | | - // | for simd | taskloop | | - // | for simd | taskloop simd | | - // | for simd | distribute | | - // | for simd | distribute | | - // | | parallel for | | - // | for simd | distribute | | - // | |parallel for simd| | - // | for simd | distribute simd | | - // | for simd | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | parallel for simd| parallel | | - // | parallel for simd| for | | - // | parallel for simd| for simd | | - // | parallel for simd| master | | - // | parallel for simd| critical | | - // | parallel for simd| simd | * | - // | parallel for simd| sections | | - // | parallel for simd| section | | - // | parallel for simd| single | | - // | parallel for simd| parallel for | | - // | parallel for simd|parallel for simd| | - // | parallel for simd|parallel sections| | - // | parallel for simd| task | | - // | parallel for simd| taskyield | | - // | parallel for simd| barrier | | - // | parallel for simd| taskwait | | - // | parallel for simd| taskgroup | | - // | parallel for simd| flush | | - // | parallel for simd| ordered | + (with simd clause) | - // | parallel for simd| atomic | | - // | parallel for simd| target | | - // | parallel for simd| target parallel | | - // | parallel for simd| target parallel | | - // | | for | | - // | parallel for simd| target enter | | - // | | data | | - // | parallel for simd| target exit | | - // | | data | | - // | parallel for simd| teams | | - // | parallel for simd| cancellation | | - // | | point | | - // | parallel for simd| cancel | | - // | parallel for simd| taskloop | | - // | parallel for simd| taskloop simd | | - // | parallel for simd| distribute | | - // | parallel for simd| distribute | | - // | | parallel for | | - // | parallel for simd| distribute | | - // | |parallel for simd| | - // | parallel for simd| distribute simd | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | sections | parallel | * | - // | sections | for | + | - // | sections | for simd | + | - // | sections | master | + | - // | sections | critical | * | - // | sections | simd | * | - // | sections | sections | + | - // | sections | section | * | - // | sections | single | + | - // | sections | parallel for | * | - // | sections |parallel for simd| * | - // | sections |parallel sections| * | - // | sections | task | * | - // | sections | taskyield | * | - // | sections | barrier | + | - // | sections | taskwait | * | - // | sections | taskgroup | * | - // | sections | flush | * | - // | sections | ordered | + | - // | sections | atomic | * | - // | sections | target | * | - // | sections | target parallel | * | - // | sections | target parallel | * | - // | | for | | - // | sections | target enter | * | - // | | data | | - // | sections | target exit | * | - // | | data | | - // | sections | teams | + | - // | sections | cancellation | | - // | | point | ! | - // | sections | cancel | ! | - // | sections | taskloop | * | - // | sections | taskloop simd | * | - // | sections | distribute | + | - // | sections | distribute | + | - // | | parallel for | | - // | sections | distribute | + | - // | |parallel for simd| | - // | sections | distribute simd | + | - // | sections | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | section | parallel | * | - // | section | for | + | - // | section | for simd | + | - // | section | master | + | - // | section | critical | * | - // | section | simd | * | - // | section | sections | + | - // | section | section | + | - // | section | single | + | - // | section | parallel for | * | - // | section |parallel for simd| * | - // | section |parallel sections| * | - // | section | task | * | - // | section | taskyield | * | - // | section | barrier | + | - // | section | taskwait | * | - // | section | taskgroup | * | - // | section | flush | * | - // | section | ordered | + | - // | section | atomic | * | - // | section | target | * | - // | section | target parallel | * | - // | section | target parallel | * | - // | | for | | - // | section | target enter | * | - // | | data | | - // | section | target exit | * | - // | | data | | - // | section | teams | + | - // | section | cancellation | | - // | | point | ! | - // | section | cancel | ! | - // | section | taskloop | * | - // | section | taskloop simd | * | - // | section | distribute | + | - // | section | distribute | + | - // | | parallel for | | - // | section | distribute | + | - // | |parallel for simd| | - // | section | distribute simd | + | - // | section | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | single | parallel | * | - // | single | for | + | - // | single | for simd | + | - // | single | master | + | - // | single | critical | * | - // | single | simd | * | - // | single | sections | + | - // | single | section | + | - // | single | single | + | - // | single | parallel for | * | - // | single |parallel for simd| * | - // | single |parallel sections| * | - // | single | task | * | - // | single | taskyield | * | - // | single | barrier | + | - // | single | taskwait | * | - // | single | taskgroup | * | - // | single | flush | * | - // | single | ordered | + | - // | single | atomic | * | - // | single | target | * | - // | single | target parallel | * | - // | single | target parallel | * | - // | | for | | - // | single | target enter | * | - // | | data | | - // | single | target exit | * | - // | | data | | - // | single | teams | + | - // | single | cancellation | | - // | | point | | - // | single | cancel | | - // | single | taskloop | * | - // | single | taskloop simd | * | - // | single | distribute | + | - // | single | distribute | + | - // | | parallel for | | - // | single | distribute | + | - // | |parallel for simd| | - // | single | distribute simd | + | - // | single | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | parallel for | parallel | * | - // | parallel for | for | + | - // | parallel for | for simd | + | - // | parallel for | master | + | - // | parallel for | critical | * | - // | parallel for | simd | * | - // | parallel for | sections | + | - // | parallel for | section | + | - // | parallel for | single | + | - // | parallel for | parallel for | * | - // | parallel for |parallel for simd| * | - // | parallel for |parallel sections| * | - // | parallel for | task | * | - // | parallel for | taskyield | * | - // | parallel for | barrier | + | - // | parallel for | taskwait | * | - // | parallel for | taskgroup | * | - // | parallel for | flush | * | - // | parallel for | ordered | * (if construct is ordered) | - // | parallel for | atomic | * | - // | parallel for | target | * | - // | parallel for | target parallel | * | - // | parallel for | target parallel | * | - // | | for | | - // | parallel for | target enter | * | - // | | data | | - // | parallel for | target exit | * | - // | | data | | - // | parallel for | teams | + | - // | parallel for | cancellation | | - // | | point | ! | - // | parallel for | cancel | ! | - // | parallel for | taskloop | * | - // | parallel for | taskloop simd | * | - // | parallel for | distribute | + | - // | parallel for | distribute | + | - // | | parallel for | | - // | parallel for | distribute | + | - // | |parallel for simd| | - // | parallel for | distribute simd | + | - // | parallel for | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | parallel sections| parallel | * | - // | parallel sections| for | + | - // | parallel sections| for simd | + | - // | parallel sections| master | + | - // | parallel sections| critical | + | - // | parallel sections| simd | * | - // | parallel sections| sections | + | - // | parallel sections| section | * | - // | parallel sections| single | + | - // | parallel sections| parallel for | * | - // | parallel sections|parallel for simd| * | - // | parallel sections|parallel sections| * | - // | parallel sections| task | * | - // | parallel sections| taskyield | * | - // | parallel sections| barrier | + | - // | parallel sections| taskwait | * | - // | parallel sections| taskgroup | * | - // | parallel sections| flush | * | - // | parallel sections| ordered | + | - // | parallel sections| atomic | * | - // | parallel sections| target | * | - // | parallel sections| target parallel | * | - // | parallel sections| target parallel | * | - // | | for | | - // | parallel sections| target enter | * | - // | | data | | - // | parallel sections| target exit | * | - // | | data | | - // | parallel sections| teams | + | - // | parallel sections| cancellation | | - // | | point | ! | - // | parallel sections| cancel | ! | - // | parallel sections| taskloop | * | - // | parallel sections| taskloop simd | * | - // | parallel sections| distribute | + | - // | parallel sections| distribute | + | - // | | parallel for | | - // | parallel sections| distribute | + | - // | |parallel for simd| | - // | parallel sections| distribute simd | + | - // | parallel sections| target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | task | parallel | * | - // | task | for | + | - // | task | for simd | + | - // | task | master | + | - // | task | critical | * | - // | task | simd | * | - // | task | sections | + | - // | task | section | + | - // | task | single | + | - // | task | parallel for | * | - // | task |parallel for simd| * | - // | task |parallel sections| * | - // | task | task | * | - // | task | taskyield | * | - // | task | barrier | + | - // | task | taskwait | * | - // | task | taskgroup | * | - // | task | flush | * | - // | task | ordered | + | - // | task | atomic | * | - // | task | target | * | - // | task | target parallel | * | - // | task | target parallel | * | - // | | for | | - // | task | target enter | * | - // | | data | | - // | task | target exit | * | - // | | data | | - // | task | teams | + | - // | task | cancellation | | - // | | point | ! | - // | task | cancel | ! | - // | task | taskloop | * | - // | task | taskloop simd | * | - // | task | distribute | + | - // | task | distribute | + | - // | | parallel for | | - // | task | distribute | + | - // | |parallel for simd| | - // | task | distribute simd | + | - // | task | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | ordered | parallel | * | - // | ordered | for | + | - // | ordered | for simd | + | - // | ordered | master | * | - // | ordered | critical | * | - // | ordered | simd | * | - // | ordered | sections | + | - // | ordered | section | + | - // | ordered | single | + | - // | ordered | parallel for | * | - // | ordered |parallel for simd| * | - // | ordered |parallel sections| * | - // | ordered | task | * | - // | ordered | taskyield | * | - // | ordered | barrier | + | - // | ordered | taskwait | * | - // | ordered | taskgroup | * | - // | ordered | flush | * | - // | ordered | ordered | + | - // | ordered | atomic | * | - // | ordered | target | * | - // | ordered | target parallel | * | - // | ordered | target parallel | * | - // | | for | | - // | ordered | target enter | * | - // | | data | | - // | ordered | target exit | * | - // | | data | | - // | ordered | teams | + | - // | ordered | cancellation | | - // | | point | | - // | ordered | cancel | | - // | ordered | taskloop | * | - // | ordered | taskloop simd | * | - // | ordered | distribute | + | - // | ordered | distribute | + | - // | | parallel for | | - // | ordered | distribute | + | - // | |parallel for simd| | - // | ordered | distribute simd | + | - // | ordered | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | atomic | parallel | | - // | atomic | for | | - // | atomic | for simd | | - // | atomic | master | | - // | atomic | critical | | - // | atomic | simd | | - // | atomic | sections | | - // | atomic | section | | - // | atomic | single | | - // | atomic | parallel for | | - // | atomic |parallel for simd| | - // | atomic |parallel sections| | - // | atomic | task | | - // | atomic | taskyield | | - // | atomic | barrier | | - // | atomic | taskwait | | - // | atomic | taskgroup | | - // | atomic | flush | | - // | atomic | ordered | | - // | atomic | atomic | | - // | atomic | target | | - // | atomic | target parallel | | - // | atomic | target parallel | | - // | | for | | - // | atomic | target enter | | - // | | data | | - // | atomic | target exit | | - // | | data | | - // | atomic | teams | | - // | atomic | cancellation | | - // | | point | | - // | atomic | cancel | | - // | atomic | taskloop | | - // | atomic | taskloop simd | | - // | atomic | distribute | | - // | atomic | distribute | | - // | | parallel for | | - // | atomic | distribute | | - // | |parallel for simd| | - // | atomic | distribute simd | | - // | atomic | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | target | parallel | * | - // | target | for | * | - // | target | for simd | * | - // | target | master | * | - // | target | critical | * | - // | target | simd | * | - // | target | sections | * | - // | target | section | * | - // | target | single | * | - // | target | parallel for | * | - // | target |parallel for simd| * | - // | target |parallel sections| * | - // | target | task | * | - // | target | taskyield | * | - // | target | barrier | * | - // | target | taskwait | * | - // | target | taskgroup | * | - // | target | flush | * | - // | target | ordered | * | - // | target | atomic | * | - // | target | target | | - // | target | target parallel | | - // | target | target parallel | | - // | | for | | - // | target | target enter | | - // | | data | | - // | target | target exit | | - // | | data | | - // | target | teams | * | - // | target | cancellation | | - // | | point | | - // | target | cancel | | - // | target | taskloop | * | - // | target | taskloop simd | * | - // | target | distribute | + | - // | target | distribute | + | - // | | parallel for | | - // | target | distribute | + | - // | |parallel for simd| | - // | target | distribute simd | + | - // | target | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | target parallel | parallel | * | - // | target parallel | for | * | - // | target parallel | for simd | * | - // | target parallel | master | * | - // | target parallel | critical | * | - // | target parallel | simd | * | - // | target parallel | sections | * | - // | target parallel | section | * | - // | target parallel | single | * | - // | target parallel | parallel for | * | - // | target parallel |parallel for simd| * | - // | target parallel |parallel sections| * | - // | target parallel | task | * | - // | target parallel | taskyield | * | - // | target parallel | barrier | * | - // | target parallel | taskwait | * | - // | target parallel | taskgroup | * | - // | target parallel | flush | * | - // | target parallel | ordered | * | - // | target parallel | atomic | * | - // | target parallel | target | | - // | target parallel | target parallel | | - // | target parallel | target parallel | | - // | | for | | - // | target parallel | target enter | | - // | | data | | - // | target parallel | target exit | | - // | | data | | - // | target parallel | teams | | - // | target parallel | cancellation | | - // | | point | ! | - // | target parallel | cancel | ! | - // | target parallel | taskloop | * | - // | target parallel | taskloop simd | * | - // | target parallel | distribute | | - // | target parallel | distribute | | - // | | parallel for | | - // | target parallel | distribute | | - // | |parallel for simd| | - // | target parallel | distribute simd | | - // | target parallel | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | target parallel | parallel | * | - // | for | | | - // | target parallel | for | * | - // | for | | | - // | target parallel | for simd | * | - // | for | | | - // | target parallel | master | * | - // | for | | | - // | target parallel | critical | * | - // | for | | | - // | target parallel | simd | * | - // | for | | | - // | target parallel | sections | * | - // | for | | | - // | target parallel | section | * | - // | for | | | - // | target parallel | single | * | - // | for | | | - // | target parallel | parallel for | * | - // | for | | | - // | target parallel |parallel for simd| * | - // | for | | | - // | target parallel |parallel sections| * | - // | for | | | - // | target parallel | task | * | - // | for | | | - // | target parallel | taskyield | * | - // | for | | | - // | target parallel | barrier | * | - // | for | | | - // | target parallel | taskwait | * | - // | for | | | - // | target parallel | taskgroup | * | - // | for | | | - // | target parallel | flush | * | - // | for | | | - // | target parallel | ordered | * | - // | for | | | - // | target parallel | atomic | * | - // | for | | | - // | target parallel | target | | - // | for | | | - // | target parallel | target parallel | | - // | for | | | - // | target parallel | target parallel | | - // | for | for | | - // | target parallel | target enter | | - // | for | data | | - // | target parallel | target exit | | - // | for | data | | - // | target parallel | teams | | - // | for | | | - // | target parallel | cancellation | | - // | for | point | ! | - // | target parallel | cancel | ! | - // | for | | | - // | target parallel | taskloop | * | - // | for | | | - // | target parallel | taskloop simd | * | - // | for | | | - // | target parallel | distribute | | - // | for | | | - // | target parallel | distribute | | - // | for | parallel for | | - // | target parallel | distribute | | - // | for |parallel for simd| | - // | target parallel | distribute simd | | - // | for | | | - // | target parallel | target parallel | | - // | for | for simd | | - // +------------------+-----------------+------------------------------------+ - // | teams | parallel | * | - // | teams | for | + | - // | teams | for simd | + | - // | teams | master | + | - // | teams | critical | + | - // | teams | simd | + | - // | teams | sections | + | - // | teams | section | + | - // | teams | single | + | - // | teams | parallel for | * | - // | teams |parallel for simd| * | - // | teams |parallel sections| * | - // | teams | task | + | - // | teams | taskyield | + | - // | teams | barrier | + | - // | teams | taskwait | + | - // | teams | taskgroup | + | - // | teams | flush | + | - // | teams | ordered | + | - // | teams | atomic | + | - // | teams | target | + | - // | teams | target parallel | + | - // | teams | target parallel | + | - // | | for | | - // | teams | target enter | + | - // | | data | | - // | teams | target exit | + | - // | | data | | - // | teams | teams | + | - // | teams | cancellation | | - // | | point | | - // | teams | cancel | | - // | teams | taskloop | + | - // | teams | taskloop simd | + | - // | teams | distribute | ! | - // | teams | distribute | ! | - // | | parallel for | | - // | teams | distribute | ! | - // | |parallel for simd| | - // | teams | distribute simd | ! | - // | teams | target parallel | + | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | taskloop | parallel | * | - // | taskloop | for | + | - // | taskloop | for simd | + | - // | taskloop | master | + | - // | taskloop | critical | * | - // | taskloop | simd | * | - // | taskloop | sections | + | - // | taskloop | section | + | - // | taskloop | single | + | - // | taskloop | parallel for | * | - // | taskloop |parallel for simd| * | - // | taskloop |parallel sections| * | - // | taskloop | task | * | - // | taskloop | taskyield | * | - // | taskloop | barrier | + | - // | taskloop | taskwait | * | - // | taskloop | taskgroup | * | - // | taskloop | flush | * | - // | taskloop | ordered | + | - // | taskloop | atomic | * | - // | taskloop | target | * | - // | taskloop | target parallel | * | - // | taskloop | target parallel | * | - // | | for | | - // | taskloop | target enter | * | - // | | data | | - // | taskloop | target exit | * | - // | | data | | - // | taskloop | teams | + | - // | taskloop | cancellation | | - // | | point | | - // | taskloop | cancel | | - // | taskloop | taskloop | * | - // | taskloop | distribute | + | - // | taskloop | distribute | + | - // | | parallel for | | - // | taskloop | distribute | + | - // | |parallel for simd| | - // | taskloop | distribute simd | + | - // | taskloop | target parallel | * | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | taskloop simd | parallel | | - // | taskloop simd | for | | - // | taskloop simd | for simd | | - // | taskloop simd | master | | - // | taskloop simd | critical | | - // | taskloop simd | simd | * | - // | taskloop simd | sections | | - // | taskloop simd | section | | - // | taskloop simd | single | | - // | taskloop simd | parallel for | | - // | taskloop simd |parallel for simd| | - // | taskloop simd |parallel sections| | - // | taskloop simd | task | | - // | taskloop simd | taskyield | | - // | taskloop simd | barrier | | - // | taskloop simd | taskwait | | - // | taskloop simd | taskgroup | | - // | taskloop simd | flush | | - // | taskloop simd | ordered | + (with simd clause) | - // | taskloop simd | atomic | | - // | taskloop simd | target | | - // | taskloop simd | target parallel | | - // | taskloop simd | target parallel | | - // | | for | | - // | taskloop simd | target enter | | - // | | data | | - // | taskloop simd | target exit | | - // | | data | | - // | taskloop simd | teams | | - // | taskloop simd | cancellation | | - // | | point | | - // | taskloop simd | cancel | | - // | taskloop simd | taskloop | | - // | taskloop simd | taskloop simd | | - // | taskloop simd | distribute | | - // | taskloop simd | distribute | | - // | | parallel for | | - // | taskloop simd | distribute | | - // | |parallel for simd| | - // | taskloop simd | distribute simd | | - // | taskloop simd | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | distribute | parallel | * | - // | distribute | for | * | - // | distribute | for simd | * | - // | distribute | master | * | - // | distribute | critical | * | - // | distribute | simd | * | - // | distribute | sections | * | - // | distribute | section | * | - // | distribute | single | * | - // | distribute | parallel for | * | - // | distribute |parallel for simd| * | - // | distribute |parallel sections| * | - // | distribute | task | * | - // | distribute | taskyield | * | - // | distribute | barrier | * | - // | distribute | taskwait | * | - // | distribute | taskgroup | * | - // | distribute | flush | * | - // | distribute | ordered | + | - // | distribute | atomic | * | - // | distribute | target | | - // | distribute | target parallel | | - // | distribute | target parallel | | - // | | for | | - // | distribute | target enter | | - // | | data | | - // | distribute | target exit | | - // | | data | | - // | distribute | teams | | - // | distribute | cancellation | + | - // | | point | | - // | distribute | cancel | + | - // | distribute | taskloop | * | - // | distribute | taskloop simd | * | - // | distribute | distribute | | - // | distribute | distribute | | - // | | parallel for | | - // | distribute | distribute | | - // | |parallel for simd| | - // | distribute | distribute simd | | - // | distribute | target parallel | | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | distribute | parallel | * | - // | parallel for | | | - // | distribute | for | * | - // | parallel for | | | - // | distribute | for simd | * | - // | parallel for | | | - // | distribute | master | * | - // | parallel for | | | - // | distribute | critical | * | - // | parallel for | | | - // | distribute | simd | * | - // | parallel for | | | - // | distribute | sections | * | - // | parallel for | | | - // | distribute | section | * | - // | parallel for | | | - // | distribute | single | * | - // | parallel for | | | - // | distribute | parallel for | * | - // | parallel for | | | - // | distribute |parallel for simd| * | - // | parallel for | | | - // | distribute |parallel sections| * | - // | parallel for | | | - // | distribute | task | * | - // | parallel for | | | - // | parallel for | | | - // | distribute | taskyield | * | - // | parallel for | | | - // | distribute | barrier | * | - // | parallel for | | | - // | distribute | taskwait | * | - // | parallel for | | | - // | distribute | taskgroup | * | - // | parallel for | | | - // | distribute | flush | * | - // | parallel for | | | - // | distribute | ordered | + | - // | parallel for | | | - // | distribute | atomic | * | - // | parallel for | | | - // | distribute | target | | - // | parallel for | | | - // | distribute | target parallel | | - // | parallel for | | | - // | distribute | target parallel | | - // | parallel for | for | | - // | distribute | target enter | | - // | parallel for | data | | - // | distribute | target exit | | - // | parallel for | data | | - // | distribute | teams | | - // | parallel for | | | - // | distribute | cancellation | + | - // | parallel for | point | | - // | distribute | cancel | + | - // | parallel for | | | - // | distribute | taskloop | * | - // | parallel for | | | - // | distribute | taskloop simd | * | - // | parallel for | | | - // | distribute | distribute | | - // | parallel for | | | - // | distribute | distribute | | - // | parallel for | parallel for | | - // | distribute | distribute | | - // | parallel for |parallel for simd| | - // | distribute | distribute simd | | - // | parallel for | | | - // | distribute | target parallel | | - // | parallel for | for simd | | - // +------------------+-----------------+------------------------------------+ - // | distribute | parallel | * | - // | parallel for simd| | | - // | distribute | for | * | - // | parallel for simd| | | - // | distribute | for simd | * | - // | parallel for simd| | | - // | distribute | master | * | - // | parallel for simd| | | - // | distribute | critical | * | - // | parallel for simd| | | - // | distribute | simd | * | - // | parallel for simd| | | - // | distribute | sections | * | - // | parallel for simd| | | - // | distribute | section | * | - // | parallel for simd| | | - // | distribute | single | * | - // | parallel for simd| | | - // | distribute | parallel for | * | - // | parallel for simd| | | - // | distribute |parallel for simd| * | - // | parallel for simd| | | - // | distribute |parallel sections| * | - // | parallel for simd| | | - // | distribute | task | * | - // | parallel for simd| | | - // | distribute | taskyield | * | - // | parallel for simd| | | - // | distribute | barrier | * | - // | parallel for simd| | | - // | distribute | taskwait | * | - // | parallel for simd| | | - // | distribute | taskgroup | * | - // | parallel for simd| | | - // | distribute | flush | * | - // | parallel for simd| | | - // | distribute | ordered | + | - // | parallel for simd| | | - // | distribute | atomic | * | - // | parallel for simd| | | - // | distribute | target | | - // | parallel for simd| | | - // | distribute | target parallel | | - // | parallel for simd| | | - // | distribute | target parallel | | - // | parallel for simd| for | | - // | distribute | target enter | | - // | parallel for simd| data | | - // | distribute | target exit | | - // | parallel for simd| data | | - // | distribute | teams | | - // | parallel for simd| | | - // | distribute | cancellation | + | - // | parallel for simd| point | | - // | distribute | cancel | + | - // | parallel for simd| | | - // | distribute | taskloop | * | - // | parallel for simd| | | - // | distribute | taskloop simd | * | - // | parallel for simd| | | - // | distribute | distribute | | - // | parallel for simd| | | - // | distribute | distribute | * | - // | parallel for simd| parallel for | | - // | distribute | distribute | * | - // | parallel for simd|parallel for simd| | - // | distribute | distribute simd | * | - // | parallel for simd| | | - // | distribute | target parallel | | - // | parallel for simd| for simd | | - // +------------------+-----------------+------------------------------------+ - // | distribute simd | parallel | * | - // | distribute simd | for | * | - // | distribute simd | for simd | * | - // | distribute simd | master | * | - // | distribute simd | critical | * | - // | distribute simd | simd | * | - // | distribute simd | sections | * | - // | distribute simd | section | * | - // | distribute simd | single | * | - // | distribute simd | parallel for | * | - // | distribute simd |parallel for simd| * | - // | distribute simd |parallel sections| * | - // | distribute simd | task | * | - // | distribute simd | taskyield | * | - // | distribute simd | barrier | * | - // | distribute simd | taskwait | * | - // | distribute simd | taskgroup | * | - // | distribute simd | flush | * | - // | distribute simd | ordered | + | - // | distribute simd | atomic | * | - // | distribute simd | target | * | - // | distribute simd | target parallel | * | - // | distribute simd | target parallel | * | - // | | for | | - // | distribute simd | target enter | * | - // | | data | | - // | distribute simd | target exit | * | - // | | data | | - // | distribute simd | teams | * | - // | distribute simd | cancellation | + | - // | | point | | - // | distribute simd | cancel | + | - // | distribute simd | taskloop | * | - // | distribute simd | taskloop simd | * | - // | distribute simd | distribute | | - // | distribute simd | distribute | * | - // | | parallel for | | - // | distribute simd | distribute | * | - // | |parallel for simd| | - // | distribute simd | distribute simd | * | - // | distribute simd | target parallel | * | - // | | for simd | | - // +------------------+-----------------+------------------------------------+ - // | target parallel | parallel | * | - // | for simd | | | - // | target parallel | for | * | - // | for simd | | | - // | target parallel | for simd | * | - // | for simd | | | - // | target parallel | master | * | - // | for simd | | | - // | target parallel | critical | * | - // | for simd | | | - // | target parallel | simd | ! | - // | for simd | | | - // | target parallel | sections | * | - // | for simd | | | - // | target parallel | section | * | - // | for simd | | | - // | target parallel | single | * | - // | for simd | | | - // | target parallel | parallel for | * | - // | for simd | | | - // | target parallel |parallel for simd| * | - // | for simd | | | - // | target parallel |parallel sections| * | - // | for simd | | | - // | target parallel | task | * | - // | for simd | | | - // | target parallel | taskyield | * | - // | for simd | | | - // | target parallel | barrier | * | - // | for simd | | | - // | target parallel | taskwait | * | - // | for simd | | | - // | target parallel | taskgroup | * | - // | for simd | | | - // | target parallel | flush | * | - // | for simd | | | - // | target parallel | ordered | + (with simd clause) | - // | for simd | | | - // | target parallel | atomic | * | - // | for simd | | | - // | target parallel | target | * | - // | for simd | | | - // | target parallel | target parallel | * | - // | for simd | | | - // | target parallel | target parallel | * | - // | for simd | for | | - // | target parallel | target enter | * | - // | for simd | data | | - // | target parallel | target exit | * | - // | for simd | data | | - // | target parallel | teams | * | - // | for simd | | | - // | target parallel | cancellation | * | - // | for simd | point | | - // | target parallel | cancel | * | - // | for simd | | | - // | target parallel | taskloop | * | - // | for simd | | | - // | target parallel | taskloop simd | * | - // | for simd | | | - // | target parallel | distribute | * | - // | for simd | | | - // | target parallel | distribute | * | - // | for simd | parallel for | | - // | target parallel | distribute | * | - // | for simd |parallel for simd| | - // | target parallel | distribute simd | * | - // | for simd | | | - // | target parallel | target parallel | * | - // | for simd | for simd | | - // +------------------+-----------------+------------------------------------+ if (Stack->getCurScope()) { auto ParentRegion = Stack->getParentDirective(); auto OffendingRegion = ParentRegion; bool NestingProhibited = false; bool CloseNesting = true; + bool OrphanSeen = false; enum { NoRecommend, ShouldBeInParallelRegion, @@ -3116,7 +1903,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP [2.8.1,simd Construct, Restrictions] // An ordered construct with the simd clause is the only OpenMP // construct that can appear in the simd region. - // Allowing a SIMD consruct nested in another SIMD construct is an + // Allowing a SIMD construct nested in another SIMD construct is an // extension. The OpenMP 4.5 spec does not allow it. Issue a warning // message. SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd) @@ -3144,9 +1931,11 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, } return false; } - // Allow some constructs to be orphaned (they could be used in functions, - // called from OpenMP regions with the required preconditions). - if (ParentRegion == OMPD_unknown) + // Allow some constructs (except teams) to be orphaned (they could be + // used in functions, called from OpenMP regions with the required + // preconditions). + if (ParentRegion == OMPD_unknown && + !isOpenMPNestingTeamsDirective(CurrentRegion)) return false; if (CurrentRegion == OMPD_cancellation_point || CurrentRegion == OMPD_cancel) { @@ -3184,20 +1973,17 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // critical region with the same name. Note that this restriction is not // sufficient to prevent deadlock. SourceLocation PreviousCriticalLoc; - bool DeadLock = - Stack->hasDirective([CurrentName, &PreviousCriticalLoc]( - OpenMPDirectiveKind K, - const DeclarationNameInfo &DNI, - SourceLocation Loc) - ->bool { - if (K == OMPD_critical && - DNI.getName() == CurrentName.getName()) { - PreviousCriticalLoc = Loc; - return true; - } else - return false; - }, - false /* skip top directive */); + bool DeadLock = Stack->hasDirective( + [CurrentName, &PreviousCriticalLoc](OpenMPDirectiveKind K, + const DeclarationNameInfo &DNI, + SourceLocation Loc) -> bool { + if (K == OMPD_critical && DNI.getName() == CurrentName.getName()) { + PreviousCriticalLoc = Loc; + return true; + } else + return false; + }, + false /* skip top directive */); if (DeadLock) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_critical_same_name) @@ -3217,7 +2003,8 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && - !isOpenMPParallelDirective(CurrentRegion)) { + !isOpenMPParallelDirective(CurrentRegion) && + !isOpenMPTeamsDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // A worksharing region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. @@ -3241,15 +2028,19 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, !(isOpenMPSimdDirective(ParentRegion) || Stack->isParentOrderedRegion()); Recommend = ShouldBeInOrderedRegion; - } else if (isOpenMPTeamsDirective(CurrentRegion)) { + } else if (isOpenMPNestingTeamsDirective(CurrentRegion)) { // OpenMP [2.16, Nesting of Regions] // If specified, a teams construct must be contained within a target // construct. NestingProhibited = ParentRegion != OMPD_target; + OrphanSeen = ParentRegion == OMPD_unknown; Recommend = ShouldBeInTargetRegion; Stack->setParentTeamsRegionLoc(Stack->getConstructLoc()); } - if (!NestingProhibited && isOpenMPTeamsDirective(ParentRegion)) { + if (!NestingProhibited && + !isOpenMPTargetExecutionDirective(CurrentRegion) && + !isOpenMPTargetDataManagementDirective(CurrentRegion) && + (ParentRegion == OMPD_teams || ParentRegion == OMPD_target_teams)) { // OpenMP [2.16, Nesting of Regions] // distribute, parallel, parallel sections, parallel workshare, and the // parallel loop and parallel loop SIMD constructs are the only OpenMP @@ -3258,11 +2049,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, !isOpenMPDistributeDirective(CurrentRegion); Recommend = ShouldBeInParallelRegion; } - if (!NestingProhibited && isOpenMPDistributeDirective(CurrentRegion)) { + if (!NestingProhibited && + isOpenMPNestingDistributeDirective(CurrentRegion)) { // OpenMP 4.5 [2.17 Nesting of Regions] // The region associated with the distribute construct must be strictly // nested inside a teams region - NestingProhibited = !isOpenMPTeamsDirective(ParentRegion); + NestingProhibited = + (ParentRegion != OMPD_teams && ParentRegion != OMPD_target_teams); Recommend = ShouldBeInTeamsRegion; } if (!NestingProhibited && @@ -3285,9 +2078,14 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, CloseNesting = false; } if (NestingProhibited) { - SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) - << CloseNesting << getOpenMPDirectiveName(OffendingRegion) - << Recommend << getOpenMPDirectiveName(CurrentRegion); + if (OrphanSeen) { + SemaRef.Diag(StartLoc, diag::err_omp_orphaned_device_directive) + << getOpenMPDirectiveName(CurrentRegion) << Recommend; + } else { + SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) + << CloseNesting << getOpenMPDirectiveName(OffendingRegion) + << Recommend << getOpenMPDirectiveName(CurrentRegion); + } return true; } } @@ -3602,6 +2400,45 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( AllowedNameModifiers.push_back(OMPD_target); AllowedNameModifiers.push_back(OMPD_parallel); break; + case OMPD_target_simd: + Res = ActOnOpenMPTargetSimdDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + break; + case OMPD_teams_distribute: + Res = ActOnOpenMPTeamsDistributeDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + break; + case OMPD_teams_distribute_simd: + Res = ActOnOpenMPTeamsDistributeSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + break; + case OMPD_teams_distribute_parallel_for_simd: + Res = ActOnOpenMPTeamsDistributeParallelForSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_teams_distribute_parallel_for: + Res = ActOnOpenMPTeamsDistributeParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_target_teams: + Res = ActOnOpenMPTargetTeamsDirective(ClausesWithImplicit, AStmt, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target); + break; + case OMPD_target_teams_distribute: + Res = ActOnOpenMPTargetTeamsDistributeDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + break; + case OMPD_target_teams_distribute_parallel_for: + Res = ActOnOpenMPTargetTeamsDistributeParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; case OMPD_declare_target: case OMPD_end_declare_target: case OMPD_threadprivate: @@ -3969,7 +2806,7 @@ public: /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; - /// \brief Build initization of the counter be used for codegen. + /// \brief Build initialization of the counter be used for codegen. Expr *BuildCounterInit() const; /// \brief Build step of the counter be used for codegen. Expr *BuildCounterStep() const; @@ -4094,8 +2931,9 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { return true; } if (TestIsLessOp == Subtract) { - NewStep = SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, - NewStep).get(); + NewStep = + SemaRef.CreateBuiltinUnaryOp(NewStep->getExprLoc(), UO_Minus, NewStep) + .get(); Subtract = !Subtract; } } @@ -4127,7 +2965,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { InitSrcRange = S->getSourceRange(); if (Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParens(); - if (auto BO = dyn_cast<BinaryOperator>(S)) { + if (auto *BO = dyn_cast<BinaryOperator>(S)) { if (BO->getOpcode() == BO_Assign) { auto *LHS = BO->getLHS()->IgnoreParens(); if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { @@ -4142,9 +2980,9 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); } } - } else if (auto DS = dyn_cast<DeclStmt>(S)) { + } else if (auto *DS = dyn_cast<DeclStmt>(S)) { if (DS->isSingleDecl()) { - if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { + if (auto *Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { if (Var->hasInit() && !Var->getType()->isReferenceType()) { // Accept non-canonical init form here but emit ext. warning. if (Var->getInitStyle() != VarDecl::CInit && EmitDiags) @@ -4155,10 +2993,10 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { } } } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { + } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { if (CE->getOperator() == OO_Equal) { auto *LHS = CE->getArg(0); - if (auto DRE = dyn_cast<DeclRefExpr>(LHS)) { + if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) { if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); @@ -4220,7 +3058,7 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { } S = getExprAsWritten(S); SourceLocation CondLoc = S->getLocStart(); - if (auto BO = dyn_cast<BinaryOperator>(S)) { + if (auto *BO = dyn_cast<BinaryOperator>(S)) { if (BO->isRelationalOp()) { if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetUB(BO->getRHS(), @@ -4233,7 +3071,7 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { + } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { if (CE->getNumArgs() == 2) { auto Op = CE->getOperator(); switch (Op) { @@ -4269,7 +3107,7 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { // var - incr // RHS = RHS->IgnoreParenImpCasts(); - if (auto BO = dyn_cast<BinaryOperator>(RHS)) { + if (auto *BO = dyn_cast<BinaryOperator>(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; if (GetInitLCDecl(BO->getLHS()) == LCDecl) @@ -4277,7 +3115,7 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl) return SetStep(BO->getLHS(), false); } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { + } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { if (GetInitLCDecl(CE->getArg(0)) == LCDecl) @@ -4317,14 +3155,15 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); - if (auto UO = dyn_cast<UnaryOperator>(S)) { + if (auto *UO = dyn_cast<UnaryOperator>(S)) { if (UO->isIncrementDecrementOp() && GetInitLCDecl(UO->getSubExpr()) == LCDecl) - return SetStep( - SemaRef.ActOnIntegerConstant(UO->getLocStart(), - (UO->isDecrementOp() ? -1 : 1)).get(), - false); - } else if (auto BO = dyn_cast<BinaryOperator>(S)) { + return SetStep(SemaRef + .ActOnIntegerConstant(UO->getLocStart(), + (UO->isDecrementOp() ? -1 : 1)) + .get(), + false); + } else if (auto *BO = dyn_cast<BinaryOperator>(S)) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: @@ -4338,16 +3177,17 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { default: break; } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) { + } else if (auto *CE = dyn_cast<CXXOperatorCallExpr>(S)) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: if (GetInitLCDecl(CE->getArg(0)) == LCDecl) - return SetStep( - SemaRef.ActOnIntegerConstant( - CE->getLocStart(), - ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)).get(), - false); + return SetStep(SemaRef + .ActOnIntegerConstant( + CE->getLocStart(), + ((CE->getOperator() == OO_MinusMinus) ? -1 : 1)) + .get(), + false); break; case OO_PlusEqual: case OO_MinusEqual: @@ -4544,7 +3384,7 @@ Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { return nullptr; } -/// \brief Build initization of the counter be used for codegen. +/// \brief Build initialization of the counter to be used for codegen. Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } /// \brief Build step of the counter be used for codegen. @@ -4615,7 +3455,7 @@ static bool CheckOpenMPIterationSpace( llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { // OpenMP [2.6, Canonical Loop Form] // for (init-expr; test-expr; incr-expr) structured-block - auto For = dyn_cast_or_null<ForStmt>(S); + auto *For = dyn_cast_or_null<ForStmt>(S); if (!For) { SemaRef.Diag(S->getLocStart(), diag::err_omp_not_for) << (CollapseLoopCountExpr != nullptr || OrderedLoopCountExpr != nullptr) @@ -4855,8 +3695,7 @@ BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, /// \brief Convert integer expression \a E to make it have at least \a Bits /// bits. -static ExprResult WidenIterationCount(unsigned Bits, Expr *E, - Sema &SemaRef) { +static ExprResult WidenIterationCount(unsigned Bits, Expr *E, Sema &SemaRef) { if (E == nullptr) return ExprError(); auto &C = SemaRef.Context; @@ -5014,15 +3853,17 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, auto PreCond = ExprResult(IterSpaces[0].PreCond); auto N0 = IterSpaces[0].NumIterations; ExprResult LastIteration32 = WidenIterationCount( - 32 /* Bits */, SemaRef.PerformImplicitConversion( - N0->IgnoreImpCasts(), N0->getType(), - Sema::AA_Converting, /*AllowExplicit=*/true) + 32 /* Bits */, SemaRef + .PerformImplicitConversion( + N0->IgnoreImpCasts(), N0->getType(), + Sema::AA_Converting, /*AllowExplicit=*/true) .get(), SemaRef); ExprResult LastIteration64 = WidenIterationCount( - 64 /* Bits */, SemaRef.PerformImplicitConversion( - N0->IgnoreImpCasts(), N0->getType(), - Sema::AA_Converting, /*AllowExplicit=*/true) + 64 /* Bits */, SemaRef + .PerformImplicitConversion( + N0->IgnoreImpCasts(), N0->getType(), + Sema::AA_Converting, /*AllowExplicit=*/true) .get(), SemaRef); @@ -5035,24 +3876,28 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Scope *CurScope = DSA.getCurScope(); for (unsigned Cnt = 1; Cnt < NestedLoopCount; ++Cnt) { if (PreCond.isUsable()) { - PreCond = SemaRef.BuildBinOp(CurScope, SourceLocation(), BO_LAnd, - PreCond.get(), IterSpaces[Cnt].PreCond); + PreCond = + SemaRef.BuildBinOp(CurScope, PreCond.get()->getExprLoc(), BO_LAnd, + PreCond.get(), IterSpaces[Cnt].PreCond); } auto N = IterSpaces[Cnt].NumIterations; + SourceLocation Loc = N->getExprLoc(); AllCountsNeedLessThan32Bits &= C.getTypeSize(N->getType()) < 32; if (LastIteration32.isUsable()) LastIteration32 = SemaRef.BuildBinOp( - CurScope, SourceLocation(), BO_Mul, LastIteration32.get(), - SemaRef.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) + CurScope, Loc, BO_Mul, LastIteration32.get(), + SemaRef + .PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true) .get()); if (LastIteration64.isUsable()) LastIteration64 = SemaRef.BuildBinOp( - CurScope, SourceLocation(), BO_Mul, LastIteration64.get(), - SemaRef.PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) + CurScope, Loc, BO_Mul, LastIteration64.get(), + SemaRef + .PerformImplicitConversion(N->IgnoreImpCasts(), N->getType(), + Sema::AA_Converting, + /*AllowExplicit=*/true) .get()); } @@ -5083,7 +3928,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, ExprResult NumIterations = LastIteration; { LastIteration = SemaRef.BuildBinOp( - CurScope, SourceLocation(), BO_Sub, LastIteration.get(), + CurScope, LastIteration.get()->getExprLoc(), BO_Sub, + LastIteration.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!LastIteration.isUsable()) return 0; @@ -5102,7 +3948,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Prepare SaveRef + 1. NumIterations = SemaRef.BuildBinOp( - CurScope, SourceLocation(), BO_Add, SaveRef.get(), + CurScope, SaveRef.get()->getExprLoc(), BO_Add, SaveRef.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!NumIterations.isUsable()) return 0; @@ -5110,7 +3956,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); - // Build variables passed into runtime, nesessary for worksharing directives. + // Build variables passed into runtime, necessary for worksharing directives. ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { @@ -5146,7 +3992,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Build expression: UB = min(UB, LastIteration) - // It is nesessary for CodeGen of directives with static scheduling. + // It is necessary for CodeGen of directives with static scheduling. ExprResult IsUBGreater = SemaRef.BuildBinOp(CurScope, InitLoc, BO_GT, UB.get(), LastIteration.get()); ExprResult CondOp = SemaRef.ActOnConditionalOp( @@ -5187,11 +4033,11 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, { VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); - Expr *RHS = (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || - isOpenMPDistributeDirective(DKind)) - ? LB.get() - : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); + Expr *RHS = + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) + ? LB.get() + : SemaRef.ActOnIntegerConstant(SourceLocation(), 0).get(); Init = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, IV.get(), RHS); Init = SemaRef.ActOnFinishFullExpr(Init.get()); } @@ -5394,9 +4240,10 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } assert(I->second == OO_Plus || I->second == OO_Minus); BinaryOperatorKind BOK = (I->second == OO_Plus) ? BO_Add : BO_Sub; - UpCounterVal = - SemaRef.BuildBinOp(CurScope, I->first->getExprLoc(), BOK, - UpCounterVal, NormalizedOffset).get(); + UpCounterVal = SemaRef + .BuildBinOp(CurScope, I->first->getExprLoc(), BOK, + UpCounterVal, NormalizedOffset) + .get(); } Multiplier = *ILM; ++I; @@ -5491,7 +4338,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -5530,7 +4377,7 @@ StmtResult Sema::ActOnOpenMPForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -5567,7 +4414,7 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -5592,9 +4439,9 @@ StmtResult Sema::ActOnOpenMPSectionsDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; - while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) + while (auto *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) BaseStmt = CS->getCapturedStmt(); - if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { + if (auto *C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { auto S = C->children(); if (S.begin() == S.end()) return StmtError(); @@ -5769,7 +4616,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -5811,7 +4658,7 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -5836,9 +4683,9 @@ Sema::ActOnOpenMPParallelSectionsDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); auto BaseStmt = AStmt; - while (CapturedStmt *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) + while (auto *CS = dyn_cast_or_null<CapturedStmt>(BaseStmt)) BaseStmt = CS->getCapturedStmt(); - if (auto C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { + if (auto *C = dyn_cast_or_null<CompoundStmt>(BaseStmt)) { auto S = C->children(); if (S.begin() == S.end()) return StmtError(); @@ -5872,7 +4719,7 @@ StmtResult Sema::ActOnOpenMPTaskDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - CapturedStmt *CS = cast<CapturedStmt>(AStmt); + auto *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. @@ -6169,21 +5016,21 @@ bool OpenMPAtomicUpdateChecker::checkStatement(Stmt *S, unsigned DiagId, AtomicCompAssignOp->getOpcode()); OpLoc = AtomicCompAssignOp->getOperatorLoc(); E = AtomicCompAssignOp->getRHS(); - X = AtomicCompAssignOp->getLHS(); + X = AtomicCompAssignOp->getLHS()->IgnoreParens(); IsXLHSInRHSPart = true; } else if (auto *AtomicBinOp = dyn_cast<BinaryOperator>( AtomicBody->IgnoreParenImpCasts())) { // Check for Binary Operation - if(checkBinaryOperation(AtomicBinOp, DiagId, NoteId)) + if (checkBinaryOperation(AtomicBinOp, DiagId, NoteId)) return true; - } else if (auto *AtomicUnaryOp = - dyn_cast<UnaryOperator>(AtomicBody->IgnoreParenImpCasts())) { + } else if (auto *AtomicUnaryOp = dyn_cast<UnaryOperator>( + AtomicBody->IgnoreParenImpCasts())) { // Check for Unary Operation if (AtomicUnaryOp->isIncrementDecrementOp()) { IsPostfixUpdate = AtomicUnaryOp->isPostfix(); Op = AtomicUnaryOp->isIncrementOp() ? BO_Add : BO_Sub; OpLoc = AtomicUnaryOp->getOperatorLoc(); - X = AtomicUnaryOp->getSubExpr(); + X = AtomicUnaryOp->getSubExpr()->IgnoreParens(); E = SemaRef.ActOnIntegerConstant(OpLoc, /*uint64_t Val=*/1).get(); IsXLHSInRHSPart = true; } else { @@ -6243,7 +5090,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, if (!AStmt) return StmtError(); - auto CS = cast<CapturedStmt>(AStmt); + auto *CS = cast<CapturedStmt>(AStmt); // 1.2.2 OpenMP Language Terminology // Structured block - An executable statement with a single entry at the // top and a single exit at the bottom. @@ -6311,8 +5158,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, SourceRange ErrorRange, NoteRange; // If clause is read: // v = x; - if (auto AtomicBody = dyn_cast<Expr>(Body)) { - auto AtomicBinOp = + if (auto *AtomicBody = dyn_cast<Expr>(Body)) { + auto *AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getRHS()->IgnoreParenImpCasts(); @@ -6373,8 +5220,8 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses, SourceRange ErrorRange, NoteRange; // If clause is write: // x = expr; - if (auto AtomicBody = dyn_cast<Expr>(Body)) { - auto AtomicBinOp = + if (auto *AtomicBody = dyn_cast<Expr>(Body)) { + auto *AtomicBinOp = dyn_cast<BinaryOperator>(AtomicBody->IgnoreParenImpCasts()); if (AtomicBinOp && AtomicBinOp->getOpcode() == BO_Assign) { X = AtomicBinOp->getLHS(); @@ -6692,7 +5539,7 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, if (auto *CS = dyn_cast<CompoundStmt>(S)) { auto I = CS->body_begin(); while (I != CS->body_end()) { - auto OED = dyn_cast<OMPExecutableDirective>(*I); + auto *OED = dyn_cast<OMPExecutableDirective>(*I); if (!OED || !isOpenMPTeamsDirective(OED->getDirectiveKind())) { OMPTeamsFound = false; break; @@ -6772,7 +5619,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -6810,8 +5657,8 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, // OpenMP [2.10.1, Restrictions, p. 97] // At least one map clause must appear on the directive. if (!HasMapClause(Clauses)) { - Diag(StartLoc, diag::err_omp_no_map_for_directive) << - getOpenMPDirectiveName(OMPD_target_data); + Diag(StartLoc, diag::err_omp_no_map_for_directive) + << getOpenMPDirectiveName(OMPD_target_data); return StmtError(); } @@ -7011,7 +5858,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -7192,7 +6039,7 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( if (!CurContext->isDependentContext()) { // Finalize the clauses that need pre-built expressions for CodeGen. for (auto C : Clauses) { - if (auto LC = dyn_cast<OMPLinearClause>(C)) + if (auto *LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), B.NumIterations, *this, CurScope, DSAStack)) @@ -7207,6 +6054,327 @@ StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPTargetSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will define the + // nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_target_simd, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target simd loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTargetSimdDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTeamsDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_teams_distribute, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, + *this, *DSAStack, VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp teams distribute loop exprs were not built"); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTeamsDistributeDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTeamsDistributeSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_teams_distribute_simd, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp teams distribute simd loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTeamsDistributeSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForSimdDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + auto NestedLoopCount = CheckOpenMPLoop( + OMPD_teams_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTeamsDistributeParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTeamsDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_teams_distribute_parallel_for, getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTeamsDistributeParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTargetTeamsDirective(ArrayRef<OMPClause *> Clauses, + Stmt *AStmt, + SourceLocation StartLoc, + SourceLocation EndLoc) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + getCurFunction()->setHasBranchProtectedScope(); + + return OMPTargetTeamsDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); +} + +StmtResult Sema::ActOnOpenMPTargetTeamsDistributeDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + auto NestedLoopCount = CheckOpenMPLoop( + OMPD_target_teams_distribute, + getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target teams distribute loop exprs were not built"); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTargetTeamsDistributeDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTargetTeamsDistributeParallelForDirective( + ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, + SourceLocation EndLoc, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { + if (!AStmt) + return StmtError(); + + CapturedStmt *CS = cast<CapturedStmt>(AStmt); + // 1.2.2 OpenMP Language Terminology + // Structured block - An executable statement with a single entry at the + // top and a single exit at the bottom. + // The point of exit cannot be a branch out of the structured block. + // longjmp() and throw() must not violate the entry/exit criteria. + CS->getCapturedDecl()->setNothrow(); + + OMPLoopDirective::HelperExprs B; + // In presence of clause 'collapse' with number of loops, it will + // define the nested loops number. + auto NestedLoopCount = CheckOpenMPLoop( + OMPD_target_teams_distribute_parallel_for, + getCollapseNumberExpr(Clauses), + nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target teams distribute parallel for loop exprs were not built"); + + if (!CurContext->isDependentContext()) { + // Finalize the clauses that need pre-built expressions for CodeGen. + for (auto C : Clauses) { + if (auto *LC = dyn_cast<OMPLinearClause>(C)) + if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), + B.NumIterations, *this, CurScope, + DSAStack)) + return StmtError(); + } + } + + getCurFunction()->setHasBranchProtectedScope(); + return OMPTargetTeamsDistributeParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -7683,8 +6851,8 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( Res = ActOnOpenMPDefaultmapClause( static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]), static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]), - StartLoc, LParenLoc, ArgumentLoc[Modifier], - ArgumentLoc[DefaultmapKind], EndLoc); + StartLoc, LParenLoc, ArgumentLoc[Modifier], ArgumentLoc[DefaultmapKind], + EndLoc); break; case OMPC_final: case OMPC_num_threads: @@ -8025,7 +7193,7 @@ OMPClause *Sema::ActOnOpenMPVarListClause( Res = ActOnOpenMPFlushClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_depend: - Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList, + Res = ActOnOpenMPDependClause(DepKind, DepLinMapLoc, ColonLoc, VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_map: @@ -8207,12 +7375,13 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, continue; } + auto CurrDir = DSAStack->getCurrentDirective(); // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && - isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { + isOpenMPTaskingDirective(CurrDir)) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_private) << Type - << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + << getOpenMPDirectiveName(CurrDir); bool IsDecl = !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; @@ -8225,14 +7394,22 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // 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 - if (DSAStack->getCurrentDirective() == OMPD_target) { + if (CurrDir == OMPD_target || CurrDir == OMPD_target_parallel || + CurrDir == OMPD_target_teams || + CurrDir == OMPD_target_teams_distribute || + CurrDir == OMPD_target_teams_distribute_parallel_for) { + OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( - VD, /* CurrentRegionOnly = */ true, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) - -> bool { return true; })) { - Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + VD, /*CurrentRegionOnly=*/true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind WhereFoundClauseKind) -> bool { + ConflictKind = WhereFoundClauseKind; + return true; + })) { + Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) << getOpenMPClauseName(OMPC_private) - << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + << getOpenMPClauseName(ConflictKind) + << getOpenMPDirectiveName(CurrDir); ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -8388,7 +7565,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // worksharing regions arising from the worksharing construct ever bind // to any of the parallel regions arising from the parallel construct. if (isOpenMPWorksharingDirective(CurrDir) && - !isOpenMPParallelDirective(CurrDir)) { + !isOpenMPParallelDirective(CurrDir) && + !isOpenMPTeamsDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared && (isOpenMPParallelDirective(DVar.DKind) || @@ -8476,13 +7654,21 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // 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 - if (CurrDir == OMPD_target) { + if (CurrDir == OMPD_target || CurrDir == OMPD_target_parallel || + CurrDir == OMPD_target_teams || + CurrDir == OMPD_target_teams_distribute || + CurrDir == OMPD_target_teams_distribute_parallel_for) { + OpenMPClauseKind ConflictKind; if (DSAStack->checkMappableExprComponentListsForDecl( - VD, /* CurrentRegionOnly = */ true, - [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) - -> bool { return true; })) { - Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + VD, /*CurrentRegionOnly=*/true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef, + OpenMPClauseKind WhereFoundClauseKind) -> bool { + ConflictKind = WhereFoundClauseKind; + return true; + })) { + Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) << getOpenMPClauseName(OMPC_firstprivate) + << getOpenMPClauseName(ConflictKind) << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); ReportOriginalDSA(*this, DSAStack, D, DVar); continue; @@ -8645,7 +7831,8 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // regions. DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && - !isOpenMPParallelDirective(CurrDir)) { + !isOpenMPParallelDirective(CurrDir) && + !isOpenMPTeamsDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) @@ -8884,7 +8071,7 @@ buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) { Lookups.push_back(UnresolvedSet<8>()); Decl *PrevD = nullptr; - for(auto *D : ULE->decls()) { + for (auto *D : ULE->decls()) { if (D == PrevD) Lookups.push_back(UnresolvedSet<8>()); else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) @@ -9175,7 +8362,8 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // worksharing regions arising from the worksharing construct bind. OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && - !isOpenMPParallelDirective(CurrDir)) { + !isOpenMPParallelDirective(CurrDir) && + !isOpenMPTeamsDirective(CurrDir)) { DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) @@ -9260,7 +8448,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( if (OASE || (!ASE && D->getType().getNonReferenceType()->isVariablyModifiedType())) { - // For arays/array sections only: + // For arrays/array sections only: // Create pseudo array type for private copy. The size for this array will // be generated during codegen. // For array subscripts or single variables Private Ty is the same as Type @@ -9738,7 +8926,7 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. - auto DE = cast<DeclRefExpr>(SimpleRefExpr); + auto *DE = cast<DeclRefExpr>(SimpleRefExpr); Expr *CapturedRef; if (LinKind == OMPC_LINEAR_uval) CapturedRef = cast<VarDecl>(DE->getDecl())->getInit(); @@ -10040,8 +9228,7 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, auto *DstVD = buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst", D->hasAttrs() ? &D->getAttrs() : nullptr); - auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, ELoc); + auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) @@ -10256,9 +9443,6 @@ static bool IsCXXRecordForMappable(Sema &SemaRef, SourceLocation Loc, if (!RD || RD->isInvalidDecl()) return true; - if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) - if (auto *CTD = CTSD->getSpecializedTemplate()) - RD = CTD->getTemplatedDecl(); auto QTy = SemaRef.Context.getRecordType(RD); if (RD->isDynamicClass()) { SemaRef.Diag(Loc, diag::err_omp_not_mappable_type) << QTy; @@ -10302,8 +9486,7 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, SemaRef.Diag(SL, diag::err_incomplete_type) << QTy << SR; return false; } else if (CXXRecordDecl *RD = dyn_cast_or_null<CXXRecordDecl>(ND)) { - if (!RD->isInvalidDecl() && - !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) + if (!RD->isInvalidDecl() && !IsCXXRecordForMappable(SemaRef, SL, Stack, RD)) return false; } return true; @@ -10332,7 +9515,7 @@ static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, auto *Length = OASE->getLength(); // If there is a lower bound that does not evaluates to zero, we are not - // convering the whole dimension. + // covering the whole dimension. if (LowerBound) { llvm::APSInt ConstLowerBound; if (!LowerBound->EvaluateAsInt(ConstLowerBound, SemaRef.getASTContext())) @@ -10367,8 +9550,8 @@ static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, // section or array subscript) does NOT specify a single element of the array // whose base type is \a BaseQTy. static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef, - const Expr *E, - QualType BaseQTy) { + const Expr *E, + QualType BaseQTy) { auto *OASE = dyn_cast<OMPArraySectionExpr>(E); // An array subscript always refer to a single element. Also, an array section @@ -10574,16 +9757,16 @@ static Expr *CheckMapClauseExpressionBase( bool NotUnity = CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); - if (AllowWholeSizeArraySection && AllowUnitySizeArraySection) { - // Any array section is currently allowed. + 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) || - (AllowWholeSizeArraySection && NotWhole)) { + } 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( @@ -10634,7 +9817,8 @@ static bool CheckMapConflicts( bool FoundError = DSAS->checkMappableExprComponentListsForDecl( VD, CurrentRegionOnly, [&](OMPClauseMappableExprCommon::MappableExprComponentListRef - StackComponents) -> bool { + StackComponents, + OpenMPClauseKind) -> bool { assert(!StackComponents.empty() && "Map clause expression with no components!"); @@ -10686,10 +9870,10 @@ static bool CheckMapConflicts( for (; SI != SE; ++SI) { QualType Type; if (auto *ASE = - dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) { + dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) { Type = ASE->getBase()->IgnoreParenImpCasts()->getType(); - } else if (auto *OASE = - dyn_cast<OMPArraySectionExpr>(SI->getAssociatedExpression())) { + } else if (auto *OASE = dyn_cast<OMPArraySectionExpr>( + SI->getAssociatedExpression())) { auto *E = OASE->getBase()->IgnoreParenImpCasts(); Type = OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); @@ -10989,11 +10173,14 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // 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 - if (DKind == OMPD_target && VD) { + if ((DKind == OMPD_target || DKind == OMPD_target_teams || + DKind == OMPD_target_teams_distribute || + DKind == OMPD_target_teams_distribute_parallel_for) && VD) { auto DVar = DSAS->getTopDSA(VD, false); if (isOpenMPPrivate(DVar.CKind)) { - SemaRef.Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + SemaRef.Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_map) << getOpenMPDirectiveName(DSAS->getCurrentDirective()); ReportOriginalDSA(SemaRef, DSAS, CurDeclaration, DVar); continue; @@ -11006,7 +10193,8 @@ checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, // Store the components in the stack so that they can be used to check // against other clauses later on. - DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents); + DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents, + /*WhereFoundClauseKind=*/OMPC_map); // Save the components and declaration to create the clause. For purposes of // the clause creation, any component list that has has base 'this' uses @@ -11274,7 +10462,7 @@ Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( return DeclReductions; } -OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, +OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { @@ -11301,8 +10489,8 @@ OMPClause *Sema::ActOnOpenMPThreadLimitClause(Expr *ThreadLimit, /*StrictlyPositive=*/true)) return nullptr; - return new (Context) OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, - EndLoc); + return new (Context) + OMPThreadLimitClause(ValExpr, StartLoc, LParenLoc, EndLoc); } OMPClause *Sema::ActOnOpenMPPriorityClause(Expr *Priority, @@ -11421,18 +10609,17 @@ OMPClause *Sema::ActOnOpenMPDefaultmapClause( SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc, SourceLocation KindLoc, SourceLocation EndLoc) { // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)' - if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || - Kind != OMPC_DEFAULTMAP_scalar) { + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom || Kind != OMPC_DEFAULTMAP_scalar) { std::string Value; SourceLocation Loc; Value += "'"; if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) { Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, - OMPC_DEFAULTMAP_MODIFIER_tofrom); + OMPC_DEFAULTMAP_MODIFIER_tofrom); Loc = MLoc; } else { Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, - OMPC_DEFAULTMAP_scalar); + OMPC_DEFAULTMAP_scalar); Loc = KindLoc; } Value += "'"; @@ -11469,11 +10656,11 @@ void Sema::ActOnFinishOpenMPDeclareTargetDirective() { IsInOpenMPDeclareTargetContext = false; } -void -Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec, - const DeclarationNameInfo &Id, - OMPDeclareTargetDeclAttr::MapTypeTy MT, - NamedDeclSetType &SameDirectiveDecls) { +void Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, + CXXScopeSpec &ScopeSpec, + const DeclarationNameInfo &Id, + OMPDeclareTargetDeclAttr::MapTypeTy MT, + NamedDeclSetType &SameDirectiveDecls) { LookupResult Lookup(*this, Id, LookupOrdinaryName); LookupParsedName(Lookup, CurScope, &ScopeSpec, true); @@ -11671,7 +10858,10 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - SmallVector<Expr *, 8> Vars; + MappableVarListInfo MVLI(VarList); + SmallVector<Expr *, 8> PrivateCopies; + SmallVector<Expr *, 8> Inits; + for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause."); SourceLocation ELoc; @@ -11680,43 +10870,89 @@ OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. - Vars.push_back(RefExpr); + MVLI.ProcessedVarList.push_back(RefExpr); + PrivateCopies.push_back(nullptr); + Inits.push_back(nullptr); } ValueDecl *D = Res.first; if (!D) continue; QualType Type = D->getType(); - // item should be a pointer or reference to pointer - if (!Type.getNonReferenceType()->isPointerType()) { + Type = Type.getNonReferenceType().getUnqualifiedType(); + + auto *VD = dyn_cast<VarDecl>(D); + + // Item should be a pointer or reference to pointer. + if (!Type->isPointerType()) { Diag(ELoc, diag::err_omp_usedeviceptr_not_a_pointer) << 0 << RefExpr->getSourceRange(); continue; } - Vars.push_back(RefExpr->IgnoreParens()); + + // Build the private variable and the expression that refers to it. + auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + if (VDPrivate->isInvalidDecl()) + continue; + + CurContext->addDecl(VDPrivate); + auto VDPrivateRefExpr = buildDeclRefExpr( + *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); + + // Add temporary variable to initialize the private copy of the pointer. + auto *VDInit = + buildVarDecl(*this, RefExpr->getExprLoc(), Type, ".devptr.temp"); + auto *VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(), + RefExpr->getExprLoc()); + AddInitializerToDecl(VDPrivate, + DefaultLvalueConversion(VDInitRefExpr).get(), + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); + + // 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); + PrivateCopies.push_back(VDPrivateRefExpr); + Inits.push_back(VDInitRefExpr); + + // 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_ptr 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.resize(MVLI.VarComponents.size() + 1); + MVLI.VarComponents.back().push_back( + OMPClauseMappableExprCommon::MappableComponent(SimpleRefExpr, D)); } - if (Vars.empty()) + if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPUseDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); + return OMPUseDevicePtrClause::Create( + Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, + PrivateCopies, Inits, MVLI.VarBaseDeclarations, MVLI.VarComponents); } OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - SmallVector<Expr *, 8> Vars; + MappableVarListInfo MVLI(VarList); for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause."); + assert(RefExpr && "NULL expr in OpenMP is_device_ptr clause."); SourceLocation ELoc; SourceRange ERange; Expr *SimpleRefExpr = RefExpr; auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange); if (Res.second) { // It will be analyzed later. - Vars.push_back(RefExpr); + MVLI.ProcessedVarList.push_back(RefExpr); } ValueDecl *D = Res.first; if (!D) @@ -11730,12 +10966,59 @@ OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, << 0 << RefExpr->getSourceRange(); continue; } - Vars.push_back(RefExpr->IgnoreParens()); + + // Check if the declaration in the clause does not show up in any data + // sharing attribute. + auto DVar = DSAStack->getTopDSA(D, false); + if (isOpenMPPrivate(DVar.CKind)) { + Diag(ELoc, diag::err_omp_variable_in_given_clause_and_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPClauseName(OMPC_is_device_ptr) + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + + Expr *ConflictExpr; + if (DSAStack->checkMappableExprComponentListsForDecl( + D, /*CurrentRegionOnly=*/true, + [&ConflictExpr]( + OMPClauseMappableExprCommon::MappableExprComponentListRef R, + OpenMPClauseKind) -> bool { + ConflictExpr = R.front().getAssociatedExpression(); + return true; + })) { + Diag(ELoc, diag::err_omp_map_shared_storage) << RefExpr->getSourceRange(); + Diag(ConflictExpr->getExprLoc(), diag::note_used_here) + << ConflictExpr->getSourceRange(); + continue; + } + + // Store the components in the stack so that they can be used to check + // against other clauses later on. + OMPClauseMappableExprCommon::MappableComponent MC(SimpleRefExpr, D); + DSAStack->addMappableExpressionComponents( + D, MC, /*WhereFoundClauseKind=*/OMPC_is_device_ptr); + + // Record the expression we've just processed. + MVLI.ProcessedVarList.push_back(SimpleRefExpr); + + // Create a mappable component for the list item. List items in this clause + // only need a component. We use a null declaration to signal fields in + // 'this'. + assert((isa<DeclRefExpr>(SimpleRefExpr) || + isa<CXXThisExpr>(cast<MemberExpr>(SimpleRefExpr)->getBase())) && + "Unexpected device pointer expression!"); + MVLI.VarBaseDeclarations.push_back( + isa<DeclRefExpr>(SimpleRefExpr) ? D : nullptr); + MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); + MVLI.VarComponents.back().push_back(MC); } - if (Vars.empty()) + if (MVLI.ProcessedVarList.empty()) return nullptr; - return OMPIsDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars); + return OMPIsDevicePtrClause::Create( + Context, StartLoc, LParenLoc, EndLoc, MVLI.ProcessedVarList, + MVLI.VarBaseDeclarations, MVLI.VarComponents); } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 40d6e910f1fb3..47e3df20d9111 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -39,8 +39,9 @@ using namespace clang; using namespace sema; static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { - return llvm::any_of(FD->parameters(), - std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); + return llvm::any_of(FD->parameters(), [](const ParmVarDecl *P) { + return P->hasAttr<PassObjectSizeAttr>(); + }); } /// A convenience routine for creating a decayed reference to a function. @@ -59,6 +60,8 @@ CreateFunctionRefExpr(Sema &S, FunctionDecl *Fn, NamedDecl *FoundDecl, // being used. if (FoundDecl != Fn && S.DiagnoseUseOfDecl(Fn, Loc)) return ExprError(); + if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>()) + S.ResolveExceptionSpec(Loc, FPT); DeclRefExpr *DRE = new (S.Context) DeclRefExpr(Fn, false, Fn->getType(), VK_LValue, Loc, LocInfo); if (HadMultipleCandidates) @@ -135,7 +138,8 @@ ImplicitConversionRank clang::GetConversionRank(ImplicitConversionKind Kind) { ICR_Exact_Match, // NOTE(gbiv): This may not be completely right -- // it was omitted by the patch that added // ICK_Zero_Event_Conversion - ICR_C_Conversion + ICR_C_Conversion, + ICR_C_Conversion_Extension }; return Rank[(int)Kind]; } @@ -148,7 +152,7 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Lvalue-to-rvalue", "Array-to-pointer", "Function-to-pointer", - "Noreturn adjustment", + "Function pointer conversion", "Qualification", "Integral promotion", "Floating point promotion", @@ -169,7 +173,8 @@ static const char* GetImplicitConversionName(ImplicitConversionKind Kind) { "Transparent Union Conversion", "Writeback conversion", "OpenCL Zero Event Conversion", - "C specific type conversion" + "C specific type conversion", + "Incompatible pointer conversion" }; return Name[Kind]; } @@ -324,6 +329,11 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, } else if (FromType->isIntegralType(Ctx) && ToType->isRealFloatingType()) { llvm::APSInt IntConstantValue; const Expr *Initializer = IgnoreNarrowingConversion(Converted); + + // If it's value-dependent, we can't tell whether it's narrowing. + if (Initializer->isValueDependent()) + return NK_Dependent_Narrowing; + if (Initializer && Initializer->isIntegerConstantExpr(IntConstantValue, Ctx)) { // Convert the integer to the floating type. @@ -357,6 +367,11 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, Ctx.getFloatingTypeOrder(FromType, ToType) == 1) { // FromType is larger than ToType. const Expr *Initializer = IgnoreNarrowingConversion(Converted); + + // If it's value-dependent, we can't tell whether it's narrowing. + if (Initializer->isValueDependent()) + return NK_Dependent_Narrowing; + if (Initializer->isCXX11ConstantExpr(Ctx, &ConstantValue)) { // Constant! assert(ConstantValue.isFloat()); @@ -398,6 +413,11 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, // Not all values of FromType can be represented in ToType. llvm::APSInt InitializerValue; const Expr *Initializer = IgnoreNarrowingConversion(Converted); + + // If it's value-dependent, we can't tell whether it's narrowing. + if (Initializer->isValueDependent()) + return NK_Dependent_Narrowing; + if (!Initializer->isIntegerConstantExpr(InitializerValue, Ctx)) { // Such conversions on variables are always narrowing. return NK_Variable_Narrowing; @@ -575,6 +595,7 @@ clang::MakeDeductionFailureInfo(ASTContext &Context, case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_CUDATargetMismatch: Result.Data = nullptr; break; @@ -642,6 +663,7 @@ void DeductionFailureInfo::Destroy() { case Sema::TDK_TooFewArguments: case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_FailedOverloadResolution: + case Sema::TDK_CUDATargetMismatch: break; case Sema::TDK_Inconsistent: @@ -684,6 +706,7 @@ TemplateParameter DeductionFailureInfo::getTemplateParameter() { case Sema::TDK_DeducedMismatch: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: + case Sema::TDK_CUDATargetMismatch: return TemplateParameter(); case Sema::TDK_Incomplete: @@ -715,6 +738,7 @@ TemplateArgumentList *DeductionFailureInfo::getTemplateArgumentList() { case Sema::TDK_Underqualified: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_FailedOverloadResolution: + case Sema::TDK_CUDATargetMismatch: return nullptr; case Sema::TDK_DeducedMismatch: @@ -742,6 +766,7 @@ const TemplateArgument *DeductionFailureInfo::getFirstArg() { case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_SubstitutionFailure: case Sema::TDK_FailedOverloadResolution: + case Sema::TDK_CUDATargetMismatch: return nullptr; case Sema::TDK_Inconsistent: @@ -769,6 +794,7 @@ const TemplateArgument *DeductionFailureInfo::getSecondArg() { case Sema::TDK_InvalidExplicitArguments: case Sema::TDK_SubstitutionFailure: case Sema::TDK_FailedOverloadResolution: + case Sema::TDK_CUDATargetMismatch: return nullptr; case Sema::TDK_Inconsistent: @@ -812,6 +838,7 @@ void OverloadCandidateSet::destroyCandidates() { void OverloadCandidateSet::clear() { destroyCandidates(); + ConversionSequenceAllocator.Reset(); NumInlineSequences = 0; Candidates.clear(); Functions.clear(); @@ -969,16 +996,23 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, Match = *I; return Ovl_Match; } - } else if (isa<UsingDecl>(OldD)) { + } else if (isa<UsingDecl>(OldD) || isa<UsingPackDecl>(OldD)) { // We can overload with these, which can show up when doing // redeclaration checks for UsingDecls. assert(Old.getLookupKind() == LookupUsingDeclName); } else if (isa<TagDecl>(OldD)) { // We can always overload with tags by hiding them. - } else if (isa<UnresolvedUsingValueDecl>(OldD)) { + } else if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(OldD)) { // Optimistically assume that an unresolved using decl will // overload; if it doesn't, we'll have to diagnose during // template instantiation. + // + // Exception: if the scope is dependent and this is not a class + // member, the using declaration can only introduce an enumerator. + if (UUD->getQualifier()->isDependent() && !UUD->isCXXClassMember()) { + Match = *I; + return Ovl_NonFunction; + } } else { // (C++ 13p1): // Only function declarations can be overloaded; object and type @@ -1126,24 +1160,20 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, } if (getLangOpts().CUDA && ConsiderCudaAttrs) { + // Don't allow overloading of destructors. (In theory we could, but it + // would be a giant change to clang.) + if (isa<CXXDestructorDecl>(New)) + return false; + CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New), OldTarget = IdentifyCUDATarget(Old); - if (NewTarget == CFT_InvalidTarget || NewTarget == CFT_Global) + if (NewTarget == CFT_InvalidTarget) return false; assert((OldTarget != CFT_InvalidTarget) && "Unexpected invalid target."); - // Don't allow mixing of HD with other kinds. This guarantees that - // we have only one viable function with this signature on any - // side of CUDA compilation . - // __global__ functions can't be overloaded based on attribute - // difference because, like HD, they also exist on both sides. - if ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice) || - (NewTarget == CFT_Global) || (OldTarget == CFT_Global)) - return false; - - // Allow overloading of functions with same signature, but - // different CUDA target attributes. + // Allow overloading of functions with same signature and different CUDA + // target attributes. return NewTarget != OldTarget; } @@ -1199,7 +1229,6 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, case OR_Success: case OR_Deleted: ICS.setUserDefined(); - ICS.UserDefined.Before.setAsIdentityConversion(); // C++ [over.ics.user]p4: // A conversion of an expression of class type to the same class // type is given Exact Match rank, and a conversion of an @@ -1383,17 +1412,20 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, } /// \brief Determine whether the conversion from FromType to ToType is a valid -/// conversion that strips "noreturn" off the nested function type. -bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType, +/// conversion that strips "noexcept" or "noreturn" off the nested function +/// type. +bool Sema::IsFunctionConversion(QualType FromType, QualType ToType, QualType &ResultTy) { if (Context.hasSameUnqualifiedType(FromType, ToType)) return false; // Permit the conversion F(t __attribute__((noreturn))) -> F(t) + // or F(t noexcept) -> F(t) // where F adds one of the following at most once: // - a pointer // - a member pointer // - a block pointer + // Changes here need matching changes in FindCompositePointerType. CanQualType CanTo = Context.getCanonicalType(ToType); CanQualType CanFrom = Context.getCanonicalType(FromType); Type::TypeClass TyClass = CanTo->getTypeClass(); @@ -1406,8 +1438,13 @@ bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType, CanTo = CanTo.getAs<BlockPointerType>()->getPointeeType(); CanFrom = CanFrom.getAs<BlockPointerType>()->getPointeeType(); } else if (TyClass == Type::MemberPointer) { - CanTo = CanTo.getAs<MemberPointerType>()->getPointeeType(); - CanFrom = CanFrom.getAs<MemberPointerType>()->getPointeeType(); + auto ToMPT = CanTo.getAs<MemberPointerType>(); + auto FromMPT = CanFrom.getAs<MemberPointerType>(); + // A function pointer conversion cannot change the class of the function. + if (ToMPT->getClass() != FromMPT->getClass()) + return false; + CanTo = ToMPT->getPointeeType(); + CanFrom = FromMPT->getPointeeType(); } else { return false; } @@ -1418,11 +1455,37 @@ bool Sema::IsNoReturnConversion(QualType FromType, QualType ToType, return false; } - const FunctionType *FromFn = cast<FunctionType>(CanFrom); - FunctionType::ExtInfo EInfo = FromFn->getExtInfo(); - if (!EInfo.getNoReturn()) return false; + const auto *FromFn = cast<FunctionType>(CanFrom); + FunctionType::ExtInfo FromEInfo = FromFn->getExtInfo(); + + const auto *ToFn = cast<FunctionType>(CanTo); + FunctionType::ExtInfo ToEInfo = ToFn->getExtInfo(); + + bool Changed = false; + + // Drop 'noreturn' if not present in target type. + if (FromEInfo.getNoReturn() && !ToEInfo.getNoReturn()) { + FromFn = Context.adjustFunctionType(FromFn, FromEInfo.withNoReturn(false)); + Changed = true; + } + + // Drop 'noexcept' if not present in target type. + if (const auto *FromFPT = dyn_cast<FunctionProtoType>(FromFn)) { + const auto *ToFPT = cast<FunctionProtoType>(ToFn); + if (FromFPT->isNothrow(Context) && !ToFPT->isNothrow(Context)) { + FromFn = cast<FunctionType>( + Context.getFunctionType(FromFPT->getReturnType(), + FromFPT->getParamTypes(), + FromFPT->getExtProtoInfo().withExceptionSpec( + FunctionProtoType::ExceptionSpecInfo())) + .getTypePtr()); + Changed = true; + } + } + + if (!Changed) + return false; - FromFn = Context.adjustFunctionType(FromFn, EInfo.withNoReturn(false)); assert(QualType(FromFn, 0).isCanonical()); if (QualType(FromFn, 0) != CanTo) return false; @@ -1527,7 +1590,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, S.ExtractUnqualifiedFunctionType(ToType), FromType)) { QualType resultTy; // if the function type matches except for [[noreturn]], it's ok - if (!S.IsNoReturnConversion(FromType, + if (!S.IsFunctionConversion(FromType, S.ExtractUnqualifiedFunctionType(ToType), resultTy)) // otherwise, only a boolean conversion is standard if (!ToType->isBooleanType()) @@ -1556,6 +1619,8 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, } // Check that we've computed the proper type after overload resolution. + // FIXME: FixOverloadedFunctionReference has side-effects; we shouldn't + // be calling it from within an NDEBUG block. assert(S.Context.hasSameType( FromType, S.FixOverloadedFunctionReference(From, AccessPair, Fn)->getType())); @@ -1684,7 +1749,7 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, ToType == S.Context.Float128Ty)); if (Float128AndLongDouble && (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != - &llvm::APFloat::IEEEdouble)) + &llvm::APFloat::IEEEdouble())) return false; } // Floating point conversions (C++ 4.8). @@ -1720,9 +1785,6 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, // Compatible conversions (Clang extension for C function overloading) SCS.Second = ICK_Compatible_Conversion; FromType = ToType.getUnqualifiedType(); - } else if (S.IsNoReturnConversion(FromType, ToType, FromType)) { - // Treat a conversion that strips "noreturn" as an identity conversion. - SCS.Second = ICK_NoReturn_Adjustment; } else if (IsTransparentUnionStandardConversion(S, From, ToType, InOverloadResolution, SCS, CStyle)) { @@ -1738,40 +1800,47 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, From->EvaluateKnownConstInt(S.getASTContext()) == 0) { SCS.Second = ICK_Zero_Event_Conversion; FromType = ToType; + } else if (ToType->isQueueT() && + From->isIntegerConstantExpr(S.getASTContext()) && + (From->EvaluateKnownConstInt(S.getASTContext()) == 0)) { + SCS.Second = ICK_Zero_Queue_Conversion; + FromType = ToType; } else { // No second conversion required. SCS.Second = ICK_Identity; } SCS.setToType(1, FromType); - QualType CanonFrom; - QualType CanonTo; - // The third conversion can be a qualification conversion (C++ 4p1). + // The third conversion can be a function pointer conversion or a + // qualification conversion (C++ [conv.fctptr], [conv.qual]). bool ObjCLifetimeConversion; - if (S.IsQualificationConversion(FromType, ToType, CStyle, - ObjCLifetimeConversion)) { + if (S.IsFunctionConversion(FromType, ToType, FromType)) { + // Function pointer conversions (removing 'noexcept') including removal of + // 'noreturn' (Clang extension). + SCS.Third = ICK_Function_Conversion; + } else if (S.IsQualificationConversion(FromType, ToType, CStyle, + ObjCLifetimeConversion)) { SCS.Third = ICK_Qualification; SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion; FromType = ToType; - CanonFrom = S.Context.getCanonicalType(FromType); - CanonTo = S.Context.getCanonicalType(ToType); } else { // No conversion required SCS.Third = ICK_Identity; + } - // C++ [over.best.ics]p6: - // [...] Any difference in top-level cv-qualification is - // subsumed by the initialization itself and does not constitute - // a conversion. [...] - CanonFrom = S.Context.getCanonicalType(FromType); - CanonTo = S.Context.getCanonicalType(ToType); - if (CanonFrom.getLocalUnqualifiedType() - == CanonTo.getLocalUnqualifiedType() && - CanonFrom.getLocalQualifiers() != CanonTo.getLocalQualifiers()) { - FromType = ToType; - CanonFrom = CanonTo; - } + // C++ [over.best.ics]p6: + // [...] Any difference in top-level cv-qualification is + // subsumed by the initialization itself and does not constitute + // a conversion. [...] + QualType CanonFrom = S.Context.getCanonicalType(FromType); + QualType CanonTo = S.Context.getCanonicalType(ToType); + if (CanonFrom.getLocalUnqualifiedType() + == CanonTo.getLocalUnqualifiedType() && + CanonFrom.getLocalQualifiers() != CanonTo.getLocalQualifiers()) { + FromType = ToType; + CanonFrom = CanonTo; } + SCS.setToType(2, FromType); if (CanonFrom == CanonTo) @@ -1783,22 +1852,43 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, return false; ExprResult ER = ExprResult{From}; - auto Conv = S.CheckSingleAssignmentConstraints(ToType, ER, - /*Diagnose=*/false, - /*DiagnoseCFAudited=*/false, - /*ConvertRHS=*/false); - if (Conv != Sema::Compatible) + Sema::AssignConvertType Conv = + S.CheckSingleAssignmentConstraints(ToType, ER, + /*Diagnose=*/false, + /*DiagnoseCFAudited=*/false, + /*ConvertRHS=*/false); + ImplicitConversionKind SecondConv; + switch (Conv) { + case Sema::Compatible: + SecondConv = ICK_C_Only_Conversion; + break; + // For our purposes, discarding qualifiers is just as bad as using an + // incompatible pointer. Note that an IncompatiblePointer conversion can drop + // qualifiers, as well. + case Sema::CompatiblePointerDiscardsQualifiers: + case Sema::IncompatiblePointer: + case Sema::IncompatiblePointerSign: + SecondConv = ICK_Incompatible_Pointer_Conversion; + break; + default: return false; + } + + // First can only be an lvalue conversion, so we pretend that this was the + // second conversion. First should already be valid from earlier in the + // function. + SCS.Second = SecondConv; + SCS.setToType(1, ToType); - SCS.setAllToTypes(ToType); - // We need to set all three because we want this conversion to rank terribly, - // and we don't know what conversions it may overlap with. - SCS.First = ICK_C_Only_Conversion; - SCS.Second = ICK_C_Only_Conversion; - SCS.Third = ICK_C_Only_Conversion; + // Third is Identity, because Second should rank us worse than any other + // conversion. This could also be ICK_Qualification, but it's simpler to just + // lump everything in with the second conversion, and we don't gain anything + // from making this ICK_Qualification. + SCS.Third = ICK_Identity; + SCS.setToType(2, ToType); return true; } - + static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From, QualType &ToType, @@ -2587,7 +2677,8 @@ enum { ft_parameter_arity, ft_parameter_mismatch, ft_return_type, - ft_qualifer_mismatch + ft_qualifer_mismatch, + ft_noexcept }; /// Attempts to get the FunctionProtoType from a Type. Handles @@ -2687,6 +2778,16 @@ void Sema::HandleFunctionTypeMismatch(PartialDiagnostic &PDiag, return; } + // Handle exception specification differences on canonical type (in C++17 + // onwards). + if (cast<FunctionProtoType>(FromFunction->getCanonicalTypeUnqualified()) + ->isNothrow(Context) != + cast<FunctionProtoType>(ToFunction->getCanonicalTypeUnqualified()) + ->isNothrow(Context)) { + PDiag << ft_noexcept; + return; + } + // Unable to find a difference, so add no extra info. PDiag << ft_default; } @@ -4098,6 +4199,7 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, DerivedToBase = false; ObjCConversion = false; ObjCLifetimeConversion = false; + QualType ConvertedT2; if (UnqualT1 == UnqualT2) { // Nothing to do. } else if (isCompleteType(Loc, OrigT2) && @@ -4108,6 +4210,15 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, UnqualT2->isObjCObjectOrInterfaceType() && Context.canBindObjCObjectType(UnqualT1, UnqualT2)) ObjCConversion = true; + else if (UnqualT2->isFunctionType() && + IsFunctionConversion(UnqualT2, UnqualT1, ConvertedT2)) + // C++1z [dcl.init.ref]p4: + // cv1 T1" is reference-compatible with "cv2 T2" if [...] T2 is "noexcept + // function" and T1 is "function" + // + // We extend this to also apply to 'noreturn', so allow any function + // conversion between function types. + return Ref_Compatible; else return Ref_Incompatible; @@ -4146,10 +4257,8 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, T1Quals.removeUnaligned(); T2Quals.removeUnaligned(); - if (T1Quals == T2Quals) + if (T1Quals.compatiblyIncludes(T2Quals)) return Ref_Compatible; - else if (T1Quals.compatiblyIncludes(T2Quals)) - return Ref_Compatible_With_Added_Qualification; else return Ref_Related; } @@ -4327,8 +4436,7 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // reference-compatible with "cv2 T2," or // // Per C++ [over.ics.ref]p4, we don't check the bit-field property here. - if (InitCategory.isLValue() && - RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) { + if (InitCategory.isLValue() && RefRelationship == Sema::Ref_Compatible) { // C++ [over.ics.ref]p1: // When a parameter of reference type binds directly (8.5.3) // to an argument expression, the implicit conversion sequence @@ -4390,10 +4498,10 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // // -- is an xvalue, class prvalue, array prvalue or function // lvalue and "cv1 T1" is reference-compatible with "cv2 T2", or - if (RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification && + if (RefRelationship == Sema::Ref_Compatible && (InitCategory.isXValue() || - (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || - (InitCategory.isLValue() && T2->isFunctionType()))) { + (InitCategory.isPRValue() && (T2->isRecordType() || T2->isArrayType())) || + (InitCategory.isLValue() && T2->isFunctionType()))) { ICS.setStandard(); ICS.Standard.First = ICK_Identity; ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base @@ -4540,7 +4648,6 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, return ICS; } - ICS.UserDefined.Before.setAsIdentityConversion(); ICS.UserDefined.After.ReferenceBinding = true; ICS.UserDefined.After.IsLvalueReference = !isRValRef; ICS.UserDefined.After.BindsToFunctionLvalue = false; @@ -4693,6 +4800,9 @@ TryListConversion(Sema &S, InitListExpr *From, QualType ToType, // Type is an aggregate, argument is an init list. At this point it comes // down to checking whether the initialization works. // FIXME: Find out whether this parameter is consumed or not. + // FIXME: Expose SemaInit's aggregate initialization code so that we don't + // need to call into the initialization code here; overload resolution + // should not be doing that. InitializedEntity Entity = InitializedEntity::InitializeParameter(S.Context, ToType, /*Consumed=*/false); @@ -4896,7 +5006,7 @@ TryObjectArgumentInitialization(Sema &S, SourceLocation Loc, QualType FromType, // cv-qualification on the member function declaration. // // However, when finding an implicit conversion sequence for the argument, we - // are not allowed to create temporaries or perform user-defined conversions + // are not allowed to perform user-defined conversions // (C++ [over.match.funcs]p5). We perform a simplified version of // reference binding here, that allows class rvalues to bind to // non-constant references. @@ -5069,9 +5179,10 @@ static bool CheckConvertedConstantConversions(Sema &S, // conversions are fine. switch (SCS.Second) { case ICK_Identity: - case ICK_NoReturn_Adjustment: + case ICK_Function_Conversion: case ICK_Integral_Promotion: case ICK_Integral_Conversion: // Narrowing conversions are checked elsewhere. + case ICK_Zero_Queue_Conversion: return true; case ICK_Boolean_Conversion: @@ -5106,6 +5217,7 @@ static bool CheckConvertedConstantConversions(Sema &S, case ICK_Writeback_Conversion: case ICK_Zero_Event_Conversion: case ICK_C_Only_Conversion: + case ICK_Incompatible_Pointer_Conversion: return false; case ICK_Lvalue_To_Rvalue: @@ -5141,12 +5253,18 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, // implicitly converted to type T, where the converted // expression is a constant expression and the implicit conversion // sequence contains only [... list of conversions ...]. + // C++1z [stmt.if]p2: + // If the if statement is of the form if constexpr, the value of the + // condition shall be a contextually converted constant expression of type + // bool. ImplicitConversionSequence ICS = - TryCopyInitialization(S, From, T, - /*SuppressUserConversions=*/false, - /*InOverloadResolution=*/false, - /*AllowObjcWritebackConversion=*/false, - /*AllowExplicit=*/false); + CCE == Sema::CCEK_ConstexprIf + ? TryContextuallyConvertToBool(S, From) + : TryCopyInitialization(S, From, T, + /*SuppressUserConversions=*/false, + /*InOverloadResolution=*/false, + /*AllowObjcWritebackConversion=*/false, + /*AllowExplicit=*/false); StandardConversionSequence *SCS = nullptr; switch (ICS.getKind()) { case ImplicitConversionSequence::StandardConversion: @@ -5192,6 +5310,9 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, QualType PreNarrowingType; switch (SCS->getNarrowingKind(S.Context, Result.get(), PreNarrowingValue, PreNarrowingType)) { + case NK_Dependent_Narrowing: + // Implicit conversion to a narrower type, but the expression is + // value-dependent so we can't tell whether it's actually narrowing. case NK_Variable_Narrowing: // Implicit conversion to a narrower type, and the value is not a constant // expression. We'll diagnose this in a moment. @@ -5210,6 +5331,11 @@ static ExprResult CheckConvertedConstantExpression(Sema &S, Expr *From, break; } + if (Result.get()->isValueDependent()) { + Value = APValue(); + return Result; + } + // Check the expression is a constant expression. SmallVector<PartialDiagnosticAt, 8> Notes; Expr::EvalResult Eval; @@ -5256,7 +5382,7 @@ ExprResult Sema::CheckConvertedConstantExpression(Expr *From, QualType T, APValue V; auto R = ::CheckConvertedConstantExpression(*this, From, T, V, CCE, true); - if (!R.isInvalid()) + if (!R.isInvalid() && !R.get()->isValueDependent()) Value = V.getInt(); return R; } @@ -5310,6 +5436,7 @@ TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) { /// PerformContextuallyConvertToObjCPointer - Perform a contextual /// conversion of the expression From to an Objective-C pointer type. +/// Returns a valid but null ExprResult if no conversion sequence exists. ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { if (checkPlaceholderForOverload(*this, From)) return ExprError(); @@ -5319,7 +5446,7 @@ ExprResult Sema::PerformContextuallyConvertToObjCPointer(Expr *From) { TryContextuallyConvertToObjCPointer(*this, From); if (!ICS.isBad()) return PerformImplicitConversion(From, Ty, ICS, AA_Converting); - return ExprError(); + return ExprResult(); } /// Determine whether the provided type is an integral type, or an enumeration @@ -5817,7 +5944,7 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, // case we may not yet know what the member's target is; the target is // inferred for the member automatically, based on the bases and fields of // the class. - if (!Caller->isImplicit() && CheckCUDATarget(Caller, Function)) { + if (!Caller->isImplicit() && !IsAllowedCUDACall(Caller, Function)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_target; return; @@ -5858,6 +5985,12 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, Candidate.DeductionFailure.Data = FailedAttr; return; } + + if (LangOpts.OpenCL && isOpenCLDisabledDecl(Function)) { + Candidate.Viable = false; + Candidate.FailureKind = ovl_fail_ext_disabled; + return; + } } ObjCMethodDecl * @@ -5907,10 +6040,15 @@ Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, /*AllowObjCWritebackConversion=*/ getLangOpts().ObjCAutoRefCount, /*AllowExplicit*/false); - if (ConversionState.isBad()) { - Match = false; - break; - } + // This function looks for a reasonably-exact match, so we consider + // incompatible pointer conversions to be a failure here. + if (ConversionState.isBad() || + (ConversionState.isStandard() && + ConversionState.Standard.Second == + ICK_Incompatible_Pointer_Conversion)) { + Match = false; + break; + } } // Promote additional arguments to variadic methods. if (Match && Method->isVariadic()) { @@ -5975,7 +6113,7 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, SmallVector<Expr *, 16> ConvertedArgs; bool InitializationFailed = false; - // Ignore any variadic parameters. Converting them is pointless, since the + // Ignore any variadic arguments. Converting them is pointless, since the // user can't refer to them in the enable_if condition. unsigned ArgSizeNoVarargs = std::min(Function->param_size(), Args.size()); @@ -6198,7 +6336,7 @@ Sema::AddMethodCandidate(CXXMethodDecl *Method, DeclAccessPair FoundDecl, // (CUDA B.1): Check for invalid calls between targets. if (getLangOpts().CUDA) if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) - if (CheckCUDATarget(Caller, Method)) { + if (!IsAllowedCUDACall(Caller, Method)) { Candidate.Viable = false; Candidate.FailureKind = ovl_fail_bad_target; return; @@ -7538,12 +7676,12 @@ public: } // C++ [over.match.oper]p16: - // For every pointer to member type T, there exist candidate operator - // functions of the form + // For every pointer to member type T or type std::nullptr_t, there + // exist candidate operator functions of the form // // bool operator==(T,T); // bool operator!=(T,T); - void addEqualEqualOrNotEqualMemberPointerOverloads() { + void addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads() { /// Set of (canonical) types that we've already handled. llvm::SmallPtrSet<QualType, 8> AddedTypes; @@ -7560,13 +7698,22 @@ public: QualType ParamTypes[2] = { *MemPtr, *MemPtr }; S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } + + if (CandidateTypes[ArgIdx].hasNullPtrType()) { + CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); + if (AddedTypes.insert(NullPtrTy).second) { + QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; + S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, + CandidateSet); + } + } } } // C++ [over.built]p15: // - // For every T, where T is an enumeration type, a pointer type, or - // std::nullptr_t, there exist candidate operator functions of the form + // For every T, where T is an enumeration type or a pointer type, + // there exist candidate operator functions of the form // // bool operator<(T, T); // bool operator>(T, T); @@ -7651,17 +7798,6 @@ public: QualType ParamTypes[2] = { *Enum, *Enum }; S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, CandidateSet); } - - if (CandidateTypes[ArgIdx].hasNullPtrType()) { - CanQualType NullPtrTy = S.Context.getCanonicalType(S.Context.NullPtrTy); - if (AddedTypes.insert(NullPtrTy).second && - !UserDefinedBinaryOperators.count(std::make_pair(NullPtrTy, - NullPtrTy))) { - QualType ParamTypes[2] = { NullPtrTy, NullPtrTy }; - S.AddBuiltinCandidate(S.Context.BoolTy, ParamTypes, Args, - CandidateSet); - } - } } } @@ -8357,7 +8493,7 @@ void Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, case OO_EqualEqual: case OO_ExclaimEqual: - OpBuilder.addEqualEqualOrNotEqualMemberPointerOverloads(); + OpBuilder.addEqualEqualOrNotEqualMemberPointerOrNullptrOverloads(); // Fall through. case OO_Less: @@ -8566,13 +8702,40 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, if (Cand1.IgnoreObjectArgument || Cand2.IgnoreObjectArgument) StartArg = 1; + auto IsIllFormedConversion = [&](const ImplicitConversionSequence &ICS) { + // We don't allow incompatible pointer conversions in C++. + if (!S.getLangOpts().CPlusPlus) + return ICS.isStandard() && + ICS.Standard.Second == ICK_Incompatible_Pointer_Conversion; + + // The only ill-formed conversion we allow in C++ is the string literal to + // char* conversion, which is only considered ill-formed after C++11. + return S.getLangOpts().CPlusPlus11 && !S.getLangOpts().WritableStrings && + hasDeprecatedStringLiteralToCharPtrConversion(ICS); + }; + + // Define functions that don't require ill-formed conversions for a given + // argument to be better candidates than functions that do. + unsigned NumArgs = Cand1.NumConversions; + assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch"); + bool HasBetterConversion = false; + for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { + bool Cand1Bad = IsIllFormedConversion(Cand1.Conversions[ArgIdx]); + bool Cand2Bad = IsIllFormedConversion(Cand2.Conversions[ArgIdx]); + if (Cand1Bad != Cand2Bad) { + if (Cand1Bad) + return false; + HasBetterConversion = true; + } + } + + if (HasBetterConversion) + return true; + // C++ [over.match.best]p1: // A viable function F1 is defined to be a better function than another // viable function F2 if for all arguments i, ICSi(F1) is not a worse // conversion sequence than ICSi(F2), and then... - unsigned NumArgs = Cand1.NumConversions; - assert(Cand2.NumConversions == NumArgs && "Overload candidate mismatch"); - bool HasBetterConversion = false; for (unsigned ArgIdx = StartArg; ArgIdx < NumArgs; ++ArgIdx) { switch (CompareImplicitConversionSequences(S, Loc, Cand1.Conversions[ArgIdx], @@ -8774,8 +8937,8 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, std::transform(begin(), end(), std::back_inserter(Candidates), [](OverloadCandidate &Cand) { return &Cand; }); - // [CUDA] HD->H or HD->D calls are technically not allowed by CUDA - // but accepted by both clang and NVCC. However during a particular + // [CUDA] HD->H or HD->D calls are technically not allowed by CUDA but + // are accepted by both clang and NVCC. However, during a particular // compilation mode only one call variant is viable. We need to // exclude non-viable overload candidates from consideration based // only on their host/device attributes. Specifically, if one @@ -8864,10 +9027,9 @@ enum OverloadCandidateKind { oc_inherited_constructor_template }; -OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, - NamedDecl *Found, - FunctionDecl *Fn, - std::string &Description) { +static OverloadCandidateKind +ClassifyOverloadCandidate(Sema &S, NamedDecl *Found, FunctionDecl *Fn, + std::string &Description) { bool isTemplate = false; if (FunctionTemplateDecl *FunTmpl = Fn->getPrimaryTemplate()) { @@ -8960,8 +9122,9 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } - auto I = llvm::find_if( - FD->parameters(), std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); + auto I = llvm::find_if(FD->parameters(), [](const ParmVarDecl *P) { + return P->hasAttr<PassObjectSizeAttr>(); + }); if (I == FD->param_end()) return true; @@ -9003,7 +9166,7 @@ void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, std::string FnDesc; OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Found, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) - << (unsigned) K << FnDesc; + << (unsigned) K << Fn << FnDesc; HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); @@ -9436,9 +9599,25 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, int which = 0; if (isa<TemplateTypeParmDecl>(ParamD)) which = 0; - else if (isa<NonTypeTemplateParmDecl>(ParamD)) + else if (isa<NonTypeTemplateParmDecl>(ParamD)) { + // Deduction might have failed because we deduced arguments of two + // different types for a non-type template parameter. + // FIXME: Use a different TDK value for this. + QualType T1 = + DeductionFailure.getFirstArg()->getNonTypeTemplateArgumentType(); + QualType T2 = + DeductionFailure.getSecondArg()->getNonTypeTemplateArgumentType(); + if (!S.Context.hasSameType(T1, T2)) { + S.Diag(Templated->getLocation(), + diag::note_ovl_candidate_inconsistent_deduction_types) + << ParamD->getDeclName() << *DeductionFailure.getFirstArg() << T1 + << *DeductionFailure.getSecondArg() << T2; + MaybeEmitInheritedConstructorNote(S, Found); + return; + } + which = 1; - else { + } else { which = 2; } @@ -9592,6 +9771,10 @@ static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction); MaybeEmitInheritedConstructorNote(S, Found); return; + case Sema::TDK_CUDATargetMismatch: + S.Diag(Templated->getLocation(), + diag::note_cuda_ovl_candidate_target_mismatch); + return; } } @@ -9673,6 +9856,13 @@ static void DiagnoseFailedEnableIfAttr(Sema &S, OverloadCandidate *Cand) { << Attr->getCond()->getSourceRange() << Attr->getMessage(); } +static void DiagnoseOpenCLExtensionDisabled(Sema &S, OverloadCandidate *Cand) { + FunctionDecl *Callee = Cand->Function; + + S.Diag(Callee->getLocation(), + diag::note_ovl_candidate_disabled_by_extension); +} + /// Generates a 'note' diagnostic for an overload candidate. We've /// already generated a primary error at the call site. /// @@ -9750,6 +9940,9 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, case ovl_fail_enable_if: return DiagnoseFailedEnableIfAttr(S, Cand); + case ovl_fail_ext_disabled: + return DiagnoseOpenCLExtensionDisabled(S, Cand); + case ovl_fail_addr_not_available: { bool Available = checkAddressOfCandidateIsAvailable(S, Cand->Function); (void)Available; @@ -9848,6 +10041,7 @@ static unsigned RankDeductionFailure(const DeductionFailureInfo &DFI) { case Sema::TDK_DeducedMismatch: case Sema::TDK_NonDeducedMismatch: case Sema::TDK_MiscellaneousDeductionFailure: + case Sema::TDK_CUDATargetMismatch: return 3; case Sema::TDK_InstantiationDepth: @@ -10074,16 +10268,17 @@ static void CompleteNonViableCandidate(Sema &S, OverloadCandidate *Cand, /// PrintOverloadCandidates - When overload resolution fails, prints /// diagnostic messages containing the candidates in the candidate /// set. -void OverloadCandidateSet::NoteCandidates(Sema &S, - OverloadCandidateDisplayKind OCD, - ArrayRef<Expr *> Args, - StringRef Opc, - SourceLocation OpLoc) { +void OverloadCandidateSet::NoteCandidates( + Sema &S, OverloadCandidateDisplayKind OCD, ArrayRef<Expr *> Args, + StringRef Opc, SourceLocation OpLoc, + llvm::function_ref<bool(OverloadCandidate &)> Filter) { // Sort the candidates by viability and position. Sorting directly would // be prohibitive, so we make a set of pointers and sort those. SmallVector<OverloadCandidate*, 32> Cands; if (OCD == OCD_AllCandidates) Cands.reserve(size()); for (iterator Cand = begin(), LastCand = end(); Cand != LastCand; ++Cand) { + if (!Filter(*Cand)) + continue; if (Cand->Viable) Cands.push_back(Cand); else if (OCD == OCD_AllCandidates) { @@ -10269,6 +10464,21 @@ QualType Sema::ExtractUnqualifiedFunctionType(QualType PossiblyAFunctionType) { return Ret; } +static bool completeFunctionType(Sema &S, FunctionDecl *FD, SourceLocation Loc, + bool Complain = true) { + if (S.getLangOpts().CPlusPlus14 && FD->getReturnType()->isUndeducedType() && + S.DeduceReturnType(FD, Loc, Complain)) + return true; + + auto *FPT = FD->getType()->castAs<FunctionProtoType>(); + if (S.getLangOpts().CPlusPlus1z && + isUnresolvedExceptionSpec(FPT->getExceptionSpecType()) && + !S.ResolveExceptionSpec(Loc, FPT)) + return true; + + return false; +} + namespace { // A helper class to help with address of function resolution // - allows us to avoid passing around all those ugly parameters @@ -10359,7 +10569,7 @@ private: bool candidateHasExactlyCorrectType(const FunctionDecl *FD) { QualType Discard; return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) || - S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard); + S.IsFunctionConversion(FD->getType(), TargetFunctionType, Discard); } /// \return true if A is considered a better overload candidate for the @@ -10436,7 +10646,7 @@ private: = S.DeduceTemplateArguments(FunctionTemplate, &OvlExplicitTemplateArgs, TargetFunctionType, Specialization, - Info, /*InOverloadResolution=*/true)) { + Info, /*IsAddressOfFunction*/true)) { // Make a note of the failed deduction for diagnostics. FailedCandidates.addCandidate() .set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(), @@ -10472,14 +10682,13 @@ private: if (FunctionDecl *FunDecl = dyn_cast<FunctionDecl>(Fn)) { if (S.getLangOpts().CUDA) if (FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext)) - if (!Caller->isImplicit() && S.CheckCUDATarget(Caller, FunDecl)) + if (!Caller->isImplicit() && !S.IsAllowedCUDACall(Caller, FunDecl)) return false; // If any candidate has a placeholder return type, trigger its deduction // now. - if (S.getLangOpts().CPlusPlus14 && - FunDecl->getReturnType()->isUndeducedType() && - S.DeduceReturnType(FunDecl, SourceExpr->getLocStart(), Complain)) { + if (completeFunctionType(S, FunDecl, SourceExpr->getLocStart(), + Complain)) { HasComplained |= Complain; return false; } @@ -10704,6 +10913,8 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, else if (NumMatches == 1) { Fn = Resolver.getMatchingFunctionDecl(); assert(Fn); + if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>()) + ResolveExceptionSpec(AddressOfExpr->getExprLoc(), FPT); FoundResult = *Resolver.getMatchingFunctionAccessPair(); if (Complain) { if (Resolver.IsStaticMemberFunctionFromBoundPointer()) @@ -10838,7 +11049,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, if (TemplateDeductionResult Result = DeduceTemplateArguments(FunctionTemplate, &ExplicitTemplateArgs, Specialization, Info, - /*InOverloadResolution=*/true)) { + /*IsAddressOfFunction*/true)) { // Make a note of the failed deduction for diagnostics. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate() @@ -10863,9 +11074,8 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, if (FoundResult) *FoundResult = I.getPair(); } - if (Matched && getLangOpts().CPlusPlus14 && - Matched->getReturnType()->isUndeducedType() && - DeduceReturnType(Matched, ovl->getExprLoc(), Complain)) + if (Matched && + completeFunctionType(*this, Matched, ovl->getExprLoc(), Complain)) return nullptr; return Matched; @@ -11255,6 +11465,12 @@ BuildRecoveryCallExpr(Sema &SemaRef, Scope *S, Expr *Fn, assert(!R.empty() && "lookup results empty despite recovery"); + // If recovery created an ambiguity, just bail out. + if (R.isAmbiguous()) { + R.suppressDiagnostics(); + return ExprError(); + } + // Build an implicit member call if appropriate. Just drop the // casts and such from the call, we don't really care. ExprResult NewFn = ExprError(); @@ -12331,18 +12547,6 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, new (Context) CXXMemberCallExpr(Context, MemExprE, Args, ResultType, VK, RParenLoc); - // (CUDA B.1): Check for invalid calls between targets. - if (getLangOpts().CUDA) { - if (const FunctionDecl *Caller = dyn_cast<FunctionDecl>(CurContext)) { - if (CheckCUDATarget(Caller, Method)) { - Diag(MemExpr->getMemberLoc(), diag::err_ref_bad_target) - << IdentifyCUDATarget(Method) << Method->getIdentifier() - << IdentifyCUDATarget(Caller); - return ExprError(); - } - } - } - // Check for a valid return type. if (CheckCallReturnType(Method->getReturnType(), MemExpr->getMemberLoc(), TheCall, Method)) @@ -12374,10 +12578,10 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, // In the case the method to call was not selected by the overloading // 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 (isa<MemberExpr>(NakedMemExpr)) { + // 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)) { - Diag(MemExprE->getLocStart(), + Diag(MemE->getMemberLoc(), diag::err_ovl_no_viable_member_function_in_call) << Method << Method->getSourceRange(); Diag(Method->getLocation(), @@ -12619,9 +12823,9 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, // Build the full argument list for the method call (the implicit object // parameter is placed at the beginning of the list). - std::unique_ptr<Expr * []> MethodArgs(new Expr *[Args.size() + 1]); + SmallVector<Expr *, 8> MethodArgs(Args.size() + 1); MethodArgs[0] = Object.get(); - std::copy(Args.begin(), Args.end(), &MethodArgs[1]); + std::copy(Args.begin(), Args.end(), MethodArgs.begin() + 1); // Once we've built TheCall, all of the expressions are properly // owned. @@ -12630,10 +12834,8 @@ Sema::BuildCallToObjectOfClassType(Scope *S, Expr *Obj, ResultTy = ResultTy.getNonLValueExprType(Context); CXXOperatorCallExpr *TheCall = new (Context) - CXXOperatorCallExpr(Context, OO_Call, NewFn.get(), - llvm::makeArrayRef(MethodArgs.get(), Args.size() + 1), - ResultTy, VK, RParenLoc, false); - MethodArgs.reset(); + CXXOperatorCallExpr(Context, OO_Call, NewFn.get(), MethodArgs, ResultTy, + VK, RParenLoc, false); if (CheckCallReturnType(Method->getReturnType(), LParenLoc, TheCall, Method)) return true; @@ -12996,6 +13198,31 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, ICE->getValueKind()); } + if (auto *GSE = dyn_cast<GenericSelectionExpr>(E)) { + if (!GSE->isResultDependent()) { + Expr *SubExpr = + FixOverloadedFunctionReference(GSE->getResultExpr(), Found, Fn); + if (SubExpr == GSE->getResultExpr()) + return GSE; + + // Replace the resulting type information before rebuilding the generic + // selection expression. + ArrayRef<Expr *> A = GSE->getAssocExprs(); + SmallVector<Expr *, 4> AssocExprs(A.begin(), A.end()); + unsigned ResultIdx = GSE->getResultIndex(); + AssocExprs[ResultIdx] = SubExpr; + + return new (Context) GenericSelectionExpr( + Context, GSE->getGenericLoc(), GSE->getControllingExpr(), + GSE->getAssocTypeSourceInfos(), AssocExprs, GSE->getDefaultLoc(), + GSE->getRParenLoc(), GSE->containsUnexpandedParameterPack(), + ResultIdx); + } + // Rather than fall through to the unreachable, return the original generic + // selection expression. + return GSE; + } + if (UnaryOperator *UnOp = dyn_cast<UnaryOperator>(E)) { assert(UnOp->getOpcode() == UO_AddrOf && "Can only take the address of an overloaded function"); @@ -13044,6 +13271,13 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, UnOp->getOperatorLoc()); } + // C++ [except.spec]p17: + // An exception-specification is considered to be needed when: + // - in an expression the function is the unique lookup result or the + // selected member of a set of overloaded functions + if (auto *FPT = Fn->getType()->getAs<FunctionProtoType>()) + ResolveExceptionSpec(E->getExprLoc(), FPT); + if (UnresolvedLookupExpr *ULE = dyn_cast<UnresolvedLookupExpr>(E)) { // FIXME: avoid copy. TemplateArgumentListInfo TemplateArgsBuffer, *TemplateArgs = nullptr; diff --git a/lib/Sema/SemaPseudoObject.cpp b/lib/Sema/SemaPseudoObject.cpp index c93d800f96d1e..8e53fda846f4e 100644 --- a/lib/Sema/SemaPseudoObject.cpp +++ b/lib/Sema/SemaPseudoObject.cpp @@ -661,7 +661,7 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration( AltMember, prop->getQueryKind())) if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { - S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use) + S.Diag(RefExpr->getExprLoc(), diag::err_property_setter_ambiguous_use) << prop << prop1 << setter->getSelector(); S.Diag(prop->getLocation(), diag::note_property_declare); S.Diag(prop1->getLocation(), diag::note_property_declare); @@ -770,7 +770,8 @@ ExprResult ObjCPropertyOpBuilder::buildSet(Expr *op, SourceLocation opcLoc, ExprResult opResult = op; Sema::AssignConvertType assignResult = S.CheckSingleAssignmentConstraints(paramType, opResult); - if (S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, + if (opResult.isInvalid() || + S.DiagnoseAssignmentResult(assignResult, opcLoc, paramType, op->getType(), opResult.get(), Sema::AA_Assigning)) return ExprError(); @@ -1103,8 +1104,9 @@ Sema::ObjCSubscriptKind Diag(FromE->getExprLoc(), diag::err_objc_multiple_subscript_type_conversion) << FromE->getType(); for (unsigned int i = 0; i < ConversionDecls.size(); i++) - Diag(ConversionDecls[i]->getLocation(), diag::not_conv_function_declared_at); - + Diag(ConversionDecls[i]->getLocation(), + diag::note_conv_function_declared_at); + return OS_Error; } @@ -1479,7 +1481,7 @@ ExprResult MSPropertyOpBuilder::buildGet() { SourceLocation(), GetterName, nullptr); if (GetterExpr.isInvalid()) { S.Diag(RefExpr->getMemberLoc(), - diag::error_cannot_find_suitable_accessor) << 0 /* getter */ + diag::err_cannot_find_suitable_accessor) << 0 /* getter */ << RefExpr->getPropertyDecl(); return ExprError(); } @@ -1508,7 +1510,7 @@ ExprResult MSPropertyOpBuilder::buildSet(Expr *op, SourceLocation sl, SourceLocation(), SetterName, nullptr); if (SetterExpr.isInvalid()) { S.Diag(RefExpr->getMemberLoc(), - diag::error_cannot_find_suitable_accessor) << 1 /* setter */ + diag::err_cannot_find_suitable_accessor) << 1 /* setter */ << RefExpr->getPropertyDecl(); return ExprError(); } diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 8e8104e581b27..50f0a22ff02b3 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -536,7 +536,7 @@ StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, if (Cond.isInvalid()) return StmtError(); - if (IsConstexpr) + if (IsConstexpr || isa<ObjCAvailabilityCheckExpr>(Cond.get().second)) getCurFunction()->setHasBranchProtectedScope(); DiagnoseUnusedExprResult(thenStmt); @@ -1070,7 +1070,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, const EnumType *ET = CondTypeBeforePromotion->getAs<EnumType>(); // If switch has default case, then ignore it. - if (!CaseListIsErroneous && !HasConstantCond && ET) { + if (!CaseListIsErroneous && !HasConstantCond && ET && + ET->getDecl()->isCompleteDefinition()) { const EnumDecl *ED = ET->getDecl(); EnumValsTy EnumVals; @@ -3193,6 +3194,10 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { if (FD->isNoReturn()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD->getDeclName(); + if (FD->isMain() && RetValExp) + if (isa<CXXBoolLiteralExpr>(RetValExp)) + Diag(ReturnLoc, diag::warn_main_returns_bool_literal) + << RetValExp->getSourceRange(); } else if (ObjCMethodDecl *MD = getCurMethodDecl()) { FnRetType = MD->getReturnType(); isObjCMethod = true; @@ -3447,7 +3452,7 @@ StmtResult Sema::BuildObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw) { !ThrowType->isObjCObjectPointerType()) { const PointerType *PT = ThrowType->getAs<PointerType>(); if (!PT || !PT->getPointeeType()->isVoidType()) - return StmtError(Diag(AtLoc, diag::error_objc_throw_expects_object) + return StmtError(Diag(AtLoc, diag::err_objc_throw_expects_object) << Throw->getType() << Throw->getSourceRange()); } } @@ -3468,7 +3473,7 @@ Sema::ActOnObjCAtThrowStmt(SourceLocation AtLoc, Expr *Throw, while (AtCatchParent && !AtCatchParent->isAtCatchScope()) AtCatchParent = AtCatchParent->getParent(); if (!AtCatchParent) - return StmtError(Diag(AtLoc, diag::error_rethrow_used_outside_catch)); + return StmtError(Diag(AtLoc, diag::err_rethrow_used_outside_catch)); } return BuildObjCAtThrowStmt(AtLoc, Throw); } @@ -3489,17 +3494,19 @@ Sema::ActOnObjCAtSynchronizedOperand(SourceLocation atLoc, Expr *operand) { if (getLangOpts().CPlusPlus) { if (RequireCompleteType(atLoc, type, diag::err_incomplete_receiver_type)) - return Diag(atLoc, diag::error_objc_synchronized_expects_object) + return Diag(atLoc, diag::err_objc_synchronized_expects_object) << type << operand->getSourceRange(); ExprResult result = PerformContextuallyConvertToObjCPointer(operand); + if (result.isInvalid()) + return ExprError(); if (!result.isUsable()) - return Diag(atLoc, diag::error_objc_synchronized_expects_object) + return Diag(atLoc, diag::err_objc_synchronized_expects_object) << type << operand->getSourceRange(); operand = result.get(); } else { - return Diag(atLoc, diag::error_objc_synchronized_expects_object) + return Diag(atLoc, diag::err_objc_synchronized_expects_object) << type << operand->getSourceRange(); } } @@ -3644,6 +3651,11 @@ StmtResult Sema::ActOnCXXTryBlock(SourceLocation TryLoc, Stmt *TryBlock, !getSourceManager().isInSystemHeader(TryLoc)) Diag(TryLoc, diag::err_exceptions_disabled) << "try"; + // Exceptions aren't allowed in CUDA device code. + if (getLangOpts().CUDA) + CUDADiagIfDeviceCode(TryLoc, diag::err_cuda_device_exceptions) + << "try" << CurrentCUDATarget(); + if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope()) Diag(TryLoc, diag::err_omp_simd_region_cannot_use_stmt) << "try"; diff --git a/lib/Sema/SemaStmtAsm.cpp b/lib/Sema/SemaStmtAsm.cpp index cd4269cd7eae3..76de9e2993990 100644 --- a/lib/Sema/SemaStmtAsm.cpp +++ b/lib/Sema/SemaStmtAsm.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/TypeLoc.h" @@ -21,8 +20,9 @@ #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/BitVector.h" +#include "llvm/ADT/StringSet.h" #include "llvm/MC/MCParser/MCAsmParser.h" using namespace clang; using namespace sema; @@ -138,6 +138,56 @@ static bool checkExprMemoryConstraintCompat(Sema &S, Expr *E, return false; } +// Extracting the register name from the Expression value, +// if there is no register name to extract, returns "" +static StringRef extractRegisterName(const Expr *Expression, + const TargetInfo &Target) { + Expression = Expression->IgnoreImpCasts(); + if (const DeclRefExpr *AsmDeclRef = dyn_cast<DeclRefExpr>(Expression)) { + // Handle cases where the expression is a variable + const VarDecl *Variable = dyn_cast<VarDecl>(AsmDeclRef->getDecl()); + if (Variable && Variable->getStorageClass() == SC_Register) { + if (AsmLabelAttr *Attr = Variable->getAttr<AsmLabelAttr>()) + if (Target.isValidGCCRegisterName(Attr->getLabel())) + return Target.getNormalizedGCCRegisterName(Attr->getLabel(), true); + } + } + return ""; +} + +// Checks if there is a conflict between the input and output lists with the +// clobbers list. If there's a conflict, returns the location of the +// conflicted clobber, else returns nullptr +static SourceLocation +getClobberConflictLocation(MultiExprArg Exprs, StringLiteral **Constraints, + StringLiteral **Clobbers, int NumClobbers, + const TargetInfo &Target, ASTContext &Cont) { + llvm::StringSet<> InOutVars; + // Collect all the input and output registers from the extended asm + // statement in order to check for conflicts with the clobber list + for (unsigned int i = 0; i < Exprs.size(); ++i) { + StringRef Constraint = Constraints[i]->getString(); + StringRef InOutReg = Target.getConstraintRegister( + Constraint, extractRegisterName(Exprs[i], Target)); + if (InOutReg != "") + InOutVars.insert(InOutReg); + } + // Check for each item in the clobber list if it conflicts with the input + // or output + for (int i = 0; i < NumClobbers; ++i) { + StringRef Clobber = Clobbers[i]->getString(); + // We only check registers, therefore we don't check cc and memory + // clobbers + if (Clobber == "cc" || Clobber == "memory") + continue; + Clobber = Target.getNormalizedGCCRegisterName(Clobber, true); + // Go over the output's registers we collected + if (InOutVars.count(Clobber)) + return Clobbers[i]->getLocStart(); + } + return SourceLocation(); +} + StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, bool IsVolatile, unsigned NumOutputs, unsigned NumInputs, IdentifierInfo **Names, @@ -544,6 +594,13 @@ StmtResult Sema::ActOnGCCAsmStmt(SourceLocation AsmLoc, bool IsSimple, return StmtError(); } + // Check for conflicts between clobber list and input or output lists + SourceLocation ConstraintLoc = + getClobberConflictLocation(Exprs, Constraints, Clobbers, NumClobbers, + Context.getTargetInfo(), Context); + if (ConstraintLoc.isValid()) + return Diag(ConstraintLoc, diag::error_inoutput_conflict_with_clobber); + return NS; } @@ -751,17 +808,17 @@ LabelDecl *Sema::GetOrCreateMSAsmLabel(StringRef ExternalLabelName, // Otherwise, insert it, but only resolve it if we have seen the label itself. std::string InternalName; llvm::raw_string_ostream OS(InternalName); - // Create an internal name for the label. The name should not be a valid mangled - // name, and should be unique. We use a dot to make the name an invalid mangled - // name. - OS << "__MSASMLABEL_." << MSAsmLabelNameCounter++ << "__"; - for (auto it = ExternalLabelName.begin(); it != ExternalLabelName.end(); - ++it) { - OS << *it; - if (*it == '$') { - // We escape '$' in asm strings by replacing it with "$$" + // Create an internal name for the label. The name should not be a valid + // mangled name, and should be unique. We use a dot to make the name an + // invalid mangled name. We use LLVM's inline asm ${:uid} escape so that a + // unique label is generated each time this blob is emitted, even after + // inlining or LTO. + OS << "__MSASMLABEL_.${:uid}__"; + for (char C : ExternalLabelName) { + OS << C; + // We escape '$' in asm strings by replacing it with "$$" + if (C == '$') OS << '$'; - } } Label->setMSAsmLabel(OS.str()); } diff --git a/lib/Sema/SemaStmtAttr.cpp b/lib/Sema/SemaStmtAttr.cpp index 87fd889395723..01fa856132d7d 100644 --- a/lib/Sema/SemaStmtAttr.cpp +++ b/lib/Sema/SemaStmtAttr.cpp @@ -225,16 +225,12 @@ CheckForIncompatibleAttributes(Sema &S, static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range) { - // OpenCL v2.0 s6.11.5 - opencl_unroll_hint can have 0 arguments (compiler + // Although the feature was introduced only in OpenCL C v2.0 s6.11.5, it's + // useful for OpenCL 1.x too and doesn't require HW support. + // opencl_unroll_hint can have 0 arguments (compiler // determines unrolling factor) or 1 argument (the unroll factor provided // by the user). - if (S.getLangOpts().OpenCLVersion < 200) { - S.Diag(A.getLoc(), diag::err_attribute_requires_opencl_version) - << A.getName() << "2.0" << 1; - return nullptr; - } - unsigned NumArgs = A.getNumArgs(); if (NumArgs > 1) { diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 72e499342f8f1..facc5d1b375bd 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -88,14 +88,14 @@ static NamedDecl *isAcceptableTemplateName(ASTContext &Context, return nullptr; } -void Sema::FilterAcceptableTemplateNames(LookupResult &R, +void Sema::FilterAcceptableTemplateNames(LookupResult &R, bool AllowFunctionTemplates) { // The set of class templates we've already seen. llvm::SmallPtrSet<ClassTemplateDecl *, 8> ClassTemplates; LookupResult::Filter filter = R.makeFilter(); while (filter.hasNext()) { NamedDecl *Orig = filter.next(); - NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, + NamedDecl *Repl = isAcceptableTemplateName(Context, Orig, AllowFunctionTemplates); if (!Repl) filter.erase(); @@ -131,7 +131,7 @@ bool Sema::hasAnyAcceptableTemplateNames(LookupResult &R, for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) if (isAcceptableTemplateName(Context, *I, AllowFunctionTemplates)) return true; - + return false; } @@ -265,7 +265,7 @@ void Sema::LookupTemplateName(LookupResult &Found, assert((isDependent || !ObjectType->isIncompleteType() || ObjectType->castAs<TagType>()->isBeingDefined()) && "Caller should have completed object type"); - + // Template names cannot appear inside an Objective-C class or object type. if (ObjectType->isObjCObjectOrInterfaceType()) { Found.clear(); @@ -312,7 +312,7 @@ void Sema::LookupTemplateName(LookupResult &Found, } else { // Perform unqualified name lookup in the current scope. LookupName(Found, S); - + if (!ObjectType.isNull()) AllowFunctionTemplatesInLookup = false; } @@ -429,7 +429,12 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, bool MightBeCxx11UnevalField = getLangOpts().CPlusPlus11 && isUnevaluatedContext(); - if (!MightBeCxx11UnevalField && !isAddressOfOperand && + // Check if the nested name specifier is an enum type. + bool IsEnum = false; + if (NestedNameSpecifier *NNS = SS.getScopeRep()) + IsEnum = dyn_cast_or_null<EnumType>(NNS->getAsType()); + + if (!MightBeCxx11UnevalField && !isAddressOfOperand && !IsEnum && isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) { QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); @@ -456,6 +461,104 @@ Sema::BuildDependentDeclRefExpr(const CXXScopeSpec &SS, TemplateArgs); } + +/// Determine whether we would be unable to instantiate this template (because +/// it either has no definition, or is in the process of being instantiated). +bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation, + NamedDecl *Instantiation, + bool InstantiatedFromMember, + const NamedDecl *Pattern, + const NamedDecl *PatternDef, + TemplateSpecializationKind TSK, + bool Complain /*= true*/) { + assert(isa<TagDecl>(Instantiation) || isa<FunctionDecl>(Instantiation) || + isa<VarDecl>(Instantiation)); + + bool IsEntityBeingDefined = false; + if (const TagDecl *TD = dyn_cast_or_null<TagDecl>(PatternDef)) + IsEntityBeingDefined = TD->isBeingDefined(); + + if (PatternDef && !IsEntityBeingDefined) { + NamedDecl *SuggestedDef = nullptr; + if (!hasVisibleDefinition(const_cast<NamedDecl*>(PatternDef), &SuggestedDef, + /*OnlyNeedComplete*/false)) { + // If we're allowed to diagnose this and recover, do so. + bool Recover = Complain && !isSFINAEContext(); + if (Complain) + diagnoseMissingImport(PointOfInstantiation, SuggestedDef, + Sema::MissingImportKind::Definition, Recover); + return !Recover; + } + return false; + } + + if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) + return true; + + llvm::Optional<unsigned> Note; + QualType InstantiationTy; + if (TagDecl *TD = dyn_cast<TagDecl>(Instantiation)) + InstantiationTy = Context.getTypeDeclType(TD); + if (PatternDef) { + Diag(PointOfInstantiation, + diag::err_template_instantiate_within_definition) + << /*implicit|explicit*/(TSK != TSK_ImplicitInstantiation) + << InstantiationTy; + // Not much point in noting the template declaration here, since + // we're lexically inside it. + Instantiation->setInvalidDecl(); + } else if (InstantiatedFromMember) { + if (isa<FunctionDecl>(Instantiation)) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << /*member function*/ 1 << Instantiation->getDeclName() + << Instantiation->getDeclContext(); + Note = diag::note_explicit_instantiation_here; + } else { + assert(isa<TagDecl>(Instantiation) && "Must be a TagDecl!"); + Diag(PointOfInstantiation, + diag::err_implicit_instantiate_member_undefined) + << InstantiationTy; + Note = diag::note_member_declared_at; + } + } else { + if (isa<FunctionDecl>(Instantiation)) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_func_template) + << Pattern; + Note = diag::note_explicit_instantiation_here; + } else if (isa<TagDecl>(Instantiation)) { + Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) + << (TSK != TSK_ImplicitInstantiation) + << InstantiationTy; + Note = diag::note_template_decl_here; + } else { + assert(isa<VarDecl>(Instantiation) && "Must be a VarDecl!"); + if (isa<VarTemplateSpecializationDecl>(Instantiation)) { + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_var_template) + << Instantiation; + Instantiation->setInvalidDecl(); + } else + Diag(PointOfInstantiation, + diag::err_explicit_instantiation_undefined_member) + << /*static data member*/ 2 << Instantiation->getDeclName() + << Instantiation->getDeclContext(); + Note = diag::note_explicit_instantiation_here; + } + } + if (Note) // Diagnostics were emitted. + Diag(Pattern->getLocation(), Note.getValue()); + + // In general, Instantiation isn't marked invalid to get more than one + // error for multiple undefined instantiations. But the code that does + // explicit declaration -> explicit definition conversion can't handle + // invalid declarations, so mark as invalid in that case. + if (TSK == TSK_ExplicitInstantiationDeclaration) + Instantiation->setInvalidDecl(); + return true; +} + /// DiagnoseTemplateParameterShadow - Produce a diagnostic complaining /// that the template parameter 'PrevDecl' is being shadowed by a new /// declaration at location Loc. Returns true to indicate that this is @@ -626,8 +729,22 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, /// /// \returns the (possibly-promoted) parameter type if valid; /// otherwise, produces a diagnostic and returns a NULL type. -QualType -Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { +QualType Sema::CheckNonTypeTemplateParameterType(TypeSourceInfo *&TSI, + SourceLocation Loc) { + if (TSI->getType()->isUndeducedType()) { + // C++1z [temp.dep.expr]p3: + // An id-expression is type-dependent if it contains + // - an identifier associated by name lookup with a non-type + // template-parameter declared with a type that contains a + // placeholder type (7.1.7.4), + TSI = SubstAutoTypeSourceInfo(TSI, Context.DependentTy); + } + + return CheckNonTypeTemplateParameterType(TSI->getType(), Loc); +} + +QualType Sema::CheckNonTypeTemplateParameterType(QualType T, + SourceLocation Loc) { // We don't allow variably-modified types as the type of non-type template // parameters. if (T->isVariablyModifiedType()) { @@ -653,7 +770,9 @@ Sema::CheckNonTypeTemplateParameterType(QualType T, SourceLocation Loc) { T->isNullPtrType() || // If T is a dependent type, we can't do the check now, so we // assume that it is well-formed. - T->isDependentType()) { + T->isDependentType() || + // Allow use of auto in template parameter declarations. + T->isUndeducedType()) { // C++ [temp.param]p5: The top-level cv-qualifiers on the template-parameter // are ignored when determining its type. return T.getUnqualifiedType(); @@ -679,13 +798,18 @@ Decl *Sema::ActOnNonTypeTemplateParameter(Scope *S, Declarator &D, SourceLocation EqualLoc, Expr *Default) { TypeSourceInfo *TInfo = GetTypeForDeclarator(D, S); - QualType T = TInfo->getType(); + + if (TInfo->getType()->isUndeducedType()) { + Diag(D.getIdentifierLoc(), + diag::warn_cxx14_compat_template_nontype_parm_auto_type) + << QualType(TInfo->getType()->getContainedAutoType(), 0); + } assert(S->isTemplateParamScope() && "Non-type template parameter not in template parameter scope!"); bool Invalid = false; - T = CheckNonTypeTemplateParameterType(T, D.getIdentifierLoc()); + QualType T = CheckNonTypeTemplateParameterType(TInfo, D.getIdentifierLoc()); if (T.isNull()) { T = Context.IntTy; // Recover with an 'int' type. Invalid = true; @@ -766,7 +890,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, Depth, Position, IsParameterPack, Name, Params); Param->setAccess(AS_public); - + // If the template template parameter has a name, then link the identifier // into the scope and lookup mechanisms. if (Name) { @@ -832,11 +956,10 @@ Sema::ActOnTemplateParameterList(unsigned Depth, if (ExportLoc.isValid()) Diag(ExportLoc, diag::warn_template_export_unsupported); - // FIXME: store RequiresClause return TemplateParameterList::Create( Context, TemplateLoc, LAngleLoc, llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()), - RAngleLoc); + RAngleLoc, RequiresClause); } static void SetNestedNameSpecifier(TagDecl *T, const CXXScopeSpec &SS) { @@ -897,8 +1020,8 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (RequireCompleteDeclContext(SS, SemanticContext)) return true; - // If we're adding a template to a dependent context, we may need to - // rebuilding some of the types used within the template parameter list, + // If we're adding a template to a dependent context, we may need to + // rebuilding some of the types used within the template parameter list, // now that we know what the current instantiation is. if (SemanticContext->isDependentContext()) { ContextRAII SavedContext(*this, SemanticContext); @@ -1124,10 +1247,10 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, DeclarationName(Name), TemplateParams, NewClass, PrevClassTemplate); NewClass->setDescribedClassTemplate(NewTemplate); - + if (ModulePrivateLoc.isValid()) NewTemplate->setModulePrivate(); - + // Build the type for the class template declaration now. QualType T = NewTemplate->getInjectedClassNameSpecialization(); T = Context.getInjectedClassNameType(NewClass, T); @@ -1218,7 +1341,7 @@ static bool DiagnoseDefaultTemplateArgument(Sema &S, // A default template-argument shall not be specified in a // function template declaration or a function template // definition [...] - // If a friend function template declaration specifies a default + // If a friend function template declaration specifies a default // template-argument, that declaration shall be a definition and shall be // the only declaration of the function template in the translation unit. // (C++98/03 doesn't have this wording; see DR226). @@ -1530,12 +1653,22 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { typedef RecursiveASTVisitor<DependencyChecker> super; unsigned Depth; + + // Whether we're looking for a use of a template parameter that makes the + // overall construct type-dependent / a dependent type. This is strictly + // best-effort for now; we may fail to match at all for a dependent type + // in some cases if this is set. + bool IgnoreNonTypeDependent; + bool Match; SourceLocation MatchLoc; - DependencyChecker(unsigned Depth) : Depth(Depth), Match(false) {} + DependencyChecker(unsigned Depth, bool IgnoreNonTypeDependent) + : Depth(Depth), IgnoreNonTypeDependent(IgnoreNonTypeDependent), + Match(false) {} - DependencyChecker(TemplateParameterList *Params) : Match(false) { + DependencyChecker(TemplateParameterList *Params, bool IgnoreNonTypeDependent) + : IgnoreNonTypeDependent(IgnoreNonTypeDependent), Match(false) { NamedDecl *ND = Params->getParam(0); if (TemplateTypeParmDecl *PD = dyn_cast<TemplateTypeParmDecl>(ND)) { Depth = PD->getDepth(); @@ -1556,12 +1689,31 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { return false; } + bool TraverseStmt(Stmt *S, DataRecursionQueue *Q = nullptr) { + // Prune out non-type-dependent expressions if requested. This can + // sometimes result in us failing to find a template parameter reference + // (if a value-dependent expression creates a dependent type), but this + // mode is best-effort only. + if (auto *E = dyn_cast_or_null<Expr>(S)) + if (IgnoreNonTypeDependent && !E->isTypeDependent()) + return true; + return super::TraverseStmt(S, Q); + } + + bool TraverseTypeLoc(TypeLoc TL) { + if (IgnoreNonTypeDependent && !TL.isNull() && + !TL.getType()->isDependentType()) + return true; + return super::TraverseTypeLoc(TL); + } + bool VisitTemplateTypeParmTypeLoc(TemplateTypeParmTypeLoc TL) { return !Matches(TL.getTypePtr()->getDepth(), TL.getNameLoc()); } bool VisitTemplateTypeParmType(const TemplateTypeParmType *T) { - return !Matches(T->getDepth()); + // For a best-effort search, keep looking until we find a location. + return IgnoreNonTypeDependent || !Matches(T->getDepth()); } bool TraverseTemplateName(TemplateName N) { @@ -1599,7 +1751,7 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { /// list. static bool DependsOnTemplateParameters(QualType T, TemplateParameterList *Params) { - DependencyChecker Checker(Params); + DependencyChecker Checker(Params, /*IgnoreNonTypeDependent*/false); Checker.TraverseType(T); return Checker.Match; } @@ -1616,10 +1768,10 @@ static SourceRange getRangeOfTypeInNestedNameSpecifier(ASTContext &Context, return NNSLoc.getTypeLoc().getSourceRange(); } else break; - + NNSLoc = NNSLoc.getPrefix(); } - + return SourceRange(); } @@ -1662,34 +1814,34 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( bool &IsExplicitSpecialization, bool &Invalid) { IsExplicitSpecialization = false; Invalid = false; - + // The sequence of nested types to which we will match up the template // parameter lists. We first build this list by starting with the type named // by the nested-name-specifier and walking out until we run out of types. SmallVector<QualType, 4> NestedTypes; QualType T; if (SS.getScopeRep()) { - if (CXXRecordDecl *Record + if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(computeDeclContext(SS, true))) T = Context.getTypeDeclType(Record); else T = QualType(SS.getScopeRep()->getAsType(), 0); } - + // If we found an explicit specialization that prevents us from needing // 'template<>' headers, this will be set to the location of that // explicit specialization. SourceLocation ExplicitSpecLoc; - + while (!T.isNull()) { NestedTypes.push_back(T); - + // Retrieve the parent of a record type. if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { // If this type is an explicit specialization, we're done. if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { - if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && + if (!isa<ClassTemplatePartialSpecializationDecl>(Spec) && Spec->getSpecializationKind() == TSK_ExplicitSpecialization) { ExplicitSpecLoc = Spec->getLocation(); break; @@ -1699,14 +1851,14 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( ExplicitSpecLoc = Record->getLocation(); break; } - + if (TypeDecl *Parent = dyn_cast<TypeDecl>(Record->getParent())) T = Context.getTypeDeclType(Parent); else T = QualType(); continue; - } - + } + if (const TemplateSpecializationType *TST = T->getAs<TemplateSpecializationType>()) { if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { @@ -1714,10 +1866,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( T = Context.getTypeDeclType(Parent); else T = QualType(); - continue; + continue; } } - + // Look one step prior in a dependent template specialization type. if (const DependentTemplateSpecializationType *DependentTST = T->getAs<DependentTemplateSpecializationType>()) { @@ -1727,7 +1879,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( T = QualType(); continue; } - + // Look one step prior in a dependent name type. if (const DependentNameType *DependentName = T->getAs<DependentNameType>()){ if (NestedNameSpecifier *NNS = DependentName->getQualifier()) @@ -1736,18 +1888,18 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( T = QualType(); continue; } - + // Retrieve the parent of an enumeration type. if (const EnumType *EnumT = T->getAs<EnumType>()) { // FIXME: Forward-declared enums require a TSK_ExplicitSpecialization // check here. EnumDecl *Enum = EnumT->getDecl(); - + // Get to the parent type. if (TypeDecl *Parent = dyn_cast<TypeDecl>(Enum->getParent())) T = Context.getTypeDeclType(Parent); else - T = QualType(); + T = QualType(); continue; } @@ -1799,21 +1951,21 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( for (unsigned TypeIdx = 0, NumTypes = NestedTypes.size(); TypeIdx != NumTypes; ++TypeIdx) { T = NestedTypes[TypeIdx]; - + // Whether we expect a 'template<>' header. bool NeedEmptyTemplateHeader = false; // Whether we expect a template header with parameters. bool NeedNonemptyTemplateHeader = false; - + // For a dependent type, the set of template parameters that we // expect to see. TemplateParameterList *ExpectedTemplateParams = nullptr; // C++0x [temp.expl.spec]p15: - // A member or a member template may be nested within many enclosing - // class templates. In an explicit specialization for such a member, the - // member declaration shall be preceded by a template<> for each + // A member or a member template may be nested within many enclosing + // class templates. In an explicit specialization for such a member, the + // member declaration shall be preceded by a template<> for each // enclosing class template that is explicitly specialized. if (CXXRecordDecl *Record = T->getAsCXXRecordDecl()) { if (ClassTemplatePartialSpecializationDecl *Partial @@ -1830,38 +1982,38 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( = dyn_cast<ClassTemplateSpecializationDecl>(Record)) { // C++0x [temp.expl.spec]p4: // Members of an explicitly specialized class template are defined - // in the same manner as members of normal classes, and not using - // the template<> syntax. + // in the same manner as members of normal classes, and not using + // the template<> syntax. if (Spec->getSpecializationKind() != TSK_ExplicitSpecialization) NeedEmptyTemplateHeader = true; else continue; } else if (Record->getTemplateSpecializationKind()) { - if (Record->getTemplateSpecializationKind() + if (Record->getTemplateSpecializationKind() != TSK_ExplicitSpecialization && TypeIdx == NumTypes - 1) IsExplicitSpecialization = true; - + continue; } } else if (const TemplateSpecializationType *TST = T->getAs<TemplateSpecializationType>()) { if (TemplateDecl *Template = TST->getTemplateName().getAsTemplateDecl()) { ExpectedTemplateParams = Template->getTemplateParameters(); - NeedNonemptyTemplateHeader = true; + NeedNonemptyTemplateHeader = true; } } else if (T->getAs<DependentTemplateSpecializationType>()) { // FIXME: We actually could/should check the template arguments here // against the corresponding template parameter list. NeedNonemptyTemplateHeader = false; - } - + } + // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates // are not explicitly specialized as well. if (ParamIdx < ParamLists.size()) { if (ParamLists[ParamIdx]->size() == 0) { @@ -1871,7 +2023,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( } else SawNonEmptyTemplateParameterList = true; } - + if (NeedEmptyTemplateHeader) { // If we're on the last of the types, and we need a 'template<>' header // here, then it's an explicit specialization. @@ -1881,7 +2033,7 @@ 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(ParamLists[ParamIdx]->getTemplateLoc(), diag::err_template_param_list_matches_nontemplate) << T << SourceRange(ParamLists[ParamIdx]->getLAngleLoc(), @@ -1913,7 +2065,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( if (ParamIdx < ParamLists.size() && DependsOnTemplateParameters(T, ParamLists[ParamIdx])) ExpectedTemplateParams = nullptr; - else + else continue; } @@ -1929,11 +2081,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( CheckTemplateParameterList(ParamLists[ParamIdx], nullptr, TPC_ClassTemplateMember)) Invalid = true; - + ++ParamIdx; continue; } - + Diag(DeclLoc, diag::err_template_spec_needs_template_parameters) << T << getRangeOfTypeInNestedNameSpecifier(Context, T, SS); @@ -1956,7 +2108,7 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // Fabricate an empty template parameter list for the invented header. return TemplateParameterList::Create(Context, SourceLocation(), SourceLocation(), None, - SourceLocation()); + SourceLocation(), nullptr); } return nullptr; @@ -1983,10 +2135,10 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( // not required, and there were any 'template<>' headers, note where the // specialization occurred. if (ExplicitSpecLoc.isValid() && HasAnyExplicitSpecHeader) - Diag(ExplicitSpecLoc, + Diag(ExplicitSpecLoc, diag::note_explicit_template_spec_does_not_need_header) << NestedTypes.back(); - + // We have a template parameter list with no corresponding scope, which // means that the resulting template declaration can't be instantiated // properly (we'll end up with dependent nodes when we shouldn't). @@ -1995,11 +2147,11 @@ TemplateParameterList *Sema::MatchTemplateParametersToScopeSpecifier( } // C++ [temp.expl.spec]p16: - // In an explicit specialization declaration for a member of a class - // template or a member template that ap- pears in namespace scope, the - // member template and some of its enclosing class templates may remain - // unspecialized, except that the declaration shall not explicitly - // specialize a class member template if its en- closing class templates + // In an explicit specialization declaration for a member of a class + // template or a member template that ap- pears in namespace scope, the + // member template and some of its enclosing class templates may remain + // unspecialized, except that the declaration shall not explicitly + // specialize a class member template if its en- closing class templates // are not explicitly specialized as well. if (ParamLists.back()->size() == 0 && CheckExplicitSpecialization(ParamLists[ParamIdx]->getSourceRange(), @@ -2024,14 +2176,14 @@ void Sema::NoteAllFoundTemplates(TemplateName Name) { << Template->getDeclName(); return; } - + if (OverloadedTemplateStorage *OST = Name.getAsOverloadedTemplate()) { - for (OverloadedTemplateStorage::iterator I = OST->begin(), + for (OverloadedTemplateStorage::iterator I = OST->begin(), IEnd = OST->end(); I != IEnd; ++I) Diag((*I)->getLocation(), diag::note_template_declared_here) << 0 << (*I)->getDeclName(); - + return; } } @@ -2074,11 +2226,8 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, for (llvm::APSInt I(NumArgs.getBitWidth(), NumArgs.isUnsigned()); I < NumArgs; ++I) { TemplateArgument TA(Context, I, ArgTy); - Expr *E = SemaRef.BuildExpressionFromIntegralTemplateArgument( - TA, TemplateArgs[2].getLocation()) - .getAs<Expr>(); - SyntheticTemplateArgs.addArgument( - TemplateArgumentLoc(TemplateArgument(E), E)); + SyntheticTemplateArgs.addArgument(SemaRef.getTrivialTemplateArgumentLoc( + TA, ArgTy, TemplateArgs[2].getLocation())); } // The first template argument will be reused as the template decl that // our synthetic template arguments will be applied to. @@ -2310,7 +2459,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, TLB.getTypeSourceInfo(Context, T)); } - + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) @@ -2337,7 +2486,7 @@ Sema::ActOnTemplateIdType(CXXScopeSpec &SS, SourceLocation TemplateKWLoc, ElabTL.setElaboratedKeywordLoc(SourceLocation()); ElabTL.setQualifierLoc(SS.getWithLocInContext(Context)); } - + return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } @@ -2352,11 +2501,11 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, ASTTemplateArgsPtr TemplateArgsIn, SourceLocation RAngleLoc) { TemplateName Template = TemplateD.get(); - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - + // Determine the tag kind TagTypeKind TagKind = TypeWithKeyword::getTagTypeKindForTypeSpec(TagSpec); ElaboratedTypeKeyword Keyword @@ -2364,11 +2513,11 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { QualType T = Context.getDependentTemplateSpecializationType(Keyword, - DTN->getQualifier(), - DTN->getIdentifier(), + DTN->getQualifier(), + DTN->getIdentifier(), TemplateArgs); - - // Build type-source information. + + // Build type-source information. TypeLocBuilder TLB; DependentTemplateSpecializationTypeLoc SpecTL = TLB.push<DependentTemplateSpecializationTypeLoc>(T); @@ -2389,21 +2538,22 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, // If the identifier resolves to a typedef-name or the simple-template-id // resolves to an alias template specialization, the // elaborated-type-specifier is ill-formed. - Diag(TemplateLoc, diag::err_tag_reference_non_tag) << 4; + Diag(TemplateLoc, diag::err_tag_reference_non_tag) + << TAT << NTK_TypeAliasTemplate << TagKind; Diag(TAT->getLocation(), diag::note_declared_at); } - + QualType Result = CheckTemplateIdType(Template, TemplateLoc, TemplateArgs); if (Result.isNull()) return TypeResult(true); - + // Check the tag kind if (const RecordType *RT = Result->getAs<RecordType>()) { RecordDecl *D = RT->getDecl(); - + IdentifierInfo *Id = D->getIdentifier(); assert(Id && "templated class must have an identifier"); - + if (!isAcceptableTagRedeclaration(D, TagKind, TUK == TUK_Definition, TagLoc, Id)) { Diag(TagLoc, diag::err_use_with_wrong_tag) @@ -2433,10 +2583,6 @@ TypeResult Sema::ActOnTagTemplateIdType(TagUseKind TUK, return CreateParsedType(Result, TLB.getTypeSourceInfo(Context, Result)); } -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation NameLoc, TemplateParameterList *TemplateParams, - unsigned ExplicitArgs, SmallVectorImpl<TemplateArgument> &TemplateArgs); - static bool CheckTemplateSpecializationScope(Sema &S, NamedDecl *Specialized, NamedDecl *PrevDecl, SourceLocation Loc, @@ -2518,6 +2664,89 @@ makeTemplateArgumentListInfo(Sema &S, TemplateIdAnnotation &TemplateId) { return TemplateArgs; } +template<typename PartialSpecDecl> +static void checkMoreSpecializedThanPrimary(Sema &S, PartialSpecDecl *Partial) { + if (Partial->getDeclContext()->isDependentContext()) + return; + + // FIXME: Get the TDK from deduction in order to provide better diagnostics + // for non-substitution-failure issues? + TemplateDeductionInfo Info(Partial->getLocation()); + if (S.isMoreSpecializedThanPrimary(Partial, Info)) + return; + + auto *Template = Partial->getSpecializedTemplate(); + S.Diag(Partial->getLocation(), + diag::ext_partial_spec_not_more_specialized_than_primary) + << isa<VarTemplateDecl>(Template); + + if (Info.hasSFINAEDiagnostic()) { + PartialDiagnosticAt Diag = {SourceLocation(), + PartialDiagnostic::NullDiagnostic()}; + Info.takeSFINAEDiagnostic(Diag); + SmallString<128> SFINAEArgString; + Diag.second.EmitToString(S.getDiagnostics(), SFINAEArgString); + S.Diag(Diag.first, + diag::note_partial_spec_not_more_specialized_than_primary) + << SFINAEArgString; + } + + S.Diag(Template->getLocation(), diag::note_template_decl_here); +} + +template<typename PartialSpecDecl> +static void checkTemplatePartialSpecialization(Sema &S, + PartialSpecDecl *Partial) { + // C++1z [temp.class.spec]p8: (DR1495) + // - The specialization shall be more specialized than the primary + // template (14.5.5.2). + checkMoreSpecializedThanPrimary(S, Partial); + + // C++ [temp.class.spec]p8: (DR1315) + // - Each template-parameter shall appear at least once in the + // template-id outside a non-deduced context. + // C++1z [temp.class.spec.match]p3 (P0127R2) + // If the template arguments of a partial specialization cannot be + // deduced because of the structure of its template-parameter-list + // and the template-id, the program is ill-formed. + auto *TemplateParams = Partial->getTemplateParameters(); + llvm::SmallBitVector DeducibleParams(TemplateParams->size()); + S.MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, + TemplateParams->getDepth(), DeducibleParams); + + if (!DeducibleParams.all()) { + unsigned NumNonDeducible = DeducibleParams.size() - DeducibleParams.count(); + S.Diag(Partial->getLocation(), diag::ext_partial_specs_not_deducible) + << isa<VarTemplatePartialSpecializationDecl>(Partial) + << (NumNonDeducible > 1) + << SourceRange(Partial->getLocation(), + Partial->getTemplateArgsAsWritten()->RAngleLoc); + for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { + if (!DeducibleParams[I]) { + NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); + if (Param->getDeclName()) + S.Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << Param->getDeclName(); + else + S.Diag(Param->getLocation(), + diag::note_partial_spec_unused_parameter) + << "(anonymous)"; + } + } + } +} + +void Sema::CheckTemplatePartialSpecialization( + ClassTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + +void Sema::CheckTemplatePartialSpecialization( + VarTemplatePartialSpecializationDecl *Partial) { + checkTemplatePartialSpecialization(*this, Partial); +} + DeclResult Sema::ActOnVarTemplateSpecialization( Scope *S, Declarator &D, TypeSourceInfo *DI, SourceLocation TemplateKWLoc, TemplateParameterList *TemplateParams, StorageClass SC, @@ -2567,11 +2796,12 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // Find the variable template (partial) specialization declaration that // corresponds to these arguments. if (IsPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, VarTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, VarTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move these checks to CheckTemplatePartialSpecializationArgs so we + // also do them during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -2643,32 +2873,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - // Check that all of the template parameters of the variable template - // partial specialization are deducible from the template - // arguments. If not, this variable template partial specialization - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = - DeducibleParams.size() - DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*variable template*/ 1 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -2890,12 +3095,10 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, << Decl; // Print the matching partial specializations. - for (SmallVector<MatchResult, 4>::iterator P = Matched.begin(), - PEnd = Matched.end(); - P != PEnd; ++P) - Diag(P->Partial->getLocation(), diag::note_partial_spec_match) - << getTemplateArgumentBindingsText( - P->Partial->getTemplateParameters(), *P->Args); + for (MatchResult P : Matched) + Diag(P.Partial->getLocation(), diag::note_partial_spec_match) + << getTemplateArgumentBindingsText(P.Partial->getTemplateParameters(), + *P.Args); return true; } @@ -3206,7 +3409,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, // Add the converted template type argument. ArgType = Context.getCanonicalType(ArgType); - + // Objective-C ARC: // If an explicitly-specified template argument type is a lifetime type // with no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -3217,7 +3420,7 @@ bool Sema::CheckTemplateTypeArgument(TemplateTypeParmDecl *Param, Qs.setObjCLifetime(Qualifiers::OCL_Strong); ArgType = Context.getQualifiedType(ArgType, Qs); } - + Converted.push_back(TemplateArgument(ArgType)); return false; } @@ -3347,7 +3550,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, /// \param Converted the list of template arguments provided for template /// parameters that precede \p Param in the template parameter list. /// -/// \param QualifierLoc Will be set to the nested-name-specifier (with +/// \param QualifierLoc Will be set to the nested-name-specifier (with /// source-location information) that precedes the template name. /// /// \returns the substituted template argument, or NULL if an error occurred. @@ -3698,7 +3901,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return false; } -/// \brief Diagnose an arity mismatch in the +/// \brief Diagnose an arity mismatch in the static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, SourceLocation TemplateLoc, TemplateArgumentListInfo &TemplateArgs) { @@ -3708,7 +3911,7 @@ static bool diagnoseArityMismatch(Sema &S, TemplateDecl *Template, SourceRange Range; if (NumArgs > NumParams) - Range = SourceRange(TemplateArgs[NumParams].getLocation(), + Range = SourceRange(TemplateArgs[NumParams].getLocation(), TemplateArgs.getRAngleLoc()); S.Diag(TemplateLoc, diag::err_template_arg_list_different_arity) << (NumArgs > NumParams) @@ -4332,20 +4535,20 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, if (!S.getLangOpts().CPlusPlus11) return NPV_NotNullPointer; - + // Determine whether we have a constant expression. ExprResult ArgRV = S.DefaultFunctionArrayConversion(Arg); if (ArgRV.isInvalid()) return NPV_Error; Arg = ArgRV.get(); - + Expr::EvalResult EvalResult; SmallVector<PartialDiagnosticAt, 8> Notes; EvalResult.Diag = &Notes; if (!Arg->EvaluateAsRValue(EvalResult, S.Context) || EvalResult.HasSideEffects) { SourceLocation DiagLoc = Arg->getExprLoc(); - + // If our only note is the usual "invalid subexpression" note, just point // the caret at its location rather than producing an essentially // redundant note. @@ -4354,21 +4557,21 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, DiagLoc = Notes[0].first; Notes.clear(); } - + S.Diag(DiagLoc, diag::err_template_arg_not_address_constant) << Arg->getType() << Arg->getSourceRange(); for (unsigned I = 0, N = Notes.size(); I != N; ++I) S.Diag(Notes[I].first, Notes[I].second); - + S.Diag(Param->getLocation(), diag::note_template_param_here); return NPV_Error; } - + // C++11 [temp.arg.nontype]p1: // - an address constant expression of type std::nullptr_t if (Arg->getType()->isNullPtrType()) return NPV_NullPointer; - + // - a constant expression that evaluates to a null pointer value (4.10); or // - a constant expression that evaluates to a null member pointer value // (4.11); or @@ -4381,7 +4584,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, S.IsQualificationConversion(Arg->getType(), ParamType, false, ObjCLifetimeConversion)) return NPV_NullPointer; - + // The types didn't match, but we know we got a null pointer; complain, // then recover as if the types were correct. S.Diag(Arg->getExprLoc(), diag::err_template_arg_wrongtype_null_constant) @@ -4401,7 +4604,7 @@ isNullPointerValueTemplateArgument(Sema &S, NonTypeTemplateParmDecl *Param, S.Diag(Param->getLocation(), diag::note_template_param_here); return NPV_NullPointer; } - + // FIXME: If we ever want to support general, address-constant expressions // as non-type template arguments, we should return the ExprResult here to // be interpreted by the caller. @@ -4902,12 +5105,33 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, CheckTemplateArgumentKind CTAK) { SourceLocation StartLoc = Arg->getLocStart(); - // If either the parameter has a dependent type or the argument is - // type-dependent, there's nothing we can check now. - if (ParamType->isDependentType() || Arg->isTypeDependent()) { - // FIXME: Produce a cloned, canonical expression? - Converted = TemplateArgument(Arg); - return Arg; + // If the parameter type somehow involves auto, deduce the type now. + if (getLangOpts().CPlusPlus1z && ParamType->isUndeducedType()) { + // When checking a deduced template argument, deduce from its type even if + // the type is dependent, in order to check the types of non-type template + // arguments line up properly in partial ordering. + Optional<unsigned> Depth; + if (CTAK != CTAK_Specified) + Depth = Param->getDepth() + 1; + if (DeduceAutoType( + Context.getTrivialTypeSourceInfo(ParamType, Param->getLocation()), + Arg, ParamType, Depth) == DAR_Failed) { + Diag(Arg->getExprLoc(), + diag::err_non_type_template_parm_type_deduction_failure) + << Param->getDeclName() << Param->getType() << Arg->getType() + << Arg->getSourceRange(); + Diag(Param->getLocation(), diag::note_template_param_here); + return ExprError(); + } + // CheckNonTypeTemplateParameterType will produce a diagnostic if there's + // an error. The error message normally references the parameter + // declaration, but here we'll pass the argument location because that's + // where the parameter type is deduced. + ParamType = CheckNonTypeTemplateParameterType(ParamType, Arg->getExprLoc()); + if (ParamType.isNull()) { + Diag(Param->getLocation(), diag::note_template_param_here); + return ExprError(); + } } // We should have already dropped all cv-qualifiers by now. @@ -4915,30 +5139,36 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, "non-type template parameter type cannot be qualified"); if (CTAK == CTAK_Deduced && - !Context.hasSameUnqualifiedType(ParamType, Arg->getType())) { - // C++ [temp.deduct.type]p17: - // If, in the declaration of a function template with a non-type - // template-parameter, the non-type template-parameter is used - // in an expression in the function parameter-list and, if the - // corresponding template-argument is deduced, the - // template-argument type shall match the type of the - // template-parameter exactly, except that a template-argument - // deduced from an array bound may be of any integral type. + !Context.hasSameType(ParamType.getNonLValueExprType(Context), + Arg->getType())) { + // C++ [temp.deduct.type]p17: (DR1770) + // If P has a form that contains <i>, and if the type of i differs from + // the type of the corresponding template parameter of the template named + // by the enclosing simple-template-id, deduction fails. + // + // Note that CTAK will be CTAK_DeducedFromArrayBound if the form was [i] + // rather than <i>. + // + // FIXME: We interpret the 'i' here as referring to the expression + // denoting the non-type template parameter rather than the parameter + // itself, and so strip off references before comparing types. It's + // not clear how this is supposed to work for references. Diag(StartLoc, diag::err_deduced_non_type_template_arg_type_mismatch) - << Arg->getType().getUnqualifiedType() + << Arg->getType() << ParamType.getUnqualifiedType(); Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); } - if (getLangOpts().CPlusPlus1z) { - // FIXME: We can do some limited checking for a value-dependent but not - // type-dependent argument. - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - return Arg; - } + // If either the parameter has a dependent type or the argument is + // type-dependent, there's nothing we can check now. + if (ParamType->isDependentType() || Arg->isTypeDependent()) { + // FIXME: Produce a cloned, canonical expression? + Converted = TemplateArgument(Arg); + return Arg; + } + if (getLangOpts().CPlusPlus1z) { // C++1z [temp.arg.nontype]p1: // A template-argument for a non-type template parameter shall be // a converted constant expression of the type of the template-parameter. @@ -4948,6 +5178,13 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (ArgResult.isInvalid()) return ExprError(); + // For a value-dependent argument, CheckConvertedConstantExpression is + // permitted (and expected) to be unable to determine a value. + if (ArgResult.get()->isValueDependent()) { + Converted = TemplateArgument(ArgResult.get()); + return ArgResult; + } + QualType CanonParamType = Context.getCanonicalType(ParamType); // Convert the APValue to a TemplateArgument. @@ -5052,14 +5289,6 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, // conversions (4.7) are applied. if (getLangOpts().CPlusPlus11) { - // We can't check arbitrary value-dependent arguments. - // FIXME: If there's no viable conversion to the template parameter type, - // we should be able to diagnose that prior to instantiation. - if (Arg->isValueDependent()) { - Converted = TemplateArgument(Arg); - return Arg; - } - // C++ [temp.arg.nontype]p1: // A template-argument for a non-type, non-template template-parameter // shall be one of: @@ -5074,6 +5303,12 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, if (ArgResult.isInvalid()) return ExprError(); + // We can't check arbitrary value-dependent arguments. + if (ArgResult.get()->isValueDependent()) { + Converted = TemplateArgument(ArgResult.get()); + return ArgResult; + } + // Widen the argument value to sizeof(parameter type). This is almost // always a no-op, except when the parameter type is bool. In // that case, this may extend the argument from 1 bit to 8 bits. @@ -5112,7 +5347,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } else if (!Arg->isValueDependent()) { class TmplArgICEDiagnoser : public VerifyICEDiagnoser { QualType T; - + public: TmplArgICEDiagnoser(QualType T) : T(T) { } @@ -5174,14 +5409,14 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); } else { llvm::APSInt OldValue = Value; - + // Coerce the template argument's value to the value it will have // based on the template parameter's type. unsigned AllowedBits = Context.getTypeSize(IntegerType); if (Value.getBitWidth() != AllowedBits) Value = Value.extOrTrunc(AllowedBits); Value.setIsSigned(IntegerType->isSignedIntegerOrEnumerationType()); - + // Complain if an unsigned parameter received a negative value. if (IntegerType->isUnsignedIntegerOrEnumerationType() && (OldValue.isSigned() && OldValue.isNegative())) { @@ -5190,7 +5425,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, << Arg->getSourceRange(); Diag(Param->getLocation(), diag::note_template_param_here); } - + // Complain if we overflowed the template parameter's type. unsigned RequiredBits; if (IntegerType->isUnsignedIntegerOrEnumerationType()) @@ -5209,7 +5444,7 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, } Converted = TemplateArgument(Context, Value, - ParamType->isEnumeralType() + ParamType->isEnumeralType() ? Context.getCanonicalType(ParamType) : IntegerType); return Arg; @@ -5321,17 +5556,17 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, Converted = TemplateArgument(Arg); return Arg; } - + switch (isNullPointerValueTemplateArgument(*this, Param, ParamType, Arg)) { case NPV_NotNullPointer: Diag(Arg->getExprLoc(), diag::err_template_arg_not_convertible) << Arg->getType() << ParamType; Diag(Param->getLocation(), diag::note_template_param_here); return ExprError(); - + case NPV_Error: return ExprError(); - + case NPV_NullPointer: Diag(Arg->getExprLoc(), diag::warn_cxx98_compat_template_arg_null); Converted = TemplateArgument(Context.getCanonicalType(ParamType), @@ -5350,6 +5585,10 @@ ExprResult Sema::CheckTemplateArgument(NonTypeTemplateParmDecl *Param, return Arg; } +static void DiagnoseTemplateParameterListArityMismatch( + Sema &S, TemplateParameterList *New, TemplateParameterList *Old, + Sema::TemplateParameterListEqualKind Kind, SourceLocation TemplateArgLoc); + /// \brief Check a template argument against its corresponding /// template template parameter. /// @@ -5366,6 +5605,9 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, return false; } + if (Template->isInvalidDecl()) + return true; + // C++0x [temp.arg.template]p1: // A template-argument for a template template-parameter shall be // the name of a class template or an alias template, expressed as an @@ -5393,6 +5635,25 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, if (Param->isExpandedParameterPack()) Params = Param->getExpansionTemplateParameters(ArgumentPackIndex); + // C++1z [temp.arg.template]p3: (DR 150) + // A template-argument matches a template template-parameter P when P + // is at least as specialized as the template-argument A. + if (getLangOpts().RelaxedTemplateTemplateArgs) { + // Quick check for the common case: + // If P contains a parameter pack, then A [...] matches P if each of A's + // template parameters matches the corresponding template parameter in + // the template-parameter-list of P. + if (TemplateParameterListsAreEqual( + Template->getTemplateParameters(), Params, false, + TPL_TemplateTemplateArgumentMatch, Arg.getLocation())) + return false; + + if (isTemplateTemplateParameterAtLeastAsSpecializedAs(Params, Template, + Arg.getLocation())) + return false; + // FIXME: Produce better diagnostics for deduction failures. + } + return !TemplateParameterListsAreEqual(Template->getTemplateParameters(), Params, true, @@ -5578,7 +5839,7 @@ Sema::BuildExpressionFromIntegralTemplateArgument(const TemplateArgument &Arg, Context.getTrivialTypeSourceInfo(OrigT, Loc), Loc, Loc); } - + return E; } @@ -5604,7 +5865,7 @@ static bool MatchTemplateParameterKind(Sema &S, NamedDecl *New, NamedDecl *Old, return false; } - // Check that both are parameter packs are neither are parameter packs. + // Check that both are parameter packs or neither are parameter packs. // However, if we are matching a template template argument to a // template template parameter, the template template parameter can have // a parameter pack where the template template argument does not. @@ -5816,12 +6077,14 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) { // C++ [temp]p4: // A template [...] shall not have C linkage. DeclContext *Ctx = S->getEntity(); - if (Ctx && Ctx->isExternCContext()) - return Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) - << TemplateParams->getSourceRange(); - - while (Ctx && isa<LinkageSpecDecl>(Ctx)) - Ctx = Ctx->getParent(); + if (Ctx && Ctx->isExternCContext()) { + Diag(TemplateParams->getTemplateLoc(), diag::err_template_linkage) + << TemplateParams->getSourceRange(); + if (const LinkageSpecDecl *LSD = Ctx->getExternCContext()) + Diag(LSD->getExternLoc(), diag::note_extern_c_begins_here); + return true; + } + Ctx = Ctx->getRedeclContext(); // C++ [temp]p2: // A template-declaration can appear only as a namespace scope or @@ -5957,7 +6220,7 @@ static bool CheckTemplateSpecializationScope(Sema &S, << Specialized; return true; } - + // C++ [temp.class.spec]p6: // A class template partial specialization may be declared or redeclared // in any namespace scope in which its definition may be defined (14.5.1 @@ -6035,12 +6298,12 @@ static bool CheckTemplateSpecializationScope(Sema &S, return false; } -static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { - if (!E->isInstantiationDependent()) +static SourceRange findTemplateParameterInType(unsigned Depth, Expr *E) { + if (!E->isTypeDependent()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseStmt(E); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return E->getSourceRange(); return Checker.MatchLoc; } @@ -6048,9 +6311,9 @@ static SourceRange findTemplateParameter(unsigned Depth, Expr *E) { static SourceRange findTemplateParameter(unsigned Depth, TypeLoc TL) { if (!TL.getType()->isDependentType()) return SourceLocation(); - DependencyChecker Checker(Depth); + DependencyChecker Checker(Depth, /*IgnoreNonTypeDependent*/true); Checker.TraverseTypeLoc(TL); - if (Checker.Match && Checker.MatchLoc.isInvalid()) + if (Checker.MatchLoc.isInvalid()) return TL.getSourceRange(); return Checker.MatchLoc; } @@ -6102,8 +6365,16 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( // shall not involve a template parameter of the partial // specialization except when the argument expression is a // simple identifier. + // -- The type of a template parameter corresponding to a + // specialized non-type argument shall not be dependent on a + // parameter of the specialization. + // DR1315 removes the first bullet, leaving an incoherent set of rules. + // We implement a compromise between the original rules and DR1315: + // -- A specialized non-type template argument shall not be + // type-dependent and the corresponding template parameter + // shall have a non-dependent type. SourceRange ParamUseRange = - findTemplateParameter(Param->getDepth(), ArgExpr); + findTemplateParameterInType(Param->getDepth(), ArgExpr); if (ParamUseRange.isValid()) { if (IsDefaultArgument) { S.Diag(TemplateNameLoc, @@ -6119,26 +6390,15 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( return true; } - // -- The type of a template parameter corresponding to a - // specialized non-type argument shall not be dependent on a - // parameter of the specialization. - // - // FIXME: We need to delay this check until instantiation in some cases: - // - // template<template<typename> class X> struct A { - // template<typename T, X<T> N> struct B; - // template<typename T> struct B<T, 0>; - // }; - // template<typename> using X = int; - // A<X>::B<int, 0> b; ParamUseRange = findTemplateParameter( - Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc()); + Param->getDepth(), Param->getTypeSourceInfo()->getTypeLoc()); if (ParamUseRange.isValid()) { S.Diag(IsDefaultArgument ? TemplateNameLoc : ArgExpr->getLocStart(), diag::err_dependent_typed_non_type_arg_in_partial_spec) - << Param->getType() << ParamUseRange; + << Param->getType(); S.Diag(Param->getLocation(), diag::note_template_param_here) - << (IsDefaultArgument ? ParamUseRange : SourceRange()); + << (IsDefaultArgument ? ParamUseRange : SourceRange()) + << ParamUseRange; return true; } } @@ -6150,27 +6410,32 @@ static bool CheckNonTypeTemplatePartialSpecializationArgs( /// partial specialization according to C++ [temp.class.spec]p9. /// /// \param TemplateNameLoc the location of the template name. -/// \param TemplateParams the template parameters of the primary class +/// \param PrimaryTemplate the template parameters of the primary class /// template. /// \param NumExplicit the number of explicitly-specified template arguments. /// \param TemplateArgs the template arguments of the class template /// partial specialization. /// /// \returns \c true if there was an error, \c false otherwise. -static bool CheckTemplatePartialSpecializationArgs( - Sema &S, SourceLocation TemplateNameLoc, - TemplateParameterList *TemplateParams, unsigned NumExplicit, - SmallVectorImpl<TemplateArgument> &TemplateArgs) { - const TemplateArgument *ArgList = TemplateArgs.data(); +bool Sema::CheckTemplatePartialSpecializationArgs( + SourceLocation TemplateNameLoc, TemplateDecl *PrimaryTemplate, + unsigned NumExplicit, ArrayRef<TemplateArgument> TemplateArgs) { + // We have to be conservative when checking a template in a dependent + // context. + if (PrimaryTemplate->getDeclContext()->isDependentContext()) + return false; + TemplateParameterList *TemplateParams = + PrimaryTemplate->getTemplateParameters(); for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { NonTypeTemplateParmDecl *Param = dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(I)); if (!Param) continue; - if (CheckNonTypeTemplatePartialSpecializationArgs( - S, TemplateNameLoc, Param, &ArgList[I], 1, I >= NumExplicit)) + if (CheckNonTypeTemplatePartialSpecializationArgs(*this, TemplateNameLoc, + Param, &TemplateArgs[I], + 1, I >= NumExplicit)) return true; } @@ -6314,11 +6579,12 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // Find the class template (partial) specialization declaration that // corresponds to these arguments. if (isPartialSpecialization) { - if (CheckTemplatePartialSpecializationArgs( - *this, TemplateNameLoc, ClassTemplate->getTemplateParameters(), - TemplateArgs.size(), Converted)) + if (CheckTemplatePartialSpecializationArgs(TemplateNameLoc, ClassTemplate, + TemplateArgs.size(), Converted)) return true; + // FIXME: Move this to CheckTemplatePartialSpecializationArgs so we + // also do it during instantiation. bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( @@ -6363,6 +6629,9 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // // -- The argument list of the specialization shall not be identical // to the implicit argument list of the primary template. + // + // This rule has since been removed, because it's redundant given DR1495, + // but we keep it because it produces better diagnostics and recovery. Diag(TemplateNameLoc, diag::err_partial_spec_args_match_primary_template) << /*class template*/0 << (TUK == TUK_Definition) << FixItHint::CreateRemoval(SourceRange(LAngleLoc, RAngleLoc)); @@ -6405,34 +6674,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, if (PrevPartial && PrevPartial->getInstantiatedFromMember()) PrevPartial->setMemberSpecialization(); - // Check that all of the template parameters of the class template - // partial specialization are deducible from the template - // arguments. If not, this class template partial specialization - // will never be used. - llvm::SmallBitVector DeducibleParams(TemplateParams->size()); - MarkUsedTemplateParameters(Partial->getTemplateArgs(), true, - TemplateParams->getDepth(), - DeducibleParams); - - if (!DeducibleParams.all()) { - unsigned NumNonDeducible = DeducibleParams.size()-DeducibleParams.count(); - Diag(TemplateNameLoc, diag::warn_partial_specs_not_deducible) - << /*class template*/0 << (NumNonDeducible > 1) - << SourceRange(TemplateNameLoc, RAngleLoc); - for (unsigned I = 0, N = DeducibleParams.size(); I != N; ++I) { - if (!DeducibleParams[I]) { - NamedDecl *Param = cast<NamedDecl>(TemplateParams->getParam(I)); - if (Param->getDeclName()) - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << Param->getDeclName(); - else - Diag(Param->getLocation(), - diag::note_partial_spec_unused_parameter) - << "(anonymous)"; - } - } - } + CheckTemplatePartialSpecialization(Partial); } else { // Create a new class template specialization declaration node for // this explicit specialization or friend declaration. @@ -6509,8 +6751,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, TUK = TUK_Declaration; } else if (Def) { SourceRange Range(TemplateNameLoc, RAngleLoc); - Diag(TemplateNameLoc, diag::err_redefinition) - << Context.getTypeDeclType(Specialization) << Range; + Diag(TemplateNameLoc, diag::err_redefinition) << Specialization << Range; Diag(Def->getLocation(), diag::note_previous_definition); Specialization->setInvalidDecl(); return true; @@ -6531,7 +6772,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, Diag(Specialization->getLocation(), diag::err_module_private_specialization) << (isPartialSpecialization? 1 : 0) << FixItHint::CreateRemoval(ModulePrivateLoc); - + // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization // itself. This means that we'll pretty-print the type retrieved @@ -6748,13 +6989,7 @@ Sema::CheckSpecializationInstantiationRedecl(SourceLocation NewLoc, // instantiation of a template appears after a declaration of // an explicit specialization for that template, the explicit // instantiation has no effect. - // - // In C++98/03 mode, we only give an extension warning here, because it - // is not harmful to try to explicitly instantiate something that - // has been explicitly specialized. - Diag(NewLoc, getLangOpts().CPlusPlus11 ? - diag::warn_cxx98_compat_explicit_instantiation_after_specialization : - diag::ext_explicit_instantiation_after_specialization) + Diag(NewLoc, diag::warn_explicit_instantiation_after_specialization) << PrevDecl; Diag(PrevDecl->getLocation(), diag::note_previous_template_specialization); @@ -6926,6 +7161,21 @@ bool Sema::CheckFunctionTemplateSpecialization( continue; } + // Target attributes are part of the cuda function signature, so + // the deduced template's cuda target must match that of the + // specialization. Given that C++ template deduction does not + // take target attributes into account, we reject candidates + // here that have a different target. + if (LangOpts.CUDA && + IdentifyCUDATarget(Specialization, + /* IgnoreImplicitHDAttributes = */ true) != + IdentifyCUDATarget(FD, /* IgnoreImplicitHDAttributes = */ true)) { + FailedCandidates.addCandidate().set( + I.getPair(), FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); + continue; + } + // Record this candidate. if (ExplicitTemplateArgs) ConvertedTemplateArgs[Specialization] = std::move(Args); @@ -7002,7 +7252,7 @@ bool Sema::CheckFunctionTemplateSpecialization( SpecInfo->getPointOfInstantiation(), HasNoEffect)) return true; - + // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { @@ -7036,6 +7286,14 @@ bool Sema::CheckFunctionTemplateSpecialization( SpecInfo->getTemplateSpecializationKind(), ExplicitTemplateArgs ? &ConvertedTemplateArgs[Specialization] : nullptr); + // A function template specialization inherits the target attributes + // of its template. (We require the attributes explicitly in the + // code to match, but a template may have implicit attributes by + // virtue e.g. of being constexpr, and it passes these implicit + // attributes on to its specializations.) + if (LangOpts.CUDA) + inheritCUDATargetAttrs(FD, *Specialization->getPrimaryTemplate()); + // The "previous declaration" for this function template specialization is // the prior function template specialization. Previous.clear(); @@ -7190,7 +7448,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { if (InstantiationFunction->isDeleted()) { assert(InstantiationFunction->getCanonicalDecl() == InstantiationFunction); - InstantiationFunction->setDeletedAsWritten(false);
+ InstantiationFunction->setDeletedAsWritten(false); } } @@ -7318,6 +7576,30 @@ static bool ScopeSpecifierHasTemplateId(const CXXScopeSpec &SS) { return false; } +/// Make a dllexport or dllimport attr on a class template specialization take +/// effect. +static void dllExportImportClassTemplateSpecialization( + Sema &S, ClassTemplateSpecializationDecl *Def) { + auto *A = cast_or_null<InheritableAttr>(getDLLAttr(Def)); + assert(A && "dllExportImportClassTemplateSpecialization called " + "on Def without dllexport or dllimport"); + + // We reject explicit instantiations in class scope, so there should + // never be any delayed exported classes to worry about. + assert(S.DelayedDllExportClasses.empty() && + "delayed exports present at explicit instantiation"); + S.checkClassLevelDLLAttribute(Def); + + // Propagate attribute to base class templates. + for (auto &B : Def->bases()) { + if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>( + B.getType()->getAsCXXRecordDecl())) + S.propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart()); + } + + S.referenceDLLExportedClassMethods(); +} + // Explicit instantiation of a class template specialization DeclResult Sema::ActOnExplicitInstantiation(Scope *S, @@ -7344,14 +7626,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(TD); if (!ClassTemplate) { - unsigned ErrorKind = 0; - if (isa<TypeAliasTemplateDecl>(TD)) { - ErrorKind = 4; - } else if (isa<TemplateTemplateParmDecl>(TD)) { - ErrorKind = 5; - } - - Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << ErrorKind; + NonTagKind NTK = getNonTagTypeDeclKind(TD, Kind); + Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << TD << NTK << Kind; Diag(TD->getLocation(), diag::note_previous_use); return true; } @@ -7561,7 +7837,8 @@ Sema::ActOnExplicitInstantiation(Scope *S, Def->setTemplateSpecializationKind(TSK); if (!getDLLAttr(Def) && getDLLAttr(Specialization) && - Context.getTargetInfo().getCXXABI().isMicrosoft()) { + (Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { // In the MS ABI, an explicit instantiation definition can add a dll // attribute to a template with a previous instantiation declaration. // MinGW doesn't allow this. @@ -7569,23 +7846,33 @@ Sema::ActOnExplicitInstantiation(Scope *S, getDLLAttr(Specialization)->clone(getASTContext())); A->setInherited(true); Def->addAttr(A); - - // We reject explicit instantiations in class scope, so there should - // never be any delayed exported classes to worry about. - assert(DelayedDllExportClasses.empty() && - "delayed exports present at explicit instantiation"); - checkClassLevelDLLAttribute(Def); - referenceDLLExportedClassMethods(); - - // Propagate attribute to base class templates. - for (auto &B : Def->bases()) { - if (auto *BT = dyn_cast_or_null<ClassTemplateSpecializationDecl>( - B.getType()->getAsCXXRecordDecl())) - propagateDLLAttrToBaseClassTemplate(Def, A, BT, B.getLocStart()); - } + dllExportImportClassTemplateSpecialization(*this, Def); } } + // Fix a TSK_ImplicitInstantiation followed by a + // TSK_ExplicitInstantiationDefinition + if (Old_TSK == TSK_ImplicitInstantiation && + Specialization->hasAttr<DLLExportAttr>() && + (Context.getTargetInfo().getCXXABI().isMicrosoft() || + Context.getTargetInfo().getTriple().isWindowsItaniumEnvironment())) { + // In the MS ABI, an explicit instantiation definition can add a dll + // attribute to a template with a previous implicit instantiation. + // MinGW doesn't allow this. We limit clang to only adding dllexport, to + // avoid potentially strange codegen behavior. For example, if we extend + // this conditional to dllimport, and we have a source file calling a + // method on an implicitly instantiated template class instance and then + // declaring a dllimport explicit instantiation definition for the same + // template class, the codegen for the method call will not respect the + // dllimport, while it will with cl. The Def will already have the DLL + // attribute, since the Def and Specialization will be the same in the + // case of Old_TSK == TSK_ImplicitInstantiation, and we already added the + // attribute to the Specialization; we just need to make it take effect. + assert(Def == Specialization && + "Def and Specialization should match for implicit instantiation"); + dllExportImportClassTemplateSpecialization(*this, Def); + } + // Set the template specialization kind. Make sure it is set before // instantiating the members which will trigger ASTConsumer callbacks. Specialization->setTemplateSpecializationKind(TSK); @@ -7754,18 +8041,18 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return true; // C++ [dcl.stc]p1: - // A storage-class-specifier shall not be specified in [...] an explicit + // A storage-class-specifier shall not be specified in [...] an explicit // instantiation (14.7.2) directive. if (D.getDeclSpec().getStorageClassSpec() == DeclSpec::SCS_typedef) { Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_of_typedef) << Name; return true; - } else if (D.getDeclSpec().getStorageClassSpec() + } else if (D.getDeclSpec().getStorageClassSpec() != DeclSpec::SCS_unspecified) { // Complain about then remove the storage class specifier. Diag(D.getIdentifierLoc(), diag::err_explicit_instantiation_storage_class) << FixItHint::CreateRemoval(D.getDeclSpec().getStorageClassSpecLoc()); - + D.getMutableDeclSpec().ClearStorageClassSpecs(); } @@ -7957,13 +8244,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, // instantiated from the member definition associated with its class // template. UnresolvedSet<8> Matches; + AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); TemplateSpecCandidateSet FailedCandidates(D.getIdentifierLoc()); for (LookupResult::iterator P = Previous.begin(), PEnd = Previous.end(); P != PEnd; ++P) { NamedDecl *Prev = *P; if (!HasExplicitTemplateArgs) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Prev)) { - QualType Adjusted = adjustCCAndNoReturn(R, Method->getType()); + QualType Adjusted = adjustCCAndNoReturn(R, Method->getType(), + /*AdjustExceptionSpec*/true); if (Context.hasSameUnqualifiedType(Method->getType(), Adjusted)) { Matches.clear(); @@ -7993,6 +8282,21 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, continue; } + // Target attributes are part of the cuda function signature, so + // the cuda target of the instantiated function must match that of its + // template. Given that C++ template deduction does not take + // target attributes into account, we reject candidates here that + // have a different target. + if (LangOpts.CUDA && + IdentifyCUDATarget(Specialization, + /* IgnoreImplicitHDAttributes = */ true) != + IdentifyCUDATarget(Attr)) { + FailedCandidates.addCandidate().set( + P.getPair(), FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK_CUDATargetMismatch, Info)); + continue; + } + Matches.addDecl(Specialization, P.getAccess()); } @@ -8063,7 +8367,6 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, } Specialization->setTemplateSpecializationKind(TSK, D.getIdentifierLoc()); - AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); @@ -8131,7 +8434,7 @@ Sema::ActOnDependentTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // Create the resulting type. ElaboratedTypeKeyword Kwd = TypeWithKeyword::getKeywordForTagTypeKind(Kind); QualType Result = Context.getDependentNameType(Kwd, NNS, Name); - + // Create type-source location information for this type. TypeLocBuilder TLB; DependentNameTypeLoc TL = TLB.push<DependentNameTypeLoc>(Result); @@ -8147,7 +8450,7 @@ Sema::ActOnTypenameType(Scope *S, SourceLocation TypenameLoc, SourceLocation IdLoc) { if (SS.isInvalid()) return true; - + if (TypenameLoc.isValid() && S && !S->getTemplateParamParent()) Diag(TypenameLoc, getLangOpts().CPlusPlus11 ? @@ -8193,11 +8496,11 @@ Sema::ActOnTypenameType(Scope *S, diag::warn_cxx98_compat_typename_outside_of_template : diag::ext_typename_outside_of_template) << FixItHint::CreateRemoval(TypenameLoc); - + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); - + TemplateName Template = TemplateIn.get(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) { // Construct a dependent template specialization type. @@ -8207,10 +8510,10 @@ Sema::ActOnTypenameType(Scope *S, DTN->getQualifier(), DTN->getIdentifier(), TemplateArgs); - + // Create source-location information for this type. TypeLocBuilder Builder; - DependentTemplateSpecializationTypeLoc SpecTL + DependentTemplateSpecializationTypeLoc SpecTL = Builder.push<DependentTemplateSpecializationTypeLoc>(T); SpecTL.setElaboratedKeywordLoc(TypenameLoc); SpecTL.setQualifierLoc(SS.getWithLocInContext(Context)); @@ -8222,11 +8525,11 @@ Sema::ActOnTypenameType(Scope *S, SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); return CreateParsedType(T, Builder.getTypeSourceInfo(Context, T)); } - + QualType T = CheckTemplateIdType(Template, TemplateNameLoc, TemplateArgs); if (T.isNull()) return true; - + // Provide source-location information for the template specialization type. TypeLocBuilder Builder; TemplateSpecializationTypeLoc SpecTL @@ -8237,12 +8540,12 @@ Sema::ActOnTypenameType(Scope *S, SpecTL.setRAngleLoc(RAngleLoc); for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) SpecTL.setArgLocInfo(I, TemplateArgs[I].getLocInfo()); - + T = Context.getElaboratedType(ETK_Typename, SS.getScopeRep(), T); ElaboratedTypeLoc TL = Builder.push<ElaboratedTypeLoc>(T); TL.setElaboratedKeywordLoc(TypenameLoc); TL.setQualifierLoc(SS.getWithLocInContext(Context)); - + TypeSourceInfo *TSI = Builder.getTypeSourceInfo(Context, T); return CreateParsedType(T, TSI); } @@ -8287,9 +8590,9 @@ static bool isEnableIf(NestedNameSpecifierLoc NNS, const IdentifierInfo &II, /// \brief Build the type that describes a C++ typename specifier, /// e.g., "typename T::type". QualType -Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, +Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, SourceLocation KeywordLoc, - NestedNameSpecifierLoc QualifierLoc, + NestedNameSpecifierLoc QualifierLoc, const IdentifierInfo &II, SourceLocation IILoc) { CXXScopeSpec SS; @@ -8300,8 +8603,8 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // 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(), + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), &II); } @@ -8353,8 +8656,8 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, case LookupResult::NotFoundInCurrentInstantiation: // Okay, it's a member of an unknown instantiation. - return Context.getDependentNameType(Keyword, - QualifierLoc.getNestedNameSpecifier(), + return Context.getDependentNameType(Keyword, + QualifierLoc.getNestedNameSpecifier(), &II); case LookupResult::Found: @@ -8362,7 +8665,7 @@ Sema::CheckTypenameType(ElaboratedTypeKeyword Keyword, // We found a type. Build an ElaboratedType, since the // typename-specifier was just sugar. MarkAnyDeclReferenced(Type->getLocation(), Type, /*OdrUse=*/false); - return Context.getElaboratedType(ETK_Typename, + return Context.getElaboratedType(ETK_Typename, QualifierLoc.getNestedNameSpecifier(), Context.getTypeDeclType(Type)); } @@ -8429,7 +8732,7 @@ namespace { this->Loc = Loc; this->Entity = Entity; } - + ExprResult TransformLambdaExpr(LambdaExpr *E) { // Lambdas never need to be transformed. return E; @@ -8480,15 +8783,15 @@ ExprResult Sema::RebuildExprInCurrentInstantiation(Expr *E) { } bool Sema::RebuildNestedNameSpecifierInCurrentInstantiation(CXXScopeSpec &SS) { - if (SS.isInvalid()) + if (SS.isInvalid()) return true; NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context); CurrentInstantiationRebuilder Rebuilder(*this, SS.getRange().getBegin(), DeclarationName()); - NestedNameSpecifierLoc Rebuilt + NestedNameSpecifierLoc Rebuilt = Rebuilder.TransformNestedNameSpecifierLoc(QualifierLoc); - if (!Rebuilt) + if (!Rebuilt) return true; SS.Adopt(Rebuilt); @@ -8501,36 +8804,36 @@ bool Sema::RebuildTemplateParamsInCurrentInstantiation( TemplateParameterList *Params) { for (unsigned I = 0, N = Params->size(); I != N; ++I) { Decl *Param = Params->getParam(I); - + // There is nothing to rebuild in a type parameter. if (isa<TemplateTypeParmDecl>(Param)) continue; - + // Rebuild the template parameter list of a template template parameter. - if (TemplateTemplateParmDecl *TTP + if (TemplateTemplateParmDecl *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { if (RebuildTemplateParamsInCurrentInstantiation( TTP->getTemplateParameters())) return true; - + continue; } - + // Rebuild the type of a non-type template parameter. NonTypeTemplateParmDecl *NTTP = cast<NonTypeTemplateParmDecl>(Param); - TypeSourceInfo *NewTSI - = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), - NTTP->getLocation(), + TypeSourceInfo *NewTSI + = RebuildTypeInCurrentInstantiation(NTTP->getTypeSourceInfo(), + NTTP->getLocation(), NTTP->getDeclName()); if (!NewTSI) return true; - + if (NewTSI != NTTP->getTypeSourceInfo()) { NTTP->setTypeSourceInfo(NewTSI); NTTP->setType(NewTSI->getType()); } } - + return false; } @@ -8580,12 +8883,12 @@ void Sema::MarkAsLateParsedTemplate(FunctionDecl *FD, Decl *FnD, if (!FD) return; - LateParsedTemplate *LPT = new LateParsedTemplate; + auto LPT = llvm::make_unique<LateParsedTemplate>(); // Take tokens to avoid allocations LPT->Toks.swap(Toks); LPT->D = FnD; - LateParsedTemplateMap.insert(std::make_pair(FD, LPT)); + LateParsedTemplateMap.insert(std::make_pair(FD, std::move(LPT))); FD->setLateTemplateParsed(true); } @@ -8611,6 +8914,7 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() { return false; } +namespace { /// \brief Walk the path from which a declaration was instantiated, and check /// that every explicit specialization along that path is visible. This enforces /// C++ [temp.expl.spec]/6: @@ -8738,6 +9042,7 @@ private: } } }; +} // end anonymous namespace void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { if (!getLangOpts().Modules) diff --git a/lib/Sema/SemaTemplateDeduction.cpp b/lib/Sema/SemaTemplateDeduction.cpp index 5740bc712e861..0bc85a2f2635b 100644 --- a/lib/Sema/SemaTemplateDeduction.cpp +++ b/lib/Sema/SemaTemplateDeduction.cpp @@ -100,12 +100,13 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, SmallVectorImpl<DeducedTemplateArgument> & Deduced, unsigned TDF, - bool PartialOrdering = false); + bool PartialOrdering = false, + bool DeducedFromArrayBound = false); static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - const TemplateArgument *Params, unsigned NumParams, - const TemplateArgument *Args, unsigned NumArgs, + ArrayRef<TemplateArgument> Params, + ArrayRef<TemplateArgument> Args, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch); @@ -113,7 +114,8 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that /// non-type template parameter. -static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { +static NonTypeTemplateParmDecl * +getDeducedParameterFromExpr(TemplateDeductionInfo &Info, Expr *E) { // If we are within an alias template, the expression may have undergone // any number of parameter substitutions already. while (1) { @@ -127,7 +129,9 @@ static NonTypeTemplateParmDecl *getDeducedParameterFromExpr(Expr *E) { } if (DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E)) - return dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl()); + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(DRE->getDecl())) + if (NTTP->getDepth() == Info.getDeducedDepth()) + return NTTP; return nullptr; } @@ -157,6 +161,20 @@ checkDeducedTemplateArguments(ASTContext &Context, if (Y.isNull()) return X; + // If we have two non-type template argument values deduced for the same + // parameter, they must both match the type of the parameter, and thus must + // match each other's type. As we're only keeping one of them, we must check + // for that now. The exception is that if either was deduced from an array + // bound, the type is permitted to differ. + if (!X.wasDeducedFromArrayBound() && !Y.wasDeducedFromArrayBound()) { + QualType XType = X.getNonTypeTemplateArgumentType(); + if (!XType.isNull()) { + QualType YType = Y.getNonTypeTemplateArgumentType(); + if (YType.isNull() || !Context.hasSameType(XType, YType)) + return DeducedTemplateArgument(); + } + } + switch (X.getKind()) { case TemplateArgument::Null: llvm_unreachable("Non-deduced template arguments handled above"); @@ -167,6 +185,12 @@ checkDeducedTemplateArguments(ASTContext &Context, Context.hasSameType(X.getAsType(), Y.getAsType())) return X; + // If one of the two arguments was deduced from an array bound, the other + // supersedes it. + if (X.wasDeducedFromArrayBound() != Y.wasDeducedFromArrayBound()) + return X.wasDeducedFromArrayBound() ? Y : X; + + // The arguments are not compatible. return DeducedTemplateArgument(); case TemplateArgument::Integral: @@ -177,9 +201,7 @@ checkDeducedTemplateArguments(ASTContext &Context, Y.getKind() == TemplateArgument::Declaration || (Y.getKind() == TemplateArgument::Integral && hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral()))) - return DeducedTemplateArgument(X, - X.wasDeducedFromArrayBound() && - Y.wasDeducedFromArrayBound()); + return X.wasDeducedFromArrayBound() ? Y : X; // All other combinations are incompatible. return DeducedTemplateArgument(); @@ -201,37 +223,38 @@ checkDeducedTemplateArguments(ASTContext &Context, // All other combinations are incompatible. return DeducedTemplateArgument(); - case TemplateArgument::Expression: - // If we deduced a dependent expression in one case and either an integral - // constant or a declaration in another case, keep the integral constant - // or declaration. - if (Y.getKind() == TemplateArgument::Integral || - Y.getKind() == TemplateArgument::Declaration) - return DeducedTemplateArgument(Y, X.wasDeducedFromArrayBound() && - Y.wasDeducedFromArrayBound()); - - if (Y.getKind() == TemplateArgument::Expression) { - // Compare the expressions for equality - llvm::FoldingSetNodeID ID1, ID2; - X.getAsExpr()->Profile(ID1, Context, true); - Y.getAsExpr()->Profile(ID2, Context, true); - if (ID1 == ID2) - return X; - } + case TemplateArgument::Expression: { + if (Y.getKind() != TemplateArgument::Expression) + return checkDeducedTemplateArguments(Context, Y, X); - // All other combinations are incompatible. + // Compare the expressions for equality + llvm::FoldingSetNodeID ID1, ID2; + X.getAsExpr()->Profile(ID1, Context, true); + Y.getAsExpr()->Profile(ID2, Context, true); + if (ID1 == ID2) + return X.wasDeducedFromArrayBound() ? Y : X; + + // Differing dependent expressions are incompatible. return DeducedTemplateArgument(); + } case TemplateArgument::Declaration: + assert(!X.wasDeducedFromArrayBound()); + // If we deduced a declaration and a dependent expression, keep the // declaration. if (Y.getKind() == TemplateArgument::Expression) return X; // If we deduced a declaration and an integral constant, keep the - // integral constant. - if (Y.getKind() == TemplateArgument::Integral) + // integral constant and whichever type did not come from an array + // bound. + if (Y.getKind() == TemplateArgument::Integral) { + if (Y.wasDeducedFromArrayBound()) + return TemplateArgument(Context, Y.getAsIntegral(), + X.getParamTypeForDecl()); return Y; + } // If we deduced two declarations, make sure they they refer to the // same declaration. @@ -253,9 +276,8 @@ checkDeducedTemplateArguments(ASTContext &Context, if (Y.getKind() == TemplateArgument::Integral) return Y; - // If we deduced two null pointers, make sure they have the same type. - if (Y.getKind() == TemplateArgument::NullPtr && - Context.hasSameType(X.getNullPtrType(), Y.getNullPtrType())) + // If we deduced two null pointers, they are the same. + if (Y.getKind() == TemplateArgument::NullPtr) return X; // All other combinations are incompatible. @@ -285,19 +307,18 @@ checkDeducedTemplateArguments(ASTContext &Context, } /// \brief Deduce the value of the given non-type template parameter -/// from the given constant. +/// as the given deduced template argument. All non-type template parameter +/// deduction is funneled through here. static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( - Sema &S, NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, - QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, + Sema &S, TemplateParameterList *TemplateParams, + NonTypeTemplateParmDecl *NTTP, const DeducedTemplateArgument &NewDeduced, + QualType ValueType, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - assert(NTTP->getDepth() == 0 && - "Cannot deduce non-type template argument with depth > 0"); - - DeducedTemplateArgument NewDeduced(S.Context, Value, ValueType, - DeducedFromArrayBound); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[NTTP->getIndex()], - NewDeduced); + assert(NTTP->getDepth() == Info.getDeducedDepth() && + "deducing non-type template argument with wrong depth"); + + DeducedTemplateArgument Result = checkDeducedTemplateArguments( + S.Context, Deduced[NTTP->getIndex()], NewDeduced); if (Result.isNull()) { Info.Param = NTTP; Info.FirstArg = Deduced[NTTP->getIndex()]; @@ -306,68 +327,77 @@ static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( } Deduced[NTTP->getIndex()] = Result; - return Sema::TDK_Success; + if (!S.getLangOpts().CPlusPlus1z) + return Sema::TDK_Success; + + // FIXME: It's not clear how deduction of a parameter of reference + // type from an argument (of non-reference type) should be performed. + // For now, we just remove reference types from both sides and let + // the final check for matching types sort out the mess. + return DeduceTemplateArgumentsByTypeMatch( + S, TemplateParams, NTTP->getType().getNonReferenceType(), + ValueType.getNonReferenceType(), Info, Deduced, TDF_SkipNonDependent, + /*PartialOrdering=*/false, + /*ArrayBound=*/NewDeduced.wasDeducedFromArrayBound()); +} + +/// \brief Deduce the value of the given non-type template parameter +/// from the given integral constant. +static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( + Sema &S, TemplateParameterList *TemplateParams, + NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, + QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, + DeducedTemplateArgument(S.Context, Value, ValueType, + DeducedFromArrayBound), + ValueType, Info, Deduced); +} + +/// \brief Deduce the value of the given non-type template parameter +/// from the given null pointer template argument type. +static Sema::TemplateDeductionResult DeduceNullPtrTemplateArgument( + Sema &S, TemplateParameterList *TemplateParams, + NonTypeTemplateParmDecl *NTTP, QualType NullPtrType, + TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + Expr *Value = + S.ImpCastExprToType(new (S.Context) CXXNullPtrLiteralExpr( + S.Context.NullPtrTy, NTTP->getLocation()), + NullPtrType, CK_NullToPointer) + .get(); + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + DeducedTemplateArgument(Value), + Value->getType(), Info, Deduced); } /// \brief Deduce the value of the given non-type template parameter /// from the given type- or value-dependent expression. /// /// \returns true if deduction succeeded, false otherwise. -static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(Sema &S, - NonTypeTemplateParmDecl *NTTP, - Expr *Value, - TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - assert(NTTP->getDepth() == 0 && - "Cannot deduce non-type template argument with depth > 0"); - assert((Value->isTypeDependent() || Value->isValueDependent()) && - "Expression template argument must be type- or value-dependent."); - - DeducedTemplateArgument NewDeduced(Value); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[NTTP->getIndex()], - NewDeduced); - - if (Result.isNull()) { - Info.Param = NTTP; - Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; - } - - Deduced[NTTP->getIndex()] = Result; - return Sema::TDK_Success; +static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( + Sema &S, TemplateParameterList *TemplateParams, + NonTypeTemplateParmDecl *NTTP, Expr *Value, TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + DeducedTemplateArgument(Value), + Value->getType(), Info, Deduced); } /// \brief Deduce the value of the given non-type template parameter /// from the given declaration. /// /// \returns true if deduction succeeded, false otherwise. -static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(Sema &S, - NonTypeTemplateParmDecl *NTTP, - ValueDecl *D, - TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - assert(NTTP->getDepth() == 0 && - "Cannot deduce non-type template argument with depth > 0"); - +static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( + Sema &S, TemplateParameterList *TemplateParams, + NonTypeTemplateParmDecl *NTTP, ValueDecl *D, QualType T, + TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { D = D ? cast<ValueDecl>(D->getCanonicalDecl()) : nullptr; - TemplateArgument New(D, NTTP->getType()); - DeducedTemplateArgument NewDeduced(New); - DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, - Deduced[NTTP->getIndex()], - NewDeduced); - if (Result.isNull()) { - Info.Param = NTTP; - Info.FirstArg = Deduced[NTTP->getIndex()]; - Info.SecondArg = NewDeduced; - return Sema::TDK_Inconsistent; - } - - Deduced[NTTP->getIndex()] = Result; - return Sema::TDK_Success; + TemplateArgument New(D, T); + return DeduceNonTypeTemplateArgument( + S, TemplateParams, NTTP, DeducedTemplateArgument(New), T, Info, Deduced); } static Sema::TemplateDeductionResult @@ -386,6 +416,10 @@ DeduceTemplateArguments(Sema &S, if (TemplateTemplateParmDecl *TempParam = dyn_cast<TemplateTemplateParmDecl>(ParamDecl)) { + // If we're not deducing at this depth, there's nothing to deduce. + if (TempParam->getDepth() != Info.getDeducedDepth()) + return Sema::TDK_Success; + DeducedTemplateArgument NewDeduced(S.Context.getCanonicalTemplateName(Arg)); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[TempParam->getIndex()], @@ -453,9 +487,9 @@ DeduceTemplateArguments(Sema &S, // Perform template argument deduction on each template // argument. Ignore any missing/extra arguments, since they could be // filled in by default arguments. - return DeduceTemplateArguments(S, TemplateParams, Param->getArgs(), - Param->getNumArgs(), SpecArg->getArgs(), - SpecArg->getNumArgs(), Info, Deduced, + return DeduceTemplateArguments(S, TemplateParams, + Param->template_arguments(), + SpecArg->template_arguments(), Info, Deduced, /*NumberOfArgumentsMustMatch=*/false); } @@ -487,10 +521,9 @@ DeduceTemplateArguments(Sema &S, return Result; // Perform template argument deduction for the template arguments. - return DeduceTemplateArguments( - S, TemplateParams, Param->getArgs(), Param->getNumArgs(), - SpecArg->getTemplateArgs().data(), SpecArg->getTemplateArgs().size(), - Info, Deduced, /*NumberOfArgumentsMustMatch=*/true); + return DeduceTemplateArguments(S, TemplateParams, Param->template_arguments(), + SpecArg->getTemplateArgs().asArray(), Info, + Deduced, /*NumberOfArgumentsMustMatch=*/true); } /// \brief Determines whether the given type is an opaque type that @@ -589,7 +622,7 @@ public: for (unsigned I = 0, N = Unexpanded.size(); I != N; ++I) { unsigned Depth, Index; std::tie(Depth, Index) = getDepthAndIndex(Unexpanded[I]); - if (Depth == 0 && !SawIndices[Index]) { + if (Depth == Info.getDeducedDepth() && !SawIndices[Index]) { SawIndices[Index] = true; // Save the deduced template argument for the parameter pack expanded @@ -620,7 +653,8 @@ public: S.CurrentInstantiationScope->getPartiallySubstitutedPack( &ExplicitArgs, &NumExplicitArgs); if (PartiallySubstitutedPack && - getDepthAndIndex(PartiallySubstitutedPack).second == Pack.Index) + getDepthAndIndex(PartiallySubstitutedPack) == + std::make_pair(Info.getDeducedDepth(), Pack.Index)) Pack.New.append(ExplicitArgs, ExplicitArgs + NumExplicitArgs); } } @@ -863,12 +897,12 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, if (ParamQs == ArgQs) return false; - + // Mismatched (but not missing) Objective-C GC attributes. - if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && + if (ParamQs.getObjCGCAttr() != ArgQs.getObjCGCAttr() && ParamQs.hasObjCGCAttr()) return true; - + // Mismatched (but not missing) address spaces. if (ParamQs.getAddressSpace() != ArgQs.getAddressSpace() && ParamQs.hasAddressSpace()) @@ -878,7 +912,7 @@ static bool hasInconsistentOrSupersetQualifiersOf(QualType ParamType, if (ParamQs.getObjCLifetime() != ArgQs.getObjCLifetime() && ParamQs.hasObjCLifetime()) return true; - + // CVR qualifier superset. return (ParamQs.getCVRQualifiers() != ArgQs.getCVRQualifiers()) && ((ParamQs.getCVRQualifiers() | ArgQs.getCVRQualifiers()) @@ -901,9 +935,9 @@ bool Sema::isSameOrCompatibleFunctionType(CanQualType Param, if (!ParamFunction || !ArgFunction) return Param == Arg; - // Noreturn adjustment. + // Noreturn and noexcept adjustment. QualType AdjustedParam; - if (IsNoReturnConversion(Param, Arg, AdjustedParam)) + if (IsFunctionConversion(Param, Arg, AdjustedParam)) return Arg == Context.getCanonicalType(AdjustedParam); // FIXME: Compatible calling conventions. @@ -942,7 +976,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, unsigned TDF, - bool PartialOrdering) { + bool PartialOrdering, + bool DeducedFromArrayBound) { // We only want to look at the canonical types, since typedefs and // sugar are not part of template argument deduction. QualType Param = S.Context.getCanonicalType(ParamIn); @@ -1057,10 +1092,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // cv-list T if (const TemplateTypeParmType *TemplateTypeParm = Param->getAs<TemplateTypeParmType>()) { - // Just skip any attempts to deduce from a placeholder type. - if (Arg->isPlaceholderType()) + // Just skip any attempts to deduce from a placeholder type or a parameter + // at a different depth. + if (Arg->isPlaceholderType() || + Info.getDeducedDepth() != TemplateTypeParm->getDepth()) return Sema::TDK_Success; - + unsigned Index = TemplateTypeParm->getIndex(); bool RecanonicalizeArg = false; @@ -1085,7 +1122,8 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return Sema::TDK_Underqualified; } - assert(TemplateTypeParm->getDepth() == 0 && "Can't deduce with depth > 0"); + assert(TemplateTypeParm->getDepth() == Info.getDeducedDepth() && + "saw template type parameter with wrong depth"); assert(Arg != S.Context.OverloadTy && "Unresolved overloaded function"); QualType DeducedType = Arg; @@ -1100,7 +1138,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, DeducedQs.removeAddressSpace(); if (ParamQs.hasObjCLifetime()) DeducedQs.removeObjCLifetime(); - + // Objective-C ARC: // If template deduction would produce a lifetime qualifier on a type // that is not a lifetime type, template argument deduction fails. @@ -1109,9 +1147,9 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, Info.Param = cast<TemplateTypeParmDecl>(TemplateParams->getParam(Index)); Info.FirstArg = TemplateArgument(Param); Info.SecondArg = TemplateArgument(Arg); - return Sema::TDK_Underqualified; + return Sema::TDK_Underqualified; } - + // Objective-C ARC: // If template deduction would produce an argument type with lifetime type // but no lifetime qualifier, the __strong lifetime qualifier is inferred. @@ -1119,14 +1157,14 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, DeducedType->isObjCLifetimeType() && !DeducedQs.hasObjCLifetime()) DeducedQs.setObjCLifetime(Qualifiers::OCL_Strong); - + DeducedType = S.Context.getQualifiedType(DeducedType.getUnqualifiedType(), DeducedQs); - + if (RecanonicalizeArg) DeducedType = S.Context.getCanonicalType(DeducedType); - DeducedTemplateArgument NewDeduced(DeducedType); + DeducedTemplateArgument NewDeduced(DeducedType, DeducedFromArrayBound); DeducedTemplateArgument Result = checkDeducedTemplateArguments(S.Context, Deduced[Index], NewDeduced); @@ -1163,7 +1201,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (Param.getCVRQualifiers() != Arg.getCVRQualifiers()) return Sema::TDK_NonDeducedMismatch; } - + // If the parameter type is not dependent, there is nothing to deduce. if (!Param->isDependentType()) { if (!(TDF & TDF_SkipNonDependent)) { @@ -1193,7 +1231,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::Class: llvm_unreachable("deducing non-canonical type: " #Class); #define TYPE(Class, Base) #include "clang/AST/TypeNodes.def" - + case Type::TemplateTypeParm: case Type::SubstTemplateTypeParmPack: llvm_unreachable("Type nodes handled above"); @@ -1211,20 +1249,20 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, case Type::ObjCObjectPointer: { if (TDF & TDF_SkipNonDependent) return Sema::TDK_Success; - + if (TDF & TDF_IgnoreQualifiers) { Param = Param.getUnqualifiedType(); Arg = Arg.getUnqualifiedType(); } - + return Param == Arg? Sema::TDK_Success : Sema::TDK_NonDeducedMismatch; } - - // _Complex T [placeholder extension] + + // _Complex T [placeholder extension] case Type::Complex: if (const ComplexType *ComplexArg = Arg->getAs<ComplexType>()) - return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, - cast<ComplexType>(Param)->getElementType(), + return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, + cast<ComplexType>(Param)->getElementType(), ComplexArg->getElementType(), Info, Deduced, TDF); @@ -1337,18 +1375,18 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // Determine the array bound is something we can deduce. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(DependentArrayParm->getSizeExpr()); + = getDeducedParameterFromExpr(Info, DependentArrayParm->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; // We can perform template argument deduction for the given non-type // template parameter. - assert(NTTP->getDepth() == 0 && - "Cannot deduce non-type template argument at depth > 0"); + assert(NTTP->getDepth() == Info.getDeducedDepth() && + "saw non-type template parameter with wrong depth"); if (const ConstantArrayType *ConstantArrayArg = dyn_cast<ConstantArrayType>(ArrayArg)) { llvm::APSInt Size(ConstantArrayArg->getSize()); - return DeduceNonTypeTemplateArgument(S, NTTP, Size, + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Size, S.Context.getSizeType(), /*ArrayBound=*/true, Info, Deduced); @@ -1356,7 +1394,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, if (const DependentSizedArrayType *DependentArrayArg = dyn_cast<DependentSizedArrayType>(ArrayArg)) if (DependentArrayArg->getSizeExpr()) - return DeduceNonTypeTemplateArgument(S, NTTP, + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, DependentArrayArg->getSizeExpr(), Info, Deduced); @@ -1549,7 +1587,7 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, QualType(MemPtrParam->getClass(), 0), QualType(MemPtrArg->getClass(), 0), - Info, Deduced, + Info, Deduced, TDF & TDF_IgnoreQualifiers); } @@ -1580,15 +1618,15 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // Make sure that the vectors have the same number of elements. if (VectorParam->getNumElements() != VectorArg->getNumElements()) return Sema::TDK_NonDeducedMismatch; - + // Perform deduction on the element types. return DeduceTemplateArgumentsByTypeMatch(S, TemplateParams, VectorParam->getElementType(), VectorArg->getElementType(), Info, Deduced, TDF); } - - if (const DependentSizedExtVectorType *VectorArg + + if (const DependentSizedExtVectorType *VectorArg = dyn_cast<DependentSizedExtVectorType>(Arg)) { // We can't check the number of elements, since the argument has a // dependent number of elements. This can only occur during partial @@ -1600,10 +1638,10 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, VectorArg->getElementType(), Info, Deduced, TDF); } - + return Sema::TDK_NonDeducedMismatch; } - + // (clang extension) // // T __attribute__(((ext_vector_type(N)))) @@ -1619,20 +1657,24 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, VectorArg->getElementType(), Info, Deduced, TDF)) return Result; - + // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + = getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; llvm::APSInt ArgSize(S.Context.getTypeSize(S.Context.IntTy), false); ArgSize = VectorArg->getNumElements(); - return DeduceNonTypeTemplateArgument(S, NTTP, ArgSize, S.Context.IntTy, - false, Info, Deduced); + // Note that we use the "array bound" rules here; just like in that + // case, we don't have any particular type for the vector size, but + // we can provide one if necessary. + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, ArgSize, + S.Context.IntTy, true, Info, + Deduced); } - - if (const DependentSizedExtVectorType *VectorArg + + if (const DependentSizedExtVectorType *VectorArg = dyn_cast<DependentSizedExtVectorType>(Arg)) { // Perform deduction on the element types. if (Sema::TemplateDeductionResult Result @@ -1641,20 +1683,21 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, VectorArg->getElementType(), Info, Deduced, TDF)) return Result; - + // Perform deduction on the vector size, if we can. NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(VectorParam->getSizeExpr()); + = getDeducedParameterFromExpr(Info, VectorParam->getSizeExpr()); if (!NTTP) return Sema::TDK_Success; - - return DeduceNonTypeTemplateArgument(S, NTTP, VectorArg->getSizeExpr(), + + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + VectorArg->getSizeExpr(), Info, Deduced); } - + return Sema::TDK_NonDeducedMismatch; } - + case Type::TypeOfExpr: case Type::TypeOf: case Type::DependentName: @@ -1751,18 +1794,24 @@ DeduceTemplateArguments(Sema &S, case TemplateArgument::Expression: { if (NonTypeTemplateParmDecl *NTTP - = getDeducedParameterFromExpr(Param.getAsExpr())) { + = getDeducedParameterFromExpr(Info, Param.getAsExpr())) { if (Arg.getKind() == TemplateArgument::Integral) - return DeduceNonTypeTemplateArgument(S, NTTP, + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, Arg.getAsIntegral(), Arg.getIntegralType(), /*ArrayBound=*/false, Info, Deduced); - if (Arg.getKind() == TemplateArgument::Expression) - return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsExpr(), + if (Arg.getKind() == TemplateArgument::NullPtr) + return DeduceNullPtrTemplateArgument(S, TemplateParams, NTTP, + Arg.getNullPtrType(), Info, Deduced); + if (Arg.getKind() == TemplateArgument::Expression) + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + Arg.getAsExpr(), Info, Deduced); if (Arg.getKind() == TemplateArgument::Declaration) - return DeduceNonTypeTemplateArgument(S, NTTP, Arg.getAsDecl(), + return DeduceNonTypeTemplateArgument(S, TemplateParams, NTTP, + Arg.getAsDecl(), + Arg.getParamTypeForDecl(), Info, Deduced); Info.FirstArg = Param; @@ -1788,45 +1837,34 @@ DeduceTemplateArguments(Sema &S, /// /// \returns true if there is another template argument (which will be at /// \c Args[ArgIdx]), false otherwise. -static bool hasTemplateArgumentForDeduction(const TemplateArgument *&Args, - unsigned &ArgIdx, - unsigned &NumArgs) { - if (ArgIdx == NumArgs) +static bool hasTemplateArgumentForDeduction(ArrayRef<TemplateArgument> &Args, + unsigned &ArgIdx) { + if (ArgIdx == Args.size()) return false; const TemplateArgument &Arg = Args[ArgIdx]; if (Arg.getKind() != TemplateArgument::Pack) return true; - assert(ArgIdx == NumArgs - 1 && "Pack not at the end of argument list?"); - Args = Arg.pack_begin(); - NumArgs = Arg.pack_size(); + assert(ArgIdx == Args.size() - 1 && "Pack not at the end of argument list?"); + Args = Arg.pack_elements(); ArgIdx = 0; - return ArgIdx < NumArgs; + return ArgIdx < Args.size(); } /// \brief Determine whether the given set of template arguments has a pack /// expansion that is not the last template argument. -static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, - unsigned NumArgs) { - unsigned ArgIdx = 0; - while (ArgIdx < NumArgs) { - const TemplateArgument &Arg = Args[ArgIdx]; - - // Unwrap argument packs. - if (Args[ArgIdx].getKind() == TemplateArgument::Pack) { - Args = Arg.pack_begin(); - NumArgs = Arg.pack_size(); - ArgIdx = 0; - continue; - } +static bool hasPackExpansionBeforeEnd(ArrayRef<TemplateArgument> Args) { + bool FoundPackExpansion = false; + for (const auto &A : Args) { + if (FoundPackExpansion) + return true; - ++ArgIdx; - if (ArgIdx == NumArgs) - return false; + if (A.getKind() == TemplateArgument::Pack) + return hasPackExpansionBeforeEnd(A.pack_elements()); - if (Arg.isPackExpansion()) - return true; + if (A.isPackExpansion()) + FoundPackExpansion = true; } return false; @@ -1834,8 +1872,8 @@ static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, static Sema::TemplateDeductionResult DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, - const TemplateArgument *Params, unsigned NumParams, - const TemplateArgument *Args, unsigned NumArgs, + ArrayRef<TemplateArgument> Params, + ArrayRef<TemplateArgument> Args, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced, bool NumberOfArgumentsMustMatch) { @@ -1843,7 +1881,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // If the template argument list of P contains a pack expansion that is not // the last template argument, the entire template argument list is a // non-deduced context. - if (hasPackExpansionBeforeEnd(Params, NumParams)) + if (hasPackExpansionBeforeEnd(Params)) return Sema::TDK_Success; // C++0x [temp.deduct.type]p9: @@ -1851,21 +1889,20 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // respective template argument list P is compared with the corresponding // argument Ai of the corresponding template argument list of A. unsigned ArgIdx = 0, ParamIdx = 0; - for (; hasTemplateArgumentForDeduction(Params, ParamIdx, NumParams); - ++ParamIdx) { + for (; hasTemplateArgumentForDeduction(Params, ParamIdx); ++ParamIdx) { if (!Params[ParamIdx].isPackExpansion()) { // The simple case: deduce template arguments by matching Pi and Ai. // Check whether we have enough arguments. - if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) + if (!hasTemplateArgumentForDeduction(Args, ArgIdx)) return NumberOfArgumentsMustMatch ? Sema::TDK_TooFewArguments : Sema::TDK_Success; - if (Args[ArgIdx].isPackExpansion()) { - // FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here, - // but applied to pack expansions that are template arguments. + // C++1z [temp.deduct.type]p9: + // During partial ordering, if Ai was originally a pack expansion [and] + // Pi is not a pack expansion, template argument deduction fails. + if (Args[ArgIdx].isPackExpansion()) return Sema::TDK_MiscellaneousDeductionFailure; - } // Perform deduction for this Pi/Ai pair. if (Sema::TemplateDeductionResult Result @@ -1899,7 +1936,7 @@ DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, // expanded by this pack expansion (the outer index) and for each // template argument (the inner SmallVectors). bool HasAnyArguments = false; - for (; hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs); ++ArgIdx) { + for (; hasTemplateArgumentForDeduction(Args, ArgIdx); ++ArgIdx) { HasAnyArguments = true; // Deduce template arguments from the pattern. @@ -1927,16 +1964,21 @@ DeduceTemplateArguments(Sema &S, const TemplateArgumentList &ArgList, TemplateDeductionInfo &Info, SmallVectorImpl<DeducedTemplateArgument> &Deduced) { - return DeduceTemplateArguments(S, TemplateParams, - ParamList.data(), ParamList.size(), - ArgList.data(), ArgList.size(), - Info, Deduced, false); + return DeduceTemplateArguments(S, TemplateParams, ParamList.asArray(), + ArgList.asArray(), Info, Deduced, + /*NumberOfArgumentsMustMatch*/false); } /// \brief Determine whether two template arguments are the same. static bool isSameTemplateArg(ASTContext &Context, - const TemplateArgument &X, - const TemplateArgument &Y) { + TemplateArgument X, + const TemplateArgument &Y, + bool PackExpansionMatchesPack = false) { + // If we're checking deduced arguments (X) against original arguments (Y), + // we will have flattened packs to non-expansions in X. + if (PackExpansionMatchesPack && X.isPackExpansion() && !Y.isPackExpansion()) + X = X.getPackExpansionPattern(); + if (X.getKind() != Y.getKind()) return false; @@ -1962,7 +2004,7 @@ static bool isSameTemplateArg(ASTContext &Context, Y.getAsTemplateOrTemplatePattern()).getAsVoidPointer(); case TemplateArgument::Integral: - return X.getAsIntegral() == Y.getAsIntegral(); + return hasSameExtendedValue(X.getAsIntegral(), Y.getAsIntegral()); case TemplateArgument::Expression: { llvm::FoldingSetNodeID XID, YID; @@ -1979,7 +2021,7 @@ static bool isSameTemplateArg(ASTContext &Context, XPEnd = X.pack_end(), YP = Y.pack_begin(); XP != XPEnd; ++XP, ++YP) - if (!isSameTemplateArg(Context, *XP, *YP)) + if (!isSameTemplateArg(Context, *XP, *YP, PackExpansionMatchesPack)) return false; return true; @@ -1991,48 +2033,47 @@ static bool isSameTemplateArg(ASTContext &Context, /// \brief Allocate a TemplateArgumentLoc where all locations have /// been initialized to the given location. /// -/// \param S The semantic analysis object. -/// /// \param Arg The template argument we are producing template argument /// location information for. /// /// \param NTTPType For a declaration template argument, the type of /// the non-type template parameter that corresponds to this template -/// argument. +/// argument. Can be null if no type sugar is available to add to the +/// type from the template argument. /// /// \param Loc The source location to use for the resulting template /// argument. -static TemplateArgumentLoc -getTrivialTemplateArgumentLoc(Sema &S, - const TemplateArgument &Arg, - QualType NTTPType, - SourceLocation Loc) { +TemplateArgumentLoc +Sema::getTrivialTemplateArgumentLoc(const TemplateArgument &Arg, + QualType NTTPType, SourceLocation Loc) { switch (Arg.getKind()) { case TemplateArgument::Null: llvm_unreachable("Can't get a NULL template argument here"); case TemplateArgument::Type: - return TemplateArgumentLoc(Arg, - S.Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); + return TemplateArgumentLoc( + Arg, Context.getTrivialTypeSourceInfo(Arg.getAsType(), Loc)); case TemplateArgument::Declaration: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .getAs<Expr>(); + if (NTTPType.isNull()) + NTTPType = Arg.getParamTypeForDecl(); + Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .getAs<Expr>(); return TemplateArgumentLoc(TemplateArgument(E), E); } case TemplateArgument::NullPtr: { - Expr *E - = S.BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) - .getAs<Expr>(); + if (NTTPType.isNull()) + NTTPType = Arg.getNullPtrType(); + Expr *E = BuildExpressionFromDeclTemplateArgument(Arg, NTTPType, Loc) + .getAs<Expr>(); return TemplateArgumentLoc(TemplateArgument(NTTPType, /*isNullPtr*/true), E); } case TemplateArgument::Integral: { - Expr *E - = S.BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>(); + Expr *E = + BuildExpressionFromIntegralTemplateArgument(Arg, Loc).getAs<Expr>(); return TemplateArgumentLoc(TemplateArgument(E), E); } @@ -2041,18 +2082,16 @@ getTrivialTemplateArgumentLoc(Sema &S, NestedNameSpecifierLocBuilder Builder; TemplateName Template = Arg.getAsTemplate(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) - Builder.MakeTrivial(S.Context, DTN->getQualifier(), Loc); + Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) - Builder.MakeTrivial(S.Context, QTN->getQualifier(), Loc); - + Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); + if (Arg.getKind() == TemplateArgument::Template) - return TemplateArgumentLoc(Arg, - Builder.getWithLocInContext(S.Context), + return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context), Loc); - - - return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(S.Context), + + return TemplateArgumentLoc(Arg, Builder.getWithLocInContext(Context), Loc, Loc); } @@ -2074,39 +2113,21 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, TemplateDeductionInfo &Info, - bool InFunctionTemplate, + bool IsDeduced, SmallVectorImpl<TemplateArgument> &Output) { - // First, for a non-type template parameter type that is - // initialized by a declaration, we need the type of the - // corresponding non-type template parameter. - QualType NTTPType; - if (NonTypeTemplateParmDecl *NTTP = - dyn_cast<NonTypeTemplateParmDecl>(Param)) { - NTTPType = NTTP->getType(); - if (NTTPType->isDependentType()) { - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output); - NTTPType = S.SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - if (NTTPType.isNull()) - return true; - } - } - auto ConvertArg = [&](DeducedTemplateArgument Arg, unsigned ArgumentPackIndex) { // Convert the deduced template argument into a template // argument that we can check, almost as if the user had written // the template argument explicitly. TemplateArgumentLoc ArgLoc = - getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation()); + S.getTrivialTemplateArgumentLoc(Arg, QualType(), Info.getLocation()); // Check the template argument, converting it as necessary. return S.CheckTemplateArgument( Param, ArgLoc, Template, Template->getLocation(), Template->getSourceRange().getEnd(), ArgumentPackIndex, Output, - InFunctionTemplate + IsDeduced ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound : Sema::CTAK_Deduced) : Sema::CTAK_Specified); @@ -2132,22 +2153,28 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, } // If the pack is empty, we still need to substitute into the parameter - // itself, in case that substitution fails. For non-type parameters, we did - // this above. For type parameters, no substitution is ever required. - auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param); - if (TTP && PackedArgsBuilder.empty()) { - // Set up a template instantiation context. + // itself, in case that substitution fails. + if (PackedArgsBuilder.empty()) { LocalInstantiationScope Scope(S); - Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, - TTP, Output, - Template->getSourceRange()); - if (Inst.isInvalid()) - return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output); - if (!S.SubstDecl(TTP, S.CurContext, - MultiLevelTemplateArgumentList(TemplateArgs))) - return true; + MultiLevelTemplateArgumentList Args(TemplateArgs); + + if (auto *NTTP = dyn_cast<NonTypeTemplateParmDecl>(Param)) { + Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, + NTTP, Output, + Template->getSourceRange()); + if (Inst.isInvalid() || + S.SubstType(NTTP->getType(), Args, NTTP->getLocation(), + NTTP->getDeclName()).isNull()) + return true; + } else if (auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param)) { + Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template, + TTP, Output, + Template->getSourceRange()); + if (Inst.isInvalid() || !S.SubstDecl(TTP, S.CurContext, Args)) + return true; + } + // For type parameters, no substitution is ever required. } // Create the resulting argument pack. @@ -2159,44 +2186,169 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, return ConvertArg(Arg, 0); } -/// Complete template argument deduction for a class template partial -/// specialization. -static Sema::TemplateDeductionResult -FinishTemplateArgumentDeduction(Sema &S, - ClassTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - TemplateDeductionInfo &Info) { - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); - Sema::SFINAETrap Trap(S); +// FIXME: This should not be a template, but +// ClassTemplatePartialSpecializationDecl sadly does not derive from +// TemplateDecl. +template<typename TemplateDeclT> +static Sema::TemplateDeductionResult ConvertDeducedTemplateArguments( + Sema &S, TemplateDeclT *Template, bool IsDeduced, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info, SmallVectorImpl<TemplateArgument> &Builder, + LocalInstantiationScope *CurrentInstantiationScope = nullptr, + unsigned NumAlreadyConverted = 0, bool PartialOverloading = false) { + TemplateParameterList *TemplateParams = Template->getTemplateParameters(); - Sema::ContextRAII SavedContext(S, Partial); + for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { + NamedDecl *Param = TemplateParams->getParam(I); - // C++ [temp.deduct.type]p2: - // [...] or if any template argument remains neither deduced nor - // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; - TemplateParameterList *PartialParams = Partial->getTemplateParameters(); - for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { - NamedDecl *Param = PartialParams->getParam(I); - if (Deduced[I].isNull()) { - Info.Param = makeTemplateParameter(Param); + if (!Deduced[I].isNull()) { + if (I < NumAlreadyConverted) { + // We have already fully type-checked and converted this + // argument, because it was explicitly-specified. Just record the + // presence of this argument. + Builder.push_back(Deduced[I]); + // We may have had explicitly-specified template arguments for a + // template parameter pack (that may or may not have been extended + // via additional deduced arguments). + if (Param->isParameterPack() && CurrentInstantiationScope) { + if (CurrentInstantiationScope->getPartiallySubstitutedPack() == + Param) { + // Forget the partially-substituted pack; its substitution is now + // complete. + CurrentInstantiationScope->ResetPartiallySubstitutedPack(); + } + } + continue; + } + + // We have deduced this argument, so it still needs to be + // checked and converted. + if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Template, Info, + IsDeduced, Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + return Sema::TDK_SubstitutionFailure; + } + + continue; + } + + // C++0x [temp.arg.explicit]p3: + // A trailing template parameter pack (14.5.3) not otherwise deduced will + // be deduced to an empty sequence of template arguments. + // FIXME: Where did the word "trailing" come from? + if (Param->isTemplateParameterPack()) { + // We may have had explicitly-specified template arguments for this + // template parameter pack. If so, our empty deduction extends the + // explicitly-specified set (C++0x [temp.arg.explicit]p9). + const TemplateArgument *ExplicitArgs; + unsigned NumExplicitArgs; + if (CurrentInstantiationScope && + CurrentInstantiationScope->getPartiallySubstitutedPack( + &ExplicitArgs, &NumExplicitArgs) == Param) { + Builder.push_back(TemplateArgument( + llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); + + // Forget the partially-substituted pack; its substitution is now + // complete. + CurrentInstantiationScope->ResetPartiallySubstitutedPack(); + } else { + // Go through the motions of checking the empty argument pack against + // the parameter pack. + DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack()); + if (ConvertDeducedTemplateArgument(S, Param, DeducedPack, Template, + Info, IsDeduced, Builder)) { + Info.Param = makeTemplateParameter(Param); + // FIXME: These template arguments are temporary. Free them! + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + return Sema::TDK_SubstitutionFailure; + } + } + continue; + } + + // Substitute into the default template argument, if available. + bool HasDefaultArg = false; + TemplateDecl *TD = dyn_cast<TemplateDecl>(Template); + if (!TD) { + assert(isa<ClassTemplatePartialSpecializationDecl>(Template)); return Sema::TDK_Incomplete; } - // We have deduced this argument, so it still needs to be - // checked and converted. - if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], - Partial, Info, false, - Builder)) { - Info.Param = makeTemplateParameter(Param); + TemplateArgumentLoc DefArg = S.SubstDefaultTemplateArgumentIfAvailable( + TD, TD->getLocation(), TD->getSourceRange().getEnd(), Param, Builder, + HasDefaultArg); + + // If there was no default argument, deduction is incomplete. + if (DefArg.getArgument().isNull()) { + Info.Param = makeTemplateParameter( + const_cast<NamedDecl *>(TemplateParams->getParam(I))); + Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); + if (PartialOverloading) break; + + return HasDefaultArg ? Sema::TDK_SubstitutionFailure + : Sema::TDK_Incomplete; + } + + // Check whether we can actually use the default argument. + if (S.CheckTemplateArgument(Param, DefArg, TD, TD->getLocation(), + TD->getSourceRange().getEnd(), 0, Builder, + Sema::CTAK_Specified)) { + Info.Param = makeTemplateParameter( + const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); return Sema::TDK_SubstitutionFailure; } + + // If we get here, we successfully used the default template argument. } + return Sema::TDK_Success; +} + +DeclContext *getAsDeclContextOrEnclosing(Decl *D) { + if (auto *DC = dyn_cast<DeclContext>(D)) + return DC; + return D->getDeclContext(); +} + +template<typename T> struct IsPartialSpecialization { + static constexpr bool value = false; +}; +template<> +struct IsPartialSpecialization<ClassTemplatePartialSpecializationDecl> { + static constexpr bool value = true; +}; +template<> +struct IsPartialSpecialization<VarTemplatePartialSpecializationDecl> { + static constexpr bool value = true; +}; + +/// Complete template argument deduction for a partial specialization. +template <typename T> +static typename std::enable_if<IsPartialSpecialization<T>::value, + Sema::TemplateDeductionResult>::type +FinishTemplateArgumentDeduction( + Sema &S, T *Partial, bool IsPartialOrdering, + const TemplateArgumentList &TemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Partial)); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> Builder; + if (auto Result = ConvertDeducedTemplateArguments( + S, Partial, IsPartialOrdering, Deduced, Info, Builder)) + return Result; + // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(S.Context, Builder); @@ -2209,11 +2361,11 @@ FinishTemplateArgumentDeduction(Sema &S, // and are equivalent to the template arguments originally provided // to the class template. LocalInstantiationScope InstScope(S); - ClassTemplateDecl *ClassTemplate = Partial->getSpecializedTemplate(); - const ASTTemplateArgumentListInfo *PartialTemplArgInfo - = Partial->getTemplateArgsAsWritten(); - const TemplateArgumentLoc *PartialTemplateArgs - = PartialTemplArgInfo->getTemplateArgs(); + auto *Template = Partial->getSpecializedTemplate(); + const ASTTemplateArgumentListInfo *PartialTemplArgInfo = + Partial->getTemplateArgsAsWritten(); + const TemplateArgumentLoc *PartialTemplateArgs = + PartialTemplArgInfo->getTemplateArgs(); TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, PartialTemplArgInfo->RAngleLoc); @@ -2224,21 +2376,19 @@ FinishTemplateArgumentDeduction(Sema &S, if (ParamIdx >= Partial->getTemplateParameters()->size()) ParamIdx = Partial->getTemplateParameters()->size() - 1; - Decl *Param - = const_cast<NamedDecl *>( - Partial->getTemplateParameters()->getParam(ParamIdx)); + Decl *Param = const_cast<NamedDecl *>( + Partial->getTemplateParameters()->getParam(ParamIdx)); Info.Param = makeTemplateParameter(Param); Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); return Sema::TDK_SubstitutionFailure; } SmallVector<TemplateArgument, 4> ConvertedInstArgs; - if (S.CheckTemplateArgumentList(ClassTemplate, Partial->getLocation(), - InstArgs, false, ConvertedInstArgs)) + if (S.CheckTemplateArgumentList(Template, Partial->getLocation(), InstArgs, + false, ConvertedInstArgs)) return Sema::TDK_SubstitutionFailure; - TemplateParameterList *TemplateParams - = ClassTemplate->getTemplateParameters(); + TemplateParameterList *TemplateParams = Template->getTemplateParameters(); for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { TemplateArgument InstArg = ConvertedInstArgs.data()[I]; if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { @@ -2255,6 +2405,48 @@ FinishTemplateArgumentDeduction(Sema &S, return Sema::TDK_Success; } +/// Complete template argument deduction for a class or variable template, +/// when partial ordering against a partial specialization. +// FIXME: Factor out duplication with partial specialization version above. +Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( + Sema &S, TemplateDecl *Template, bool PartialOrdering, + const TemplateArgumentList &TemplateArgs, + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + TemplateDeductionInfo &Info) { + // Unevaluated SFINAE context. + EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); + Sema::SFINAETrap Trap(S); + + Sema::ContextRAII SavedContext(S, getAsDeclContextOrEnclosing(Template)); + + // C++ [temp.deduct.type]p2: + // [...] or if any template argument remains neither deduced nor + // explicitly specified, template argument deduction fails. + SmallVector<TemplateArgument, 4> Builder; + if (auto Result = ConvertDeducedTemplateArguments( + S, Template, /*IsDeduced*/PartialOrdering, Deduced, Info, Builder)) + return Result; + + // Check that we produced the correct argument list. + TemplateParameterList *TemplateParams = Template->getTemplateParameters(); + for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { + TemplateArgument InstArg = Builder[I]; + if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg, + /*PackExpansionMatchesPack*/true)) { + Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); + Info.FirstArg = TemplateArgs[I]; + Info.SecondArg = InstArg; + return Sema::TDK_NonDeducedMismatch; + } + } + + if (Trap.hasErrorOccurred()) + return Sema::TDK_SubstitutionFailure; + + return Sema::TDK_Success; +} + + /// \brief Perform template argument deduction to determine whether /// the given template arguments match the given class template /// partial specialization per C++ [temp.class.spec.match]. @@ -2293,112 +2485,13 @@ Sema::DeduceTemplateArguments(ClassTemplatePartialSpecializationDecl *Partial, if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, - Deduced, Info); -} - -/// Complete template argument deduction for a variable template partial -/// specialization. -/// TODO: Unify with ClassTemplatePartialSpecializationDecl version? -/// May require unifying ClassTemplate(Partial)SpecializationDecl and -/// VarTemplate(Partial)SpecializationDecl with a new data -/// structure Template(Partial)SpecializationDecl, and -/// using Template(Partial)SpecializationDecl as input type. -static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( - Sema &S, VarTemplatePartialSpecializationDecl *Partial, - const TemplateArgumentList &TemplateArgs, - SmallVectorImpl<DeducedTemplateArgument> &Deduced, - TemplateDeductionInfo &Info) { - // Unevaluated SFINAE context. - EnterExpressionEvaluationContext Unevaluated(S, Sema::Unevaluated); - Sema::SFINAETrap Trap(S); - - // C++ [temp.deduct.type]p2: - // [...] or if any template argument remains neither deduced nor - // explicitly specified, template argument deduction fails. - SmallVector<TemplateArgument, 4> Builder; - TemplateParameterList *PartialParams = Partial->getTemplateParameters(); - for (unsigned I = 0, N = PartialParams->size(); I != N; ++I) { - NamedDecl *Param = PartialParams->getParam(I); - if (Deduced[I].isNull()) { - Info.Param = makeTemplateParameter(Param); - return Sema::TDK_Incomplete; - } - - // We have deduced this argument, so it still needs to be - // checked and converted. - if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, - Info, false, Builder)) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder)); - return Sema::TDK_SubstitutionFailure; - } - } - - // Form the template argument list from the deduced template arguments. - TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy( - S.Context, Builder); - - Info.reset(DeducedArgumentList); - - // Substitute the deduced template arguments into the template - // arguments of the class template partial specialization, and - // verify that the instantiated template arguments are both valid - // and are equivalent to the template arguments originally provided - // to the class template. - LocalInstantiationScope InstScope(S); - VarTemplateDecl *VarTemplate = Partial->getSpecializedTemplate(); - const ASTTemplateArgumentListInfo *PartialTemplArgInfo - = Partial->getTemplateArgsAsWritten(); - const TemplateArgumentLoc *PartialTemplateArgs - = PartialTemplArgInfo->getTemplateArgs(); - - TemplateArgumentListInfo InstArgs(PartialTemplArgInfo->LAngleLoc, - PartialTemplArgInfo->RAngleLoc); - - if (S.Subst(PartialTemplateArgs, PartialTemplArgInfo->NumTemplateArgs, - InstArgs, MultiLevelTemplateArgumentList(*DeducedArgumentList))) { - unsigned ArgIdx = InstArgs.size(), ParamIdx = ArgIdx; - if (ParamIdx >= Partial->getTemplateParameters()->size()) - ParamIdx = Partial->getTemplateParameters()->size() - 1; - - Decl *Param = const_cast<NamedDecl *>( - Partial->getTemplateParameters()->getParam(ParamIdx)); - Info.Param = makeTemplateParameter(Param); - Info.FirstArg = PartialTemplateArgs[ArgIdx].getArgument(); - return Sema::TDK_SubstitutionFailure; - } - SmallVector<TemplateArgument, 4> ConvertedInstArgs; - if (S.CheckTemplateArgumentList(VarTemplate, Partial->getLocation(), InstArgs, - false, ConvertedInstArgs)) - return Sema::TDK_SubstitutionFailure; - - TemplateParameterList *TemplateParams = VarTemplate->getTemplateParameters(); - for (unsigned I = 0, E = TemplateParams->size(); I != E; ++I) { - TemplateArgument InstArg = ConvertedInstArgs.data()[I]; - if (!isSameTemplateArg(S.Context, TemplateArgs[I], InstArg)) { - Info.Param = makeTemplateParameter(TemplateParams->getParam(I)); - Info.FirstArg = TemplateArgs[I]; - Info.SecondArg = InstArg; - return Sema::TDK_NonDeducedMismatch; - } - } - - if (Trap.hasErrorOccurred()) - return Sema::TDK_SubstitutionFailure; - - return Sema::TDK_Success; + return ::FinishTemplateArgumentDeduction( + *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info); } /// \brief Perform template argument deduction to determine whether /// the given template arguments match the given variable template /// partial specialization per C++ [temp.class.spec.match]. -/// TODO: Unify with ClassTemplatePartialSpecializationDecl version? -/// May require unifying ClassTemplate(Partial)SpecializationDecl and -/// VarTemplate(Partial)SpecializationDecl with a new data -/// structure Template(Partial)SpecializationDecl, and -/// using Template(Partial)SpecializationDecl as input type. Sema::TemplateDeductionResult Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, const TemplateArgumentList &TemplateArgs, @@ -2432,8 +2525,8 @@ Sema::DeduceTemplateArguments(VarTemplatePartialSpecializationDecl *Partial, if (Trap.hasErrorOccurred()) return Sema::TDK_SubstitutionFailure; - return ::FinishTemplateArgumentDeduction(*this, Partial, TemplateArgs, - Deduced, Info); + return ::FinishTemplateArgumentDeduction( + *this, Partial, /*PartialOrdering=*/false, TemplateArgs, Deduced, Info); } /// \brief Determine whether the given type T is a simple-template-id type. @@ -2573,15 +2666,15 @@ Sema::SubstituteExplicitTemplateArguments( ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } - + // Instantiate the return type. QualType ResultType; { // C++11 [expr.prim.general]p3: - // If a declaration declares a member function or member function - // template of a class X, the expression this is a prvalue of type + // If a declaration declares a member function or member function + // template of a class X, the expression this is a prvalue of type // "pointer to cv-qualifier-seq X" between the optional cv-qualifer-seq - // and the end of the function-definition, member-declarator, or + // and the end of the function-definition, member-declarator, or // declarator. unsigned ThisTypeQuals = 0; CXXRecordDecl *ThisContext = nullptr; @@ -2589,7 +2682,7 @@ Sema::SubstituteExplicitTemplateArguments( ThisContext = Method->getParent(); ThisTypeQuals = Method->getTypeQualifiers(); } - + CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals, getLangOpts().CPlusPlus11); @@ -2645,35 +2738,42 @@ Sema::SubstituteExplicitTemplateArguments( /// \brief Check whether the deduced argument type for a call to a function /// template matches the actual argument type per C++ [temp.deduct.call]p4. -static bool -CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, +static bool +CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, QualType DeducedA) { ASTContext &Context = S.Context; - + QualType A = OriginalArg.OriginalArgType; QualType OriginalParamType = OriginalArg.OriginalParamType; - + // Check for type equality (top-level cv-qualifiers are ignored). if (Context.hasSameUnqualifiedType(A, DeducedA)) return false; - + // Strip off references on the argument types; they aren't needed for // the following checks. if (const ReferenceType *DeducedARef = DeducedA->getAs<ReferenceType>()) DeducedA = DeducedARef->getPointeeType(); if (const ReferenceType *ARef = A->getAs<ReferenceType>()) A = ARef->getPointeeType(); - + // C++ [temp.deduct.call]p4: // [...] However, there are three cases that allow a difference: - // - If the original P is a reference type, the deduced A (i.e., the - // type referred to by the reference) can be more cv-qualified than + // - If the original P is a reference type, the deduced A (i.e., the + // type referred to by the reference) can be more cv-qualified than // the transformed A. if (const ReferenceType *OriginalParamRef = OriginalParamType->getAs<ReferenceType>()) { // We don't want to keep the reference around any more. OriginalParamType = OriginalParamRef->getPointeeType(); - + + // FIXME: Resolve core issue (no number yet): if the original P is a + // reference type and the transformed A is function type "noexcept F", + // the deduced A can be F. + QualType Tmp; + if (A->isFunctionType() && S.IsFunctionConversion(A, DeducedA, Tmp)) + return false; + Qualifiers AQuals = A.getQualifiers(); Qualifiers DeducedAQuals = DeducedA.getQualifiers(); @@ -2693,34 +2793,32 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, // Qualifiers match; there's nothing to do. } else if (!DeducedAQuals.compatiblyIncludes(AQuals)) { return true; - } else { + } else { // Qualifiers are compatible, so have the argument type adopt the // deduced argument type's qualifiers as if we had performed the // qualification conversion. A = Context.getQualifiedType(A.getUnqualifiedType(), DeducedAQuals); } } - - // - The transformed A can be another pointer or pointer to member - // type that can be converted to the deduced A via a qualification - // conversion. + + // - The transformed A can be another pointer or pointer to member + // type that can be converted to the deduced A via a function pointer + // conversion and/or a qualification conversion. // - // Also allow conversions which merely strip [[noreturn]] from function types - // (recursively) as an extension. - // FIXME: Currently, this doesn't play nicely with qualification conversions. + // Also allow conversions which merely strip __attribute__((noreturn)) from + // function types (recursively). bool ObjCLifetimeConversion = false; QualType ResultTy; if ((A->isAnyPointerType() || A->isMemberPointerType()) && (S.IsQualificationConversion(A, DeducedA, false, ObjCLifetimeConversion) || - S.IsNoReturnConversion(A, DeducedA, ResultTy))) + S.IsFunctionConversion(A, DeducedA, ResultTy))) return false; - - - // - If P is a class and P has the form simple-template-id, then the + + // - If P is a class and P has the form simple-template-id, then the // transformed A can be a derived class of the deduced A. [...] - // [...] Likewise, if P is a pointer to a class of the form - // simple-template-id, the transformed A can be a pointer to a + // [...] Likewise, if P is a pointer to a class of the form + // simple-template-id, the transformed A can be a pointer to a // derived class pointed to by the deduced A. if (const PointerType *OriginalParamPtr = OriginalParamType->getAs<PointerType>()) { @@ -2734,14 +2832,14 @@ CheckOriginalCallArgDeduction(Sema &S, Sema::OriginalCallArg OriginalArg, } } } - + if (Context.hasSameUnqualifiedType(A, DeducedA)) return false; - + if (A->isRecordType() && isSimpleTemplateIdType(OriginalParamType) && S.IsDerivedFrom(SourceLocation(), A, DeducedA)) return false; - + return true; } @@ -2759,9 +2857,6 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, TemplateDeductionInfo &Info, SmallVectorImpl<OriginalCallArg> const *OriginalCallArgs, bool PartialOverloading) { - TemplateParameterList *TemplateParams - = FunctionTemplate->getTemplateParameters(); - // Unevaluated SFINAE context. EnterExpressionEvaluationContext Unevaluated(*this, Sema::Unevaluated); SFINAETrap Trap(*this); @@ -2782,114 +2877,11 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // [...] or if any template argument remains neither deduced nor // explicitly specified, template argument deduction fails. SmallVector<TemplateArgument, 4> Builder; - for (unsigned I = 0, N = TemplateParams->size(); I != N; ++I) { - NamedDecl *Param = TemplateParams->getParam(I); - - if (!Deduced[I].isNull()) { - if (I < NumExplicitlySpecified) { - // We have already fully type-checked and converted this - // argument, because it was explicitly-specified. Just record the - // presence of this argument. - Builder.push_back(Deduced[I]); - // We may have had explicitly-specified template arguments for a - // template parameter pack (that may or may not have been extended - // via additional deduced arguments). - if (Param->isParameterPack() && CurrentInstantiationScope) { - if (CurrentInstantiationScope->getPartiallySubstitutedPack() == - Param) { - // Forget the partially-substituted pack; its substitution is now - // complete. - CurrentInstantiationScope->ResetPartiallySubstitutedPack(); - } - } - continue; - } - - // We have deduced this argument, so it still needs to be - // checked and converted. - if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], - FunctionTemplate, Info, - true, Builder)) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - return TDK_SubstitutionFailure; - } - - continue; - } - - // C++0x [temp.arg.explicit]p3: - // A trailing template parameter pack (14.5.3) not otherwise deduced will - // be deduced to an empty sequence of template arguments. - // FIXME: Where did the word "trailing" come from? - if (Param->isTemplateParameterPack()) { - // We may have had explicitly-specified template arguments for this - // template parameter pack. If so, our empty deduction extends the - // explicitly-specified set (C++0x [temp.arg.explicit]p9). - const TemplateArgument *ExplicitArgs; - unsigned NumExplicitArgs; - if (CurrentInstantiationScope && - CurrentInstantiationScope->getPartiallySubstitutedPack(&ExplicitArgs, - &NumExplicitArgs) - == Param) { - Builder.push_back(TemplateArgument( - llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); - - // Forget the partially-substituted pack; its substitution is now - // complete. - CurrentInstantiationScope->ResetPartiallySubstitutedPack(); - } else { - // Go through the motions of checking the empty argument pack against - // the parameter pack. - DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack()); - if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack, - FunctionTemplate, Info, true, - Builder)) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - return TDK_SubstitutionFailure; - } - } - continue; - } - - // Substitute into the default template argument, if available. - bool HasDefaultArg = false; - TemplateArgumentLoc DefArg - = SubstDefaultTemplateArgumentIfAvailable(FunctionTemplate, - FunctionTemplate->getLocation(), - FunctionTemplate->getSourceRange().getEnd(), - Param, - Builder, HasDefaultArg); - - // If there was no default argument, deduction is incomplete. - if (DefArg.getArgument().isNull()) { - Info.Param = makeTemplateParameter( - const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - if (PartialOverloading) break; - - return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete; - } - - // Check whether we can actually use the default argument. - if (CheckTemplateArgument(Param, DefArg, - FunctionTemplate, - FunctionTemplate->getLocation(), - FunctionTemplate->getSourceRange().getEnd(), - 0, Builder, - CTAK_Specified)) { - Info.Param = makeTemplateParameter( - const_cast<NamedDecl *>(TemplateParams->getParam(I))); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); - return TDK_SubstitutionFailure; - } - - // If we get here, we successfully used the default template argument. - } + if (auto Result = ConvertDeducedTemplateArguments( + *this, FunctionTemplate, /*IsDeduced*/true, Deduced, Info, Builder, + CurrentInstantiationScope, NumExplicitlySpecified, + PartialOverloading)) + return Result; // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList @@ -2927,15 +2919,15 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (OriginalCallArgs) { // C++ [temp.deduct.call]p4: // In general, the deduction process attempts to find template argument - // values that will make the deduced A identical to A (after the type A + // values that will make the deduced A identical to A (after the type A // is transformed as described above). [...] for (unsigned I = 0, N = OriginalCallArgs->size(); I != N; ++I) { OriginalCallArg OriginalArg = (*OriginalCallArgs)[I]; unsigned ParamIdx = OriginalArg.ArgIdx; - + if (ParamIdx >= Specialization->getNumParams()) continue; - + QualType DeducedA = Specialization->getParamDecl(ParamIdx)->getType(); if (CheckOriginalCallArgDeduction(*this, OriginalArg, DeducedA)) { Info.FirstArg = TemplateArgument(DeducedA); @@ -2945,7 +2937,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } } } - + // If we suppressed any diagnostics while performing template argument // deduction, and if we haven't already instantiated this declaration, // keep track of these diagnostics. They'll be emitted if this specialization @@ -3025,7 +3017,7 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, return QualType(); } - + // Gather the explicit template arguments, if any. TemplateArgumentListInfo ExplicitTemplateArgs; if (Ovl->hasExplicitTemplateArgs()) @@ -3041,14 +3033,14 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, // non-deduced context. if (!Ovl->hasExplicitTemplateArgs()) return QualType(); - - // Otherwise, see if we can resolve a function type + + // Otherwise, see if we can resolve a function type FunctionDecl *Specialization = nullptr; TemplateDeductionInfo Info(Ovl->getNameLoc()); if (S.DeduceTemplateArguments(FunTmpl, &ExplicitTemplateArgs, Specialization, Info)) continue; - + D = Specialization; } @@ -3250,16 +3242,13 @@ DeduceFromInitializerList(Sema &S, TemplateParameterList *TemplateParams, S.Context.getAsDependentSizedArrayType(AdjustedParamType); // Determine the array bound is something we can deduce. if (NonTypeTemplateParmDecl *NTTP = - getDeducedParameterFromExpr(ArrTy->getSizeExpr())) { + getDeducedParameterFromExpr(Info, ArrTy->getSizeExpr())) { // We can perform template argument deduction for the given non-type // template parameter. - assert(NTTP->getDepth() == 0 && - "Cannot deduce non-type template argument at depth > 0"); llvm::APInt Size(S.Context.getIntWidth(NTTP->getType()), ILE->getNumInits()); - Result = DeduceNonTypeTemplateArgument( - S, NTTP, llvm::APSInt(Size), NTTP->getType(), + S, TemplateParams, NTTP, llvm::APSInt(Size), NTTP->getType(), /*ArrayBound=*/true, Info, Deduced); } } @@ -3291,7 +3280,7 @@ DeduceTemplateArgumentByListElement(Sema &S, // For all other cases, just match by type. QualType ArgType = Arg->getType(); - if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType, + if (AdjustFunctionParmAndArgTypesForDeduction(S, TemplateParams, ParamType, ArgType, Arg, TDF)) { Info.Expression = Arg; return Sema::TDK_FailedOverloadResolution; @@ -3382,7 +3371,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( ParamIdx != NumParamTypes; ++ParamIdx) { QualType OrigParamType = ParamTypes[ParamIdx]; QualType ParamType = OrigParamType; - + const PackExpansionType *ParamExpansion = dyn_cast<PackExpansionType>(ParamType); if (!ParamExpansion) { @@ -3392,7 +3381,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( Expr *Arg = Args[ArgIdx++]; QualType ArgType = Arg->getType(); - + unsigned TDF = 0; if (AdjustFunctionParmAndArgTypesForDeduction(*this, TemplateParams, ParamType, ArgType, Arg, @@ -3419,7 +3408,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // Keep track of the argument type and corresponding parameter index, // so we can check for compatibility between the deduced A and A. - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx-1, ArgType)); if (TemplateDeductionResult Result @@ -3482,7 +3471,7 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( // Keep track of the argument type and corresponding argument index, // so we can check for compatibility between the deduced A and A. if (hasDeducibleTemplateParameters(*this, FunctionTemplate, ParamType)) - OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, + OriginalCallArgs.push_back(OriginalCallArg(OrigParamType, ArgIdx, ArgType)); if (TemplateDeductionResult Result @@ -3511,25 +3500,42 @@ Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( } QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, - QualType FunctionType) { + QualType FunctionType, + bool AdjustExceptionSpec) { if (ArgFunctionType.isNull()) return ArgFunctionType; const FunctionProtoType *FunctionTypeP = FunctionType->castAs<FunctionProtoType>(); - CallingConv CC = FunctionTypeP->getCallConv(); - bool NoReturn = FunctionTypeP->getNoReturnAttr(); const FunctionProtoType *ArgFunctionTypeP = ArgFunctionType->getAs<FunctionProtoType>(); - if (ArgFunctionTypeP->getCallConv() == CC && - ArgFunctionTypeP->getNoReturnAttr() == NoReturn) + + FunctionProtoType::ExtProtoInfo EPI = ArgFunctionTypeP->getExtProtoInfo(); + bool Rebuild = false; + + CallingConv CC = FunctionTypeP->getCallConv(); + if (EPI.ExtInfo.getCC() != CC) { + EPI.ExtInfo = EPI.ExtInfo.withCallingConv(CC); + Rebuild = true; + } + + bool NoReturn = FunctionTypeP->getNoReturnAttr(); + if (EPI.ExtInfo.getNoReturn() != NoReturn) { + EPI.ExtInfo = EPI.ExtInfo.withNoReturn(NoReturn); + Rebuild = true; + } + + if (AdjustExceptionSpec && (FunctionTypeP->hasExceptionSpec() || + ArgFunctionTypeP->hasExceptionSpec())) { + EPI.ExceptionSpec = FunctionTypeP->getExtProtoInfo().ExceptionSpec; + Rebuild = true; + } + + if (!Rebuild) return ArgFunctionType; - FunctionType::ExtInfo EI = ArgFunctionTypeP->getExtInfo().withCallingConv(CC); - EI = EI.withNoReturn(NoReturn); - ArgFunctionTypeP = - cast<FunctionProtoType>(Context.adjustFunctionType(ArgFunctionTypeP, EI)); - return QualType(ArgFunctionTypeP, 0); + return Context.getFunctionType(ArgFunctionTypeP->getReturnType(), + ArgFunctionTypeP->getParamTypes(), EPI); } /// \brief Deduce template arguments when taking the address of a function @@ -3554,14 +3560,17 @@ QualType Sema::adjustCCAndNoReturn(QualType ArgFunctionType, /// \param Info the argument will be updated to provide additional information /// about template argument deduction. /// +/// \param IsAddressOfFunction If \c true, we are deducing as part of taking +/// the address of a function template per [temp.deduct.funcaddr] and +/// [over.over]. If \c false, we are looking up a function template +/// specialization based on its signature, per [temp.deduct.decl]. +/// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - QualType ArgFunctionType, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - bool InOverloadResolution) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, QualType ArgFunctionType, + FunctionDecl *&Specialization, TemplateDeductionInfo &Info, + bool IsAddressOfFunction) { if (FunctionTemplate->isInvalidDecl()) return TDK_Invalid; @@ -3569,8 +3578,13 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); QualType FunctionType = Function->getType(); - if (!InOverloadResolution) - ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType); + + // When taking the address of a function, we require convertibility of + // the resulting function type. Otherwise, we allow arbitrary mismatches + // of calling convention, noreturn, and noexcept. + if (!IsAddressOfFunction) + ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, FunctionType, + /*AdjustExceptionSpec*/true); // Substitute any explicit template arguments. LocalInstantiationScope InstScope(*this); @@ -3595,9 +3609,11 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, Deduced.resize(TemplateParams->size()); // If the function has a deduced return type, substitute it for a dependent - // type so that we treat it as a non-deduced context in what follows. + // type so that we treat it as a non-deduced context in what follows. If we + // are looking up by signature, the signature type should also have a deduced + // return type, which we instead expect to exactly match. bool HasDeducedReturnType = false; - if (getLangOpts().CPlusPlus14 && InOverloadResolution && + if (getLangOpts().CPlusPlus14 && IsAddressOfFunction && Function->getReturnType()->getContainedAutoType()) { FunctionType = SubstAutoType(FunctionType, Context.DependentTy); HasDeducedReturnType = true; @@ -3605,7 +3621,8 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, if (!ArgFunctionType.isNull()) { unsigned TDF = TDF_TopLevelParameterTypeList; - if (InOverloadResolution) TDF |= TDF_InOverloadResolution; + if (IsAddressOfFunction) + TDF |= TDF_InOverloadResolution; // Deduce template arguments from the function type. if (TemplateDeductionResult Result = DeduceTemplateArgumentsByTypeMatch(*this, TemplateParams, @@ -3627,86 +3644,106 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, DeduceReturnType(Specialization, Info.getLocation(), false)) return TDK_MiscellaneousDeductionFailure; + // If the function has a dependent exception specification, resolve it now, + // so we can check that the exception specification matches. + auto *SpecializationFPT = + Specialization->getType()->castAs<FunctionProtoType>(); + if (getLangOpts().CPlusPlus1z && + isUnresolvedExceptionSpec(SpecializationFPT->getExceptionSpecType()) && + !ResolveExceptionSpec(Info.getLocation(), SpecializationFPT)) + return TDK_MiscellaneousDeductionFailure; + + // Adjust the exception specification of the argument again to match the + // substituted and resolved type we just formed. (Calling convention and + // noreturn can't be dependent, so we don't actually need this for them + // right now.) + QualType SpecializationType = Specialization->getType(); + if (!IsAddressOfFunction) + ArgFunctionType = adjustCCAndNoReturn(ArgFunctionType, SpecializationType, + /*AdjustExceptionSpec*/true); + // If the requested function type does not match the actual type of the // specialization with respect to arguments of compatible pointer to function // types, template argument deduction fails. if (!ArgFunctionType.isNull()) { - if (InOverloadResolution && !isSameOrCompatibleFunctionType( - Context.getCanonicalType(Specialization->getType()), - Context.getCanonicalType(ArgFunctionType))) + if (IsAddressOfFunction && + !isSameOrCompatibleFunctionType( + Context.getCanonicalType(SpecializationType), + Context.getCanonicalType(ArgFunctionType))) return TDK_MiscellaneousDeductionFailure; - else if(!InOverloadResolution && - !Context.hasSameType(Specialization->getType(), ArgFunctionType)) + + if (!IsAddressOfFunction && + !Context.hasSameType(SpecializationType, ArgFunctionType)) return TDK_MiscellaneousDeductionFailure; } return TDK_Success; } -/// \brief Given a function declaration (e.g. a generic lambda conversion -/// function) that contains an 'auto' in its result type, substitute it +/// \brief Given a function declaration (e.g. a generic lambda conversion +/// function) that contains an 'auto' in its result type, substitute it /// with TypeToReplaceAutoWith. Be careful to pass in the type you want /// to replace 'auto' with and not the actual result type you want /// to set the function to. -static inline void -SubstAutoWithinFunctionReturnType(FunctionDecl *F, +static inline void +SubstAutoWithinFunctionReturnType(FunctionDecl *F, QualType TypeToReplaceAutoWith, Sema &S) { assert(!TypeToReplaceAutoWith->getContainedAutoType()); QualType AutoResultType = F->getReturnType(); - assert(AutoResultType->getContainedAutoType()); - QualType DeducedResultType = S.SubstAutoType(AutoResultType, + assert(AutoResultType->getContainedAutoType()); + QualType DeducedResultType = S.SubstAutoType(AutoResultType, TypeToReplaceAutoWith); S.Context.adjustDeducedFunctionResultType(F, DeducedResultType); } -/// \brief Given a specialized conversion operator of a generic lambda -/// create the corresponding specializations of the call operator and -/// the static-invoker. If the return type of the call operator is auto, -/// deduce its return type and check if that matches the +/// \brief Given a specialized conversion operator of a generic lambda +/// create the corresponding specializations of the call operator and +/// the static-invoker. If the return type of the call operator is auto, +/// deduce its return type and check if that matches the /// return type of the destination function ptr. -static inline Sema::TemplateDeductionResult +static inline Sema::TemplateDeductionResult SpecializeCorrespondingLambdaCallOperatorAndInvoker( CXXConversionDecl *ConversionSpecialized, SmallVectorImpl<DeducedTemplateArgument> &DeducedArguments, QualType ReturnTypeOfDestFunctionPtr, TemplateDeductionInfo &TDInfo, Sema &S) { - + CXXRecordDecl *LambdaClass = ConversionSpecialized->getParent(); - assert(LambdaClass && LambdaClass->isGenericLambda()); - + assert(LambdaClass && LambdaClass->isGenericLambda()); + CXXMethodDecl *CallOpGeneric = LambdaClass->getLambdaCallOperator(); QualType CallOpResultType = CallOpGeneric->getReturnType(); - const bool GenericLambdaCallOperatorHasDeducedReturnType = + const bool GenericLambdaCallOperatorHasDeducedReturnType = CallOpResultType->getContainedAutoType(); - - FunctionTemplateDecl *CallOpTemplate = + + FunctionTemplateDecl *CallOpTemplate = CallOpGeneric->getDescribedFunctionTemplate(); FunctionDecl *CallOpSpecialized = nullptr; - // Use the deduced arguments of the conversion function, to specialize our + // Use the deduced arguments of the conversion function, to specialize our // generic lambda's call operator. if (Sema::TemplateDeductionResult Result - = S.FinishTemplateArgumentDeduction(CallOpTemplate, - DeducedArguments, + = S.FinishTemplateArgumentDeduction(CallOpTemplate, + DeducedArguments, 0, CallOpSpecialized, TDInfo)) return Result; - + // If we need to deduce the return type, do so (instantiates the callop). if (GenericLambdaCallOperatorHasDeducedReturnType && CallOpSpecialized->getReturnType()->isUndeducedType()) - S.DeduceReturnType(CallOpSpecialized, + S.DeduceReturnType(CallOpSpecialized, CallOpSpecialized->getPointOfInstantiation(), /*Diagnose*/ true); - + // Check to see if the return type of the destination ptr-to-function // matches the return type of the call operator. if (!S.Context.hasSameType(CallOpSpecialized->getReturnType(), ReturnTypeOfDestFunctionPtr)) return Sema::TDK_NonDeducedMismatch; // Since we have succeeded in matching the source and destination - // ptr-to-functions (now including return type), and have successfully + // ptr-to-functions (now including return type), and have successfully // specialized our corresponding call operator, we are ready to // specialize the static invoker with the deduced arguments of our // ptr-to-function. @@ -3717,16 +3754,16 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker( #ifndef NDEBUG Sema::TemplateDeductionResult LLVM_ATTRIBUTE_UNUSED Result = #endif - S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0, + S.FinishTemplateArgumentDeduction(InvokerTemplate, DeducedArguments, 0, InvokerSpecialized, TDInfo); - assert(Result == Sema::TDK_Success && + assert(Result == Sema::TDK_Success && "If the call operator succeeded so should the invoker!"); // Set the result type to match the corresponding call operator // specialization's result type. if (GenericLambdaCallOperatorHasDeducedReturnType && InvokerSpecialized->getReturnType()->isUndeducedType()) { // Be sure to get the type to replace 'auto' with and not - // the full result type of the call op specialization + // the full result type of the call op specialization // to substitute into the 'auto' of the invoker and conversion // function. // For e.g. @@ -3738,14 +3775,14 @@ SpecializeCorrespondingLambdaCallOperatorAndInvoker( ->getDeducedType(); SubstAutoWithinFunctionReturnType(InvokerSpecialized, TypeToReplaceAutoWith, S); - SubstAutoWithinFunctionReturnType(ConversionSpecialized, + SubstAutoWithinFunctionReturnType(ConversionSpecialized, TypeToReplaceAutoWith, S); } - + // Ensure that static invoker doesn't have a const qualifier. - // FIXME: When creating the InvokerTemplate in SemaLambda.cpp + // FIXME: When creating the InvokerTemplate in SemaLambda.cpp // do not use the CallOperator's TypeSourceInfo which allows - // the const qualifier to leak through. + // the const qualifier to leak through. const FunctionProtoType *InvokerFPT = InvokerSpecialized-> getType().getTypePtr()->castAs<FunctionProtoType>(); FunctionProtoType::ExtProtoInfo EPI = InvokerFPT->getExtProtoInfo(); @@ -3857,7 +3894,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // Finish template argument deduction. FunctionDecl *ConversionSpecialized = nullptr; TemplateDeductionResult Result - = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, + = FinishTemplateArgumentDeduction(ConversionTemplate, Deduced, 0, ConversionSpecialized, Info); Specialization = cast_or_null<CXXConversionDecl>(ConversionSpecialized); @@ -3866,19 +3903,19 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // function to specialize the corresponding call operator. // e.g., int (*fp)(int) = [](auto a) { return a; }; if (Result == TDK_Success && isLambdaConversionOperator(ConversionGeneric)) { - + // Get the return type of the destination ptr-to-function we are converting - // to. This is necessary for matching the lambda call operator's return + // to. This is necessary for matching the lambda call operator's return // type to that of the destination ptr-to-function's return type. - assert(A->isPointerType() && + assert(A->isPointerType() && "Can only convert from lambda to ptr-to-function"); - const FunctionType *ToFunType = + const FunctionType *ToFunType = A->getPointeeType().getTypePtr()->getAs<FunctionType>(); const QualType DestFunctionPtrReturnType = ToFunType->getReturnType(); - // Create the corresponding specializations of the call operator and - // the static-invoker; and if the return type is auto, - // deduce the return type and check if it matches the + // Create the corresponding specializations of the call operator and + // the static-invoker; and if the return type is auto, + // deduce the return type and check if it matches the // DestFunctionPtrReturnType. // For instance: // auto L = [](auto a) { return f(a); }; @@ -3886,7 +3923,7 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, // char (*fp2)(int) = L; <-- Not OK. Result = SpecializeCorrespondingLambdaCallOperatorAndInvoker( - Specialization, Deduced, DestFunctionPtrReturnType, + Specialization, Deduced, DestFunctionPtrReturnType, Info, *this); } return Result; @@ -3908,16 +3945,22 @@ Sema::DeduceTemplateArguments(FunctionTemplateDecl *ConversionTemplate, /// \param Info the argument will be updated to provide additional information /// about template argument deduction. /// +/// \param IsAddressOfFunction If \c true, we are deducing as part of taking +/// the address of a function template in a context where we do not have a +/// target type, per [over.over]. If \c false, we are looking up a function +/// template specialization based on its signature, which only happens when +/// deducing a function parameter type from an argument that is a template-id +/// naming a function template specialization. +/// /// \returns the result of template argument deduction. -Sema::TemplateDeductionResult -Sema::DeduceTemplateArguments(FunctionTemplateDecl *FunctionTemplate, - TemplateArgumentListInfo *ExplicitTemplateArgs, - FunctionDecl *&Specialization, - TemplateDeductionInfo &Info, - bool InOverloadResolution) { +Sema::TemplateDeductionResult Sema::DeduceTemplateArguments( + FunctionTemplateDecl *FunctionTemplate, + TemplateArgumentListInfo *ExplicitTemplateArgs, + FunctionDecl *&Specialization, TemplateDeductionInfo &Info, + bool IsAddressOfFunction) { return DeduceTemplateArguments(FunctionTemplate, ExplicitTemplateArgs, QualType(), Specialization, Info, - InOverloadResolution); + IsAddressOfFunction); } namespace { @@ -3926,10 +3969,12 @@ namespace { class SubstituteAutoTransform : public TreeTransform<SubstituteAutoTransform> { QualType Replacement; + bool UseAutoSugar; public: - SubstituteAutoTransform(Sema &SemaRef, QualType Replacement) + SubstituteAutoTransform(Sema &SemaRef, QualType Replacement, + bool UseAutoSugar = true) : TreeTransform<SubstituteAutoTransform>(SemaRef), - Replacement(Replacement) {} + Replacement(Replacement), UseAutoSugar(UseAutoSugar) {} QualType TransformAutoType(TypeLocBuilder &TLB, AutoTypeLoc TL) { // If we're building the type pattern to deduce against, don't wrap the @@ -3939,19 +3984,17 @@ namespace { // auto &&lref = lvalue; // must transform into "rvalue reference to T" not "rvalue reference to // auto type deduced as T" in order for [temp.deduct.call]p3 to apply. - if (!Replacement.isNull() && isa<TemplateTypeParmType>(Replacement)) { + if (!UseAutoSugar) { + assert(isa<TemplateTypeParmType>(Replacement) && + "unexpected unsugared replacement kind"); QualType Result = Replacement; TemplateTypeParmTypeLoc NewTL = TLB.push<TemplateTypeParmTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; } else { - bool Dependent = - !Replacement.isNull() && Replacement->isDependentType(); - QualType Result = - SemaRef.Context.getAutoType(Dependent ? QualType() : Replacement, - TL.getTypePtr()->getKeyword(), - Dependent); + QualType Result = SemaRef.Context.getAutoType( + Replacement, TL.getTypePtr()->getKeyword(), Replacement.isNull()); AutoTypeLoc NewTL = TLB.push<AutoTypeLoc>(Result); NewTL.setNameLoc(TL.getNameLoc()); return Result; @@ -3974,18 +4017,29 @@ namespace { } Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result) { - return DeduceAutoType(Type->getTypeLoc(), Init, Result); +Sema::DeduceAutoType(TypeSourceInfo *Type, Expr *&Init, QualType &Result, + Optional<unsigned> DependentDeductionDepth) { + return DeduceAutoType(Type->getTypeLoc(), Init, Result, + DependentDeductionDepth); } /// \brief 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 +/// necessary to support partial ordering of templates using 'auto'.) +/// A dependent type will be produced when deducing from a dependent type. +/// /// \param Type the type pattern using the auto type-specifier. /// \param Init the initializer for the variable whose type is to be deduced. /// \param Result if type deduction was successful, this will be set to the /// deduced type. +/// \param DependentDeductionDepth Set if we should permit deduction in +/// 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. Sema::DeduceAutoResult -Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { +Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result, + Optional<unsigned> DependentDeductionDepth) { if (Init->getType()->isNonOverloadPlaceholderType()) { ExprResult NonPlaceholder = CheckPlaceholderExpr(Init); if (NonPlaceholder.isInvalid()) @@ -3993,12 +4047,16 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { Init = NonPlaceholder.get(); } - if (Init->isTypeDependent() || Type.getType()->isDependentType()) { - Result = SubstituteAutoTransform(*this, Context.DependentTy).Apply(Type); + if (!DependentDeductionDepth && + (Type.getType()->isDependentType() || Init->isTypeDependent())) { + Result = SubstituteAutoTransform(*this, QualType()).Apply(Type); assert(!Result.isNull() && "substituting DependentTy can't fail"); return DAR_Succeeded; } + // Find the depth of template parameter to synthesize. + unsigned Depth = DependentDeductionDepth.getValueOr(0); + // If this is a 'decltype(auto)' specifier, do the decltype dance. // Since 'decltype(auto)' can only occur at the top of the type, we // don't need to go digging for it. @@ -4031,15 +4089,16 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { LocalInstantiationScope InstScope(*this); // Build template<class TemplParam> void Func(FuncParam); - TemplateTypeParmDecl *TemplParam = - TemplateTypeParmDecl::Create(Context, nullptr, SourceLocation(), Loc, 0, 0, - nullptr, false, false); + TemplateTypeParmDecl *TemplParam = TemplateTypeParmDecl::Create( + Context, nullptr, SourceLocation(), Loc, Depth, 0, nullptr, false, false); QualType TemplArg = QualType(TemplParam->getTypeForDecl(), 0); NamedDecl *TemplParamPtr = TemplParam; - FixedSizeTemplateParameterListStorage<1> TemplateParamsSt( - Loc, Loc, TemplParamPtr, Loc); + FixedSizeTemplateParameterListStorage<1, false> TemplateParamsSt( + Loc, Loc, TemplParamPtr, Loc, nullptr); - QualType FuncParam = SubstituteAutoTransform(*this, TemplArg).Apply(Type); + QualType FuncParam = + SubstituteAutoTransform(*this, TemplArg, /*UseAutoSugar*/false) + .Apply(Type); assert(!FuncParam.isNull() && "substituting template parameter for 'auto' failed"); @@ -4049,7 +4108,18 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { QualType InitType = Init->getType(); unsigned TDF = 0; - TemplateDeductionInfo Info(Loc); + TemplateDeductionInfo Info(Loc, Depth); + + // If deduction failed, don't diagnose if the initializer is dependent; it + // might acquire a matching type in the instantiation. + auto DeductionFailed = [&]() -> DeduceAutoResult { + if (Init->isTypeDependent()) { + Result = SubstituteAutoTransform(*this, QualType()).Apply(Type); + assert(!Result.isNull() && "substituting DependentTy can't fail"); + return DAR_Succeeded; + } + return DAR_Failed; + }; InitListExpr *InitList = dyn_cast<InitListExpr>(Init); if (InitList) { @@ -4057,7 +4127,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { if (DeduceTemplateArgumentByListElement(*this, TemplateParamsSt.get(), TemplArg, InitList->getInit(i), Info, Deduced, TDF)) - return DAR_Failed; + return DeductionFailed(); } } else { if (!getLangOpts().CPlusPlus && Init->refersToBitField()) { @@ -4072,11 +4142,12 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { if (DeduceTemplateArgumentsByTypeMatch(*this, TemplateParamsSt.get(), FuncParam, InitType, Info, Deduced, TDF)) - return DAR_Failed; + return DeductionFailed(); } + // Could be null if somehow 'auto' appears in a non-deduced context. if (Deduced[0].getKind() != TemplateArgument::Type) - return DAR_Failed; + return DeductionFailed(); QualType DeducedType = Deduced[0].getAsType(); @@ -4088,7 +4159,7 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { Result = SubstituteAutoTransform(*this, DeducedType).Apply(Type); if (Result.isNull()) - return DAR_FailedAlreadyDiagnosed; + return DAR_FailedAlreadyDiagnosed; // Check that the deduced argument type is compatible with the original // argument type per C++ [temp.deduct.call]p4. @@ -4097,22 +4168,26 @@ Sema::DeduceAutoType(TypeLoc Type, Expr *&Init, QualType &Result) { Sema::OriginalCallArg(FuncParam,0,InitType), Result)) { Result = QualType(); - return DAR_Failed; + return DeductionFailed(); } return DAR_Succeeded; } -QualType Sema::SubstAutoType(QualType TypeWithAuto, +QualType Sema::SubstAutoType(QualType TypeWithAuto, QualType TypeToReplaceAuto) { - return SubstituteAutoTransform(*this, TypeToReplaceAuto). - TransformType(TypeWithAuto); + if (TypeToReplaceAuto->isDependentType()) + TypeToReplaceAuto = QualType(); + return SubstituteAutoTransform(*this, TypeToReplaceAuto) + .TransformType(TypeWithAuto); } -TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, +TypeSourceInfo* Sema::SubstAutoTypeSourceInfo(TypeSourceInfo *TypeWithAuto, QualType TypeToReplaceAuto) { - return SubstituteAutoTransform(*this, TypeToReplaceAuto). - TransformType(TypeWithAuto); + if (TypeToReplaceAuto->isDependentType()) + TypeToReplaceAuto = QualType(); + return SubstituteAutoTransform(*this, TypeToReplaceAuto) + .TransformType(TypeWithAuto); } void Sema::DiagnoseAutoDeductionFailure(VarDecl *VDecl, Expr *Init) { @@ -4284,6 +4359,10 @@ static bool isAtLeastAsSpecializedAs(Sema &S, if (Deduced[ArgIdx].isNull()) break; + // FIXME: We fail to implement [temp.deduct.type]p1 along this path. We need + // to substitute the deduced arguments back into the template and check that + // we get the right type. + if (ArgIdx == NumArgs) { // All template arguments were deduced. FT1 is at least as specialized // as FT2. @@ -4487,12 +4566,12 @@ UnresolvedSetIterator Sema::getMostSpecialized( // FIXME: Can we order the candidates in some sane way? for (UnresolvedSetIterator I = SpecBegin; I != SpecEnd; ++I) { PartialDiagnostic PD = CandidateDiag; - PD << getTemplateArgumentBindingsText( - cast<FunctionDecl>(*I)->getPrimaryTemplate()->getTemplateParameters(), - *cast<FunctionDecl>(*I)->getTemplateSpecializationArgs()); + const auto *FD = cast<FunctionDecl>(*I); + PD << FD << getTemplateArgumentBindingsText( + FD->getPrimaryTemplate()->getTemplateParameters(), + *FD->getTemplateSpecializationArgs()); if (!TargetType.isNull()) - HandleFunctionTypeMismatch(PD, cast<FunctionDecl>(*I)->getType(), - TargetType); + HandleFunctionTypeMismatch(PD, FD->getType(), TargetType); Diag((*I)->getLocation(), PD); } } @@ -4500,21 +4579,17 @@ UnresolvedSetIterator Sema::getMostSpecialized( return SpecEnd; } -/// \brief Returns the more specialized class template partial specialization -/// according to the rules of partial ordering of class template partial -/// specializations (C++ [temp.class.order]). -/// -/// \param PS1 the first class template partial specialization +/// Determine whether one partial specialization, P1, is at least as +/// specialized than another, P2. /// -/// \param PS2 the second class template partial specialization -/// -/// \returns the more specialized class template partial specialization. If -/// neither partial specialization is more specialized, returns NULL. -ClassTemplatePartialSpecializationDecl * -Sema::getMoreSpecializedPartialSpecialization( - ClassTemplatePartialSpecializationDecl *PS1, - ClassTemplatePartialSpecializationDecl *PS2, - SourceLocation Loc) { +/// \tparam TemplateLikeDecl The kind of P2, which must be a +/// TemplateDecl or {Class,Var}TemplatePartialSpecializationDecl. +/// \param T1 The injected-class-name of P1 (faked for a variable template). +/// \param T2 The injected-class-name of P2 (faked for a variable template). +template<typename TemplateLikeDecl> +static bool isAtLeastAsSpecializedAs(Sema &S, QualType T1, QualType T2, + TemplateLikeDecl *P2, + TemplateDeductionInfo &Info) { // C++ [temp.class.order]p1: // For two class template partial specializations, the first is at least as // specialized as the second if, given the following rewrite to two @@ -4540,37 +4615,50 @@ Sema::getMoreSpecializedPartialSpecialization( // template partial specialization's template arguments, for // example. SmallVector<DeducedTemplateArgument, 4> Deduced; - TemplateDeductionInfo Info(Loc); + // Determine whether P1 is at least as specialized as P2. + Deduced.resize(P2->getTemplateParameters()->size()); + if (DeduceTemplateArgumentsByTypeMatch(S, P2->getTemplateParameters(), + T2, T1, Info, Deduced, TDF_None, + /*PartialOrdering=*/true)) + return false; + + SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), + Deduced.end()); + Sema::InstantiatingTemplate Inst(S, Info.getLocation(), P2, DeducedArgs, + Info); + auto *TST1 = T1->castAs<TemplateSpecializationType>(); + if (FinishTemplateArgumentDeduction( + S, P2, /*PartialOrdering=*/true, + TemplateArgumentList(TemplateArgumentList::OnStack, + TST1->template_arguments()), + Deduced, Info)) + return false; + + return true; +} + +/// \brief Returns the more specialized class template partial specialization +/// according to the rules of partial ordering of class template partial +/// specializations (C++ [temp.class.order]). +/// +/// \param PS1 the first class template partial specialization +/// +/// \param PS2 the second class template partial specialization +/// +/// \returns the more specialized class template partial specialization. If +/// neither partial specialization is more specialized, returns NULL. +ClassTemplatePartialSpecializationDecl * +Sema::getMoreSpecializedPartialSpecialization( + ClassTemplatePartialSpecializationDecl *PS1, + ClassTemplatePartialSpecializationDecl *PS2, + SourceLocation Loc) { QualType PT1 = PS1->getInjectedSpecializationType(); QualType PT2 = PS2->getInjectedSpecializationType(); - // Determine whether PS1 is at least as specialized as PS2 - Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch(*this, - PS2->getTemplateParameters(), - PT2, PT1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true); - if (Better1) { - SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); - Better1 = !::FinishTemplateArgumentDeduction( - *this, PS2, PS1->getTemplateArgs(), Deduced, Info); - } - - // Determine whether PS2 is at least as specialized as PS1 - Deduced.clear(); - Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS1->getTemplateParameters(), PT1, PT2, Info, Deduced, TDF_None, - /*PartialOrdering=*/true); - if (Better2) { - SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), - Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); - Better2 = !::FinishTemplateArgumentDeduction( - *this, PS1, PS2->getTemplateArgs(), Deduced, Info); - } + TemplateDeductionInfo Info(Loc); + bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); + bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); if (Better1 == Better2) return nullptr; @@ -4578,18 +4666,26 @@ Sema::getMoreSpecializedPartialSpecialization( return Better1 ? PS1 : PS2; } -/// TODO: Unify with ClassTemplatePartialSpecializationDecl version? -/// May require unifying ClassTemplate(Partial)SpecializationDecl and -/// VarTemplate(Partial)SpecializationDecl with a new data -/// structure Template(Partial)SpecializationDecl, and -/// using Template(Partial)SpecializationDecl as input type. +bool Sema::isMoreSpecializedThanPrimary( + ClassTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { + ClassTemplateDecl *Primary = Spec->getSpecializedTemplate(); + QualType PrimaryT = Primary->getInjectedClassNameSpecialization(); + QualType PartialT = Spec->getInjectedSpecializationType(); + if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) + return false; + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); + return false; + } + return true; +} + VarTemplatePartialSpecializationDecl * Sema::getMoreSpecializedPartialSpecialization( VarTemplatePartialSpecializationDecl *PS1, VarTemplatePartialSpecializationDecl *PS2, SourceLocation Loc) { - SmallVector<DeducedTemplateArgument, 4> Deduced; - TemplateDeductionInfo Info(Loc); - + // Pretend the variable template specializations are class template + // specializations and form a fake injected class name type for comparison. assert(PS1->getSpecializedTemplate() == PS2->getSpecializedTemplate() && "the partial specializations being compared should specialize" " the same template."); @@ -4600,39 +4696,101 @@ Sema::getMoreSpecializedPartialSpecialization( QualType PT2 = Context.getTemplateSpecializationType( CanonTemplate, PS2->getTemplateArgs().asArray()); - // Determine whether PS1 is at least as specialized as PS2 - Deduced.resize(PS2->getTemplateParameters()->size()); - bool Better1 = !DeduceTemplateArgumentsByTypeMatch( - *this, PS2->getTemplateParameters(), PT2, PT1, Info, Deduced, TDF_None, - /*PartialOrdering=*/true); - if (Better1) { - SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(), - Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS2, DeducedArgs, Info); - Better1 = !::FinishTemplateArgumentDeduction(*this, PS2, - PS1->getTemplateArgs(), - Deduced, Info); + TemplateDeductionInfo Info(Loc); + bool Better1 = isAtLeastAsSpecializedAs(*this, PT1, PT2, PS2, Info); + bool Better2 = isAtLeastAsSpecializedAs(*this, PT2, PT1, PS1, Info); + + if (Better1 == Better2) + return nullptr; + + return Better1 ? PS1 : PS2; +} + +bool Sema::isMoreSpecializedThanPrimary( + VarTemplatePartialSpecializationDecl *Spec, TemplateDeductionInfo &Info) { + TemplateDecl *Primary = Spec->getSpecializedTemplate(); + // FIXME: Cache the injected template arguments rather than recomputing + // them for each partial specialization. + SmallVector<TemplateArgument, 8> PrimaryArgs; + Context.getInjectedTemplateArgs(Primary->getTemplateParameters(), + PrimaryArgs); + + TemplateName CanonTemplate = + Context.getCanonicalTemplateName(TemplateName(Primary)); + QualType PrimaryT = Context.getTemplateSpecializationType( + CanonTemplate, PrimaryArgs); + QualType PartialT = Context.getTemplateSpecializationType( + CanonTemplate, Spec->getTemplateArgs().asArray()); + if (!isAtLeastAsSpecializedAs(*this, PartialT, PrimaryT, Primary, Info)) + return false; + if (isAtLeastAsSpecializedAs(*this, PrimaryT, PartialT, Spec, Info)) { + Info.clearSFINAEDiagnostic(); + return false; } + return true; +} - // Determine whether PS2 is at least as specialized as PS1 - Deduced.clear(); - Deduced.resize(PS1->getTemplateParameters()->size()); - bool Better2 = !DeduceTemplateArgumentsByTypeMatch(*this, - PS1->getTemplateParameters(), - PT1, PT2, Info, Deduced, TDF_None, - /*PartialOrdering=*/true); - if (Better2) { - SmallVector<TemplateArgument, 4> DeducedArgs(Deduced.begin(),Deduced.end()); - InstantiatingTemplate Inst(*this, Loc, PS1, DeducedArgs, Info); - Better2 = !::FinishTemplateArgumentDeduction(*this, PS1, - PS2->getTemplateArgs(), - Deduced, Info); +bool Sema::isTemplateTemplateParameterAtLeastAsSpecializedAs( + TemplateParameterList *P, TemplateDecl *AArg, SourceLocation Loc) { + // C++1z [temp.arg.template]p4: (DR 150) + // A template template-parameter P is at least as specialized as a + // template template-argument A if, given the following rewrite to two + // function templates... + + // Rather than synthesize function templates, we merely perform the + // equivalent partial ordering by performing deduction directly on + // the template parameter lists of the template template parameters. + // + // Given an invented class template X with the template parameter list of + // A (including default arguments): + TemplateName X = Context.getCanonicalTemplateName(TemplateName(AArg)); + TemplateParameterList *A = AArg->getTemplateParameters(); + + // - Each function template has a single function parameter whose type is + // a specialization of X with template arguments corresponding to the + // template parameters from the respective function template + SmallVector<TemplateArgument, 8> AArgs; + Context.getInjectedTemplateArgs(A, AArgs); + + // Check P's arguments against A's parameter list. This will fill in default + // template arguments as needed. AArgs are already correct by construction. + // We can't just use CheckTemplateIdType because that will expand alias + // templates. + SmallVector<TemplateArgument, 4> PArgs; + { + SFINAETrap Trap(*this); + + Context.getInjectedTemplateArgs(P, PArgs); + TemplateArgumentListInfo PArgList(P->getLAngleLoc(), P->getRAngleLoc()); + for (unsigned I = 0, N = P->size(); I != N; ++I) { + // Unwrap packs that getInjectedTemplateArgs wrapped around pack + // expansions, to form an "as written" argument list. + TemplateArgument Arg = PArgs[I]; + if (Arg.getKind() == TemplateArgument::Pack) { + assert(Arg.pack_size() == 1 && Arg.pack_begin()->isPackExpansion()); + Arg = *Arg.pack_begin(); + } + PArgList.addArgument(getTrivialTemplateArgumentLoc( + Arg, QualType(), P->getParam(I)->getLocation())); + } + PArgs.clear(); + + // C++1z [temp.arg.template]p3: + // If the rewrite produces an invalid type, then P is not at least as + // specialized as A. + if (CheckTemplateArgumentList(AArg, Loc, PArgList, false, PArgs) || + Trap.hasErrorOccurred()) + return false; } - if (Better1 == Better2) - return nullptr; + QualType AType = Context.getTemplateSpecializationType(X, AArgs); + QualType PType = Context.getTemplateSpecializationType(X, PArgs); - return Better1? PS1 : PS2; + // ... the function template corresponding to P is at least as specialized + // as the function template corresponding to A according to the partial + // ordering rules for function templates. + TemplateDeductionInfo Info(Loc, A->getDepth()); + return isAtLeastAsSpecializedAs(*this, PType, AType, AArg, Info); } static void @@ -4679,6 +4837,11 @@ MarkUsedTemplateParameters(ASTContext &Ctx, if (NTTP->getDepth() == Depth) Used[NTTP->getIndex()] = true; + + // In C++1z mode, additional arguments may be deduced from the type of a + // non-type argument. + if (Ctx.getLangOpts().CPlusPlus1z) + MarkUsedTemplateParameters(Ctx, NTTP->getType(), OnlyDeduced, Depth, Used); } /// \brief Mark the template parameters that are used by the given @@ -4846,7 +5009,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, // not the last template argument, the entire template argument list is a // non-deduced context. if (OnlyDeduced && - hasPackExpansionBeforeEnd(Spec->getArgs(), Spec->getNumArgs())) + hasPackExpansionBeforeEnd(Spec->template_arguments())) break; for (unsigned I = 0, N = Spec->getNumArgs(); I != N; ++I) @@ -4925,7 +5088,7 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T, case Type::UnaryTransform: if (!OnlyDeduced) MarkUsedTemplateParameters(Ctx, - cast<UnaryTransformType>(T)->getUnderlyingType(), + cast<UnaryTransformType>(T)->getUnderlyingType(), OnlyDeduced, Depth, Used); break; @@ -5021,7 +5184,7 @@ Sema::MarkUsedTemplateParameters(const TemplateArgumentList &TemplateArgs, // the last template argument, the entire template argument list is a // non-deduced context. if (OnlyDeduced && - hasPackExpansionBeforeEnd(TemplateArgs.data(), TemplateArgs.size())) + hasPackExpansionBeforeEnd(TemplateArgs.asArray())) return; for (unsigned I = 0, N = TemplateArgs.size(); I != N; ++I) @@ -5054,7 +5217,7 @@ bool hasDeducibleTemplateParameters(Sema &S, TemplateParameterList *TemplateParams = FunctionTemplate->getTemplateParameters(); llvm::SmallBitVector Deduced(TemplateParams->size()); - ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(), + ::MarkUsedTemplateParameters(S.Context, T, true, TemplateParams->getDepth(), Deduced); return Deduced.any(); diff --git a/lib/Sema/SemaTemplateInstantiate.cpp b/lib/Sema/SemaTemplateInstantiate.cpp index 65a5633bf0d5c..160c9f090788d 100644 --- a/lib/Sema/SemaTemplateInstantiate.cpp +++ b/lib/Sema/SemaTemplateInstantiate.cpp @@ -15,6 +15,7 @@ #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/ASTLambda.h" +#include "clang/AST/ASTMutationListener.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/Expr.h" #include "clang/Basic/LangOptions.h" @@ -208,9 +209,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( sema::TemplateDeductionInfo *DeductionInfo) : SemaRef(SemaRef), SavedInNonInstantiationSFINAEContext( SemaRef.InNonInstantiationSFINAEContext) { - // Don't allow further instantiation if a fatal error has occcured. Any - // diagnostics we might have raised will not be visible. - if (SemaRef.Diags.hasFatalErrorOccurred()) { + // Don't allow further instantiation if a fatal error and an uncompilable + // error have occurred. Any diagnostics we might have raised will not be + // visible, and we do not need to construct a correct AST. + if (SemaRef.Diags.hasFatalErrorOccurred() && + SemaRef.Diags.hasUncompilableErrorOccurred()) { Invalid = true; return; } @@ -276,6 +279,17 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, + TemplateDecl *Template, + ArrayRef<TemplateArgument> TemplateArgs, + sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) + : InstantiatingTemplate( + SemaRef, + ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution, + PointOfInstantiation, InstantiationRange, Template, nullptr, + TemplateArgs, &DeductionInfo) {} + +Sema::InstantiatingTemplate::InstantiatingTemplate( + Sema &SemaRef, SourceLocation PointOfInstantiation, ClassTemplatePartialSpecializationDecl *PartialSpec, ArrayRef<TemplateArgument> TemplateArgs, sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) @@ -420,8 +434,7 @@ void Sema::PrintInstantiationStack() { if (isa<ClassTemplateSpecializationDecl>(Record)) DiagID = diag::note_template_class_instantiation_here; Diags.Report(Active->PointOfInstantiation, DiagID) - << Context.getTypeDeclType(Record) - << Active->InstantiationRange; + << Record << Active->InstantiationRange; } else if (FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { unsigned DiagID; if (Function->getPrimaryTemplate()) @@ -482,29 +495,43 @@ void Sema::PrintInstantiationStack() { break; } - case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: - if (ClassTemplatePartialSpecializationDecl *PartialSpec = - dyn_cast<ClassTemplatePartialSpecializationDecl>(Active->Entity)) { + case ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution: { + if (FunctionTemplateDecl *FnTmpl = + dyn_cast<FunctionTemplateDecl>(Active->Entity)) { Diags.Report(Active->PointOfInstantiation, - diag::note_partial_spec_deduct_instantiation_here) - << Context.getTypeDeclType(PartialSpec) - << getTemplateArgumentBindingsText( - PartialSpec->getTemplateParameters(), + diag::note_function_template_deduction_instantiation_here) + << FnTmpl + << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; } else { - FunctionTemplateDecl *FnTmpl - = cast<FunctionTemplateDecl>(Active->Entity); + bool IsVar = isa<VarTemplateDecl>(Active->Entity) || + isa<VarTemplateSpecializationDecl>(Active->Entity); + bool IsTemplate = false; + TemplateParameterList *Params; + if (auto *D = dyn_cast<TemplateDecl>(Active->Entity)) { + IsTemplate = true; + Params = D->getTemplateParameters(); + } else if (auto *D = dyn_cast<ClassTemplatePartialSpecializationDecl>( + Active->Entity)) { + Params = D->getTemplateParameters(); + } else if (auto *D = dyn_cast<VarTemplatePartialSpecializationDecl>( + Active->Entity)) { + Params = D->getTemplateParameters(); + } else { + llvm_unreachable("unexpected template kind"); + } + Diags.Report(Active->PointOfInstantiation, - diag::note_function_template_deduction_instantiation_here) - << FnTmpl - << getTemplateArgumentBindingsText(FnTmpl->getTemplateParameters(), - Active->TemplateArgs, + diag::note_deduced_template_arg_substitution_here) + << IsVar << IsTemplate << cast<NamedDecl>(Active->Entity) + << getTemplateArgumentBindingsText(Params, Active->TemplateArgs, Active->NumTemplateArgs) << Active->InstantiationRange; } break; + } case ActiveTemplateInstantiation::DefaultFunctionArgumentInstantiation: { ParmVarDecl *Param = cast<ParmVarDecl>(Active->Entity); @@ -1178,8 +1205,8 @@ ExprResult TemplateInstantiator::transformNonTypeTemplateParmRef( cast<PackExpansionType>(parm->getType())->getPattern(), TemplateArgs, loc, parm->getDeclName()); } else { - type = SemaRef.SubstType(parm->getType(), TemplateArgs, - loc, parm->getDeclName()); + type = SemaRef.SubstType(VD ? arg.getParamTypeForDecl() : arg.getNullPtrType(), + TemplateArgs, loc, parm->getDeclName()); } assert(!type.isNull() && "type substitution failed for param type"); assert(!type->isDependentType() && "param type still dependent"); @@ -1684,7 +1711,7 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, // Instantiate default arguments for methods of local classes (DR1484) // and non-defining declarations. Sema::ContextRAII SavedContext(*this, OwningFunc); - LocalInstantiationScope Local(*this); + LocalInstantiationScope Local(*this, true); ExprResult NewArg = SubstExpr(Arg, TemplateArgs); if (NewArg.isUsable()) { // It would be nice if we still had this. @@ -1858,62 +1885,6 @@ namespace clang { } } -/// Determine whether we would be unable to instantiate this template (because -/// it either has no definition, or is in the process of being instantiated). -static bool DiagnoseUninstantiableTemplate(Sema &S, - SourceLocation PointOfInstantiation, - TagDecl *Instantiation, - bool InstantiatedFromMember, - TagDecl *Pattern, - TagDecl *PatternDef, - TemplateSpecializationKind TSK, - bool Complain = true) { - if (PatternDef && !PatternDef->isBeingDefined()) { - NamedDecl *SuggestedDef = nullptr; - if (!S.hasVisibleDefinition(PatternDef, &SuggestedDef, - /*OnlyNeedComplete*/false)) { - // If we're allowed to diagnose this and recover, do so. - bool Recover = Complain && !S.isSFINAEContext(); - if (Complain) - S.diagnoseMissingImport(PointOfInstantiation, SuggestedDef, - Sema::MissingImportKind::Definition, Recover); - return !Recover; - } - return false; - } - - if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) { - // Say nothing - } else if (PatternDef) { - assert(PatternDef->isBeingDefined()); - S.Diag(PointOfInstantiation, - diag::err_template_instantiate_within_definition) - << (TSK != TSK_ImplicitInstantiation) - << S.Context.getTypeDeclType(Instantiation); - // Not much point in noting the template declaration here, since - // we're lexically inside it. - Instantiation->setInvalidDecl(); - } else if (InstantiatedFromMember) { - S.Diag(PointOfInstantiation, - diag::err_implicit_instantiate_member_undefined) - << S.Context.getTypeDeclType(Instantiation); - S.Diag(Pattern->getLocation(), diag::note_member_declared_at); - } else { - S.Diag(PointOfInstantiation, diag::err_template_instantiate_undefined) - << (TSK != TSK_ImplicitInstantiation) - << S.Context.getTypeDeclType(Instantiation); - S.Diag(Pattern->getLocation(), diag::note_template_decl_here); - } - - // In general, Instantiation isn't marked invalid to get more than one - // error for multiple undefined instantiations. But the code that does - // explicit declaration -> explicit definition conversion can't handle - // invalid declarations, so mark as invalid in that case. - if (TSK == TSK_ExplicitInstantiationDeclaration) - Instantiation->setInvalidDecl(); - return true; -} - /// \brief Instantiate the definition of a class from a given pattern. /// /// \param PointOfInstantiation The point of instantiation within the @@ -1944,7 +1915,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool Complain) { CXXRecordDecl *PatternDef = cast_or_null<CXXRecordDecl>(Pattern->getDefinition()); - if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation, + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberClass(), Pattern, PatternDef, TSK, Complain)) return true; @@ -2174,7 +2145,7 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, const MultiLevelTemplateArgumentList &TemplateArgs, TemplateSpecializationKind TSK) { EnumDecl *PatternDef = Pattern->getDefinition(); - if (DiagnoseUninstantiableTemplate(*this, PointOfInstantiation, Instantiation, + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Instantiation, Instantiation->getInstantiatedFromMemberEnum(), Pattern, PatternDef, TSK,/*Complain*/true)) return true; @@ -2251,14 +2222,10 @@ bool Sema::InstantiateInClassInitializer( if (!OldInit) { RecordDecl *PatternRD = Pattern->getParent(); RecordDecl *OutermostClass = PatternRD->getOuterLexicalRecordContext(); - if (OutermostClass == PatternRD) { - Diag(Pattern->getLocEnd(), diag::err_in_class_initializer_not_yet_parsed) - << PatternRD << Pattern; - } else { - Diag(Pattern->getLocEnd(), - diag::err_in_class_initializer_not_yet_parsed_outer_class) - << PatternRD << OutermostClass << Pattern; - } + Diag(PointOfInstantiation, + diag::err_in_class_initializer_not_yet_parsed) + << OutermostClass << Pattern; + Diag(Pattern->getLocEnd(), diag::note_in_class_initializer_not_yet_parsed); Instantiation->setInvalidDecl(); return true; } @@ -2294,6 +2261,9 @@ bool Sema::InstantiateInClassInitializer( ActOnFinishCXXInClassMemberInitializer( Instantiation, Init ? Init->getLocStart() : SourceLocation(), Init); + if (auto *L = getASTMutationListener()) + L->DefaultMemberInitializerInstantiated(Instantiation); + // Exit the scope of this instantiation. SavedContext.pop(); diff --git a/lib/Sema/SemaTemplateInstantiateDecl.cpp b/lib/Sema/SemaTemplateInstantiateDecl.cpp index dd3748fb5337a..7328dcb8760fa 100644 --- a/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -19,6 +19,7 @@ #include "clang/AST/Expr.h" #include "clang/AST/ExprCXX.h" #include "clang/AST/TypeLoc.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" @@ -178,7 +179,7 @@ static void instantiateDependentEnableIfAttr( return; Cond = Result.getAs<Expr>(); } - if (A->getCond()->isTypeDependent() && !Cond->isTypeDependent()) { + if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); if (Converted.isInvalid()) return; @@ -187,7 +188,7 @@ static void instantiateDependentEnableIfAttr( SmallVector<PartialDiagnosticAt, 8> Diags; if (A->getCond()->isValueDependent() && !Cond->isValueDependent() && - !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(Tmpl), + !Expr::isPotentialConstantExprUnevaluated(Cond, cast<FunctionDecl>(New), Diags)) { S.Diag(A->getLocation(), diag::err_enable_if_never_constant_expr); for (int I = 0, N = Diags.size(); I != N; ++I) @@ -331,8 +332,7 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } - const EnableIfAttr *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr); - if (EnableIf && EnableIf->getCond()->isValueDependent()) { + if (const auto *EnableIf = dyn_cast<EnableIfAttr>(TmplAttr)) { instantiateDependentEnableIfAttr(*this, TemplateArgs, EnableIf, Tmpl, New); continue; @@ -598,12 +598,37 @@ TemplateDeclInstantiator::VisitTypeAliasTemplateDecl(TypeAliasTemplateDecl *D) { return Inst; } +Decl *TemplateDeclInstantiator::VisitBindingDecl(BindingDecl *D) { + auto *NewBD = BindingDecl::Create(SemaRef.Context, Owner, D->getLocation(), + D->getIdentifier()); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewBD); + return NewBD; +} + +Decl *TemplateDeclInstantiator::VisitDecompositionDecl(DecompositionDecl *D) { + // Transform the bindings first. + SmallVector<BindingDecl*, 16> NewBindings; + for (auto *OldBD : D->bindings()) + NewBindings.push_back(cast<BindingDecl>(VisitBindingDecl(OldBD))); + ArrayRef<BindingDecl*> NewBindingArray = NewBindings; + + auto *NewDD = cast_or_null<DecompositionDecl>( + VisitVarDecl(D, /*InstantiatingVarTemplate=*/false, &NewBindingArray)); + + if (!NewDD || NewDD->isInvalidDecl()) + for (auto *NewBD : NewBindings) + NewBD->setInvalidDecl(); + + return NewDD; +} + Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { return VisitVarDecl(D, /*InstantiatingVarTemplate=*/false); } Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, - bool InstantiatingVarTemplate) { + bool InstantiatingVarTemplate, + ArrayRef<BindingDecl*> *Bindings) { // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), @@ -624,9 +649,15 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, SemaRef.adjustContextForLocalExternDecl(DC); // Build the instantiated declaration. - VarDecl *Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), - D->getLocation(), D->getIdentifier(), - DI->getType(), DI, D->getStorageClass()); + VarDecl *Var; + if (Bindings) + Var = DecompositionDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), + D->getLocation(), DI->getType(), DI, + D->getStorageClass(), *Bindings); + else + Var = VarDecl::Create(SemaRef.Context, DC, D->getInnerLocStart(), + D->getLocation(), D->getIdentifier(), DI->getType(), + DI, D->getStorageClass()); // In ARC, infer 'retaining' for variables of retainable type. if (SemaRef.getLangOpts().ObjCAutoRefCount && @@ -1840,11 +1871,13 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); + Method->setRangeEnd(Constructor->getLocEnd()); } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, Destructor->isInlineSpecified(), false); + Method->setRangeEnd(Destructor->getLocEnd()); } else if (CXXConversionDecl *Conversion = dyn_cast<CXXConversionDecl>(D)) { Method = CXXConversionDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -2052,18 +2085,18 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( ExpandedParameterPackTypes.reserve(D->getNumExpansionTypes()); ExpandedParameterPackTypesAsWritten.reserve(D->getNumExpansionTypes()); for (unsigned I = 0, N = D->getNumExpansionTypes(); I != N; ++I) { - TypeSourceInfo *NewDI =SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), - TemplateArgs, - D->getLocation(), - D->getDeclName()); + TypeSourceInfo *NewDI = + SemaRef.SubstType(D->getExpansionTypeSourceInfo(I), TemplateArgs, + D->getLocation(), D->getDeclName()); if (!NewDI) return nullptr; - ExpandedParameterPackTypesAsWritten.push_back(NewDI); - QualType NewT =SemaRef.CheckNonTypeTemplateParameterType(NewDI->getType(), - D->getLocation()); + QualType NewT = + SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation()); if (NewT.isNull()) return nullptr; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); ExpandedParameterPackTypes.push_back(NewT); } @@ -2103,12 +2136,12 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (!NewDI) return nullptr; - ExpandedParameterPackTypesAsWritten.push_back(NewDI); - QualType NewT = SemaRef.CheckNonTypeTemplateParameterType( - NewDI->getType(), - D->getLocation()); + QualType NewT = + SemaRef.CheckNonTypeTemplateParameterType(NewDI, D->getLocation()); if (NewT.isNull()) return nullptr; + + ExpandedParameterPackTypesAsWritten.push_back(NewDI); ExpandedParameterPackTypes.push_back(NewT); } @@ -2128,6 +2161,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( if (!NewPattern) return nullptr; + SemaRef.CheckNonTypeTemplateParameterType(NewPattern, D->getLocation()); DI = SemaRef.CheckPackExpansion(NewPattern, Expansion.getEllipsisLoc(), NumExpansions); if (!DI) @@ -2143,8 +2177,7 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( return nullptr; // Check that this type is acceptable for a non-type template parameter. - T = SemaRef.CheckNonTypeTemplateParameterType(DI->getType(), - D->getLocation()); + T = SemaRef.CheckNonTypeTemplateParameterType(DI, D->getLocation()); if (T.isNull()) { T = SemaRef.Context.IntTy; Invalid = true; @@ -2397,8 +2430,8 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { } if (!NewUD->isInvalidDecl() && - SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), SS, NameInfo, - D->getLocation())) + SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(), + SS, NameInfo, D->getLocation())) NewUD->setInvalidDecl(); SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D); @@ -2462,35 +2495,76 @@ Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl( return nullptr; } -Decl * TemplateDeclInstantiator - ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { - NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), - TemplateArgs); - if (!QualifierLoc) - return nullptr; +template <typename T> +Decl *TemplateDeclInstantiator::instantiateUnresolvedUsingDecl( + T *D, bool InstantiatingPackElement) { + // If this is a pack expansion, expand it now. + if (D->isPackExpansion() && !InstantiatingPackElement) { + SmallVector<UnexpandedParameterPack, 2> Unexpanded; + SemaRef.collectUnexpandedParameterPacks(D->getQualifierLoc(), Unexpanded); + SemaRef.collectUnexpandedParameterPacks(D->getNameInfo(), Unexpanded); - CXXScopeSpec SS; - SS.Adopt(QualifierLoc); + // Determine whether the set of unexpanded parameter packs can and should + // be expanded. + bool Expand = true; + bool RetainExpansion = false; + Optional<unsigned> NumExpansions; + if (SemaRef.CheckParameterPacksForExpansion( + D->getEllipsisLoc(), D->getSourceRange(), Unexpanded, TemplateArgs, + Expand, RetainExpansion, NumExpansions)) + return nullptr; - // Since NameInfo refers to a typename, it cannot be a C++ special name. - // Hence, no transformation is required for it. - DeclarationNameInfo NameInfo(D->getDeclName(), D->getLocation()); - NamedDecl *UD = - SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(), - D->getUsingLoc(), SS, NameInfo, nullptr, - /*instantiation*/ true, - /*typename*/ true, D->getTypenameLoc()); - if (UD) - SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D); + // This declaration cannot appear within a function template signature, + // so we can't have a partial argument list for a parameter pack. + assert(!RetainExpansion && + "should never need to retain an expansion for UsingPackDecl"); - return UD; -} + if (!Expand) { + // We cannot fully expand the pack expansion now, so substitute into the + // pattern and create a new pack expansion. + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, -1); + return instantiateUnresolvedUsingDecl(D, true); + } + + // Within a function, we don't have any normal way to check for conflicts + // between shadow declarations from different using declarations in the + // same pack expansion, but this is always ill-formed because all expansions + // must produce (conflicting) enumerators. + // + // Sadly we can't just reject this in the template definition because it + // could be valid if the pack is empty or has exactly one expansion. + if (D->getDeclContext()->isFunctionOrMethod() && *NumExpansions > 1) { + SemaRef.Diag(D->getEllipsisLoc(), + diag::err_using_decl_redeclaration_expansion); + return nullptr; + } + + // Instantiate the slices of this pack and build a UsingPackDecl. + SmallVector<NamedDecl*, 8> Expansions; + for (unsigned I = 0; I != *NumExpansions; ++I) { + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(SemaRef, I); + Decl *Slice = instantiateUnresolvedUsingDecl(D, true); + if (!Slice) + return nullptr; + // Note that we can still get unresolved using declarations here, if we + // had arguments for all packs but the pattern also contained other + // template arguments (this only happens during partial substitution, eg + // into the body of a generic lambda in a function template). + Expansions.push_back(cast<NamedDecl>(Slice)); + } + + auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions); + if (isDeclWithinFunction(D)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD); + return NewD; + } + + UnresolvedUsingTypenameDecl *TD = dyn_cast<UnresolvedUsingTypenameDecl>(D); + SourceLocation TypenameLoc = TD ? TD->getTypenameLoc() : SourceLocation(); -Decl * TemplateDeclInstantiator - ::VisitUnresolvedUsingValueDecl(UnresolvedUsingValueDecl *D) { NestedNameSpecifierLoc QualifierLoc - = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), TemplateArgs); + = SemaRef.SubstNestedNameSpecifierLoc(D->getQualifierLoc(), + TemplateArgs); if (!QualifierLoc) return nullptr; @@ -2500,17 +2574,48 @@ Decl * TemplateDeclInstantiator DeclarationNameInfo NameInfo = SemaRef.SubstDeclarationNameInfo(D->getNameInfo(), TemplateArgs); - NamedDecl *UD = - SemaRef.BuildUsingDeclaration(/*Scope*/ nullptr, D->getAccess(), - D->getUsingLoc(), SS, NameInfo, nullptr, - /*instantiation*/ true, - /*typename*/ false, SourceLocation()); + // Produce a pack expansion only if we're not instantiating a particular + // slice of a pack expansion. + bool InstantiatingSlice = D->getEllipsisLoc().isValid() && + SemaRef.ArgumentPackSubstitutionIndex != -1; + SourceLocation EllipsisLoc = + InstantiatingSlice ? SourceLocation() : D->getEllipsisLoc(); + + NamedDecl *UD = SemaRef.BuildUsingDeclaration( + /*Scope*/ nullptr, D->getAccess(), D->getUsingLoc(), + /*HasTypename*/ TD, TypenameLoc, SS, NameInfo, EllipsisLoc, nullptr, + /*IsInstantiation*/ true); if (UD) - SemaRef.Context.setInstantiatedFromUsingDecl(cast<UsingDecl>(UD), D); + SemaRef.Context.setInstantiatedFromUsingDecl(UD, D); return UD; } +Decl *TemplateDeclInstantiator::VisitUnresolvedUsingTypenameDecl( + UnresolvedUsingTypenameDecl *D) { + return instantiateUnresolvedUsingDecl(D); +} + +Decl *TemplateDeclInstantiator::VisitUnresolvedUsingValueDecl( + UnresolvedUsingValueDecl *D) { + return instantiateUnresolvedUsingDecl(D); +} + +Decl *TemplateDeclInstantiator::VisitUsingPackDecl(UsingPackDecl *D) { + SmallVector<NamedDecl*, 8> Expansions; + for (auto *UD : D->expansions()) { + if (auto *NewUD = + SemaRef.FindInstantiatedDecl(D->getLocation(), UD, TemplateArgs)) + Expansions.push_back(cast<NamedDecl>(NewUD)); + else + return nullptr; + } + + auto *NewD = SemaRef.BuildUsingPackDecl(D, Expansions); + if (isDeclWithinFunction(D)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewD); + return NewD; +} Decl *TemplateDeclInstantiator::VisitClassScopeFunctionSpecializationDecl( ClassScopeFunctionSpecializationDecl *Decl) { @@ -2922,10 +3027,14 @@ TemplateDeclInstantiator::SubstTemplateParams(TemplateParameterList *L) { if (Invalid) return nullptr; + // Note: we substitute into associated constraints later + Expr *const UninstantiatedRequiresClause = L->getRequiresClause(); + TemplateParameterList *InstL = TemplateParameterList::Create(SemaRef.Context, L->getTemplateLoc(), L->getLAngleLoc(), Params, - L->getRAngleLoc()); + L->getRAngleLoc(), + UninstantiatedRequiresClause); return InstL; } @@ -2977,6 +3086,12 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( Converted)) return nullptr; + // Check these arguments are valid for a template partial specialization. + if (SemaRef.CheckTemplatePartialSpecializationArgs( + PartialSpec->getLocation(), ClassTemplate, InstTemplateArgs.size(), + Converted)) + return nullptr; + // Figure out where to insert this class template partial specialization // in the member template's set of class template partial specializations. void *InsertPos = nullptr; @@ -3047,6 +3162,9 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); + // Check the completed partial specialization. + SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec); + // Add this partial specialization to the set of class template partial // specializations. ClassTemplate->AddPartialSpecialization(InstPartialSpec, @@ -3099,6 +3217,12 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( InstTemplateArgs, false, Converted)) return nullptr; + // Check these arguments are valid for a template partial specialization. + if (SemaRef.CheckTemplatePartialSpecializationArgs( + PartialSpec->getLocation(), VarTemplate, InstTemplateArgs.size(), + Converted)) + return nullptr; + // Figure out where to insert this variable template partial specialization // in the member template's set of variable template partial specializations. void *InsertPos = nullptr; @@ -3173,6 +3297,9 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( InstPartialSpec->setInstantiatedFromMember(PartialSpec); InstPartialSpec->setTypeAsWritten(WrittenTy); + // Check the completed partial specialization. + SemaRef.CheckTemplatePartialSpecialization(InstPartialSpec); + // Add this partial specialization to the set of variable template partial // specializations. The instantiation of the initializer is not necessary. VarTemplate->AddPartialSpecialization(InstPartialSpec, /*InsertPos=*/nullptr); @@ -3516,7 +3643,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, // Never instantiate an explicit specialization except if it is a class scope // explicit specialization. - if (Function->getTemplateSpecializationKind() == TSK_ExplicitSpecialization && + TemplateSpecializationKind TSK = Function->getTemplateSpecializationKind(); + if (TSK == TSK_ExplicitSpecialization && !Function->getClassScopeSpecializationPattern()) return; @@ -3524,13 +3652,40 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, const FunctionDecl *PatternDecl = Function->getTemplateInstantiationPattern(); assert(PatternDecl && "instantiating a non-template"); - Stmt *Pattern = PatternDecl->getBody(PatternDecl); - assert(PatternDecl && "template definition is not a template"); - if (!Pattern) { - // Try to find a defaulted definition - PatternDecl->isDefined(PatternDecl); + const FunctionDecl *PatternDef = PatternDecl->getDefinition(); + Stmt *Pattern = nullptr; + if (PatternDef) { + Pattern = PatternDef->getBody(PatternDef); + PatternDecl = PatternDef; + } + + // FIXME: We need to track the instantiation stack in order to know which + // definitions should be visible within this instantiation. + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Function, + Function->getInstantiatedFromMemberFunction(), + PatternDecl, PatternDef, TSK, + /*Complain*/DefinitionRequired)) { + if (DefinitionRequired) + Function->setInvalidDecl(); + else if (TSK == TSK_ExplicitInstantiationDefinition) { + // Try again at the end of the translation unit (at which point a + // definition will be required). + assert(!Recursive); + PendingInstantiations.push_back( + std::make_pair(Function, PointOfInstantiation)); + } else if (TSK == TSK_ImplicitInstantiation) { + if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { + Diag(PointOfInstantiation, diag::warn_func_template_missing) + << Function; + Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); + if (getLangOpts().CPlusPlus11) + Diag(PointOfInstantiation, diag::note_inst_declaration_hint) + << Function; + } + } + + return; } - assert(PatternDecl && "template definition is not a template"); // Postpone late parsed template instantiations. if (PatternDecl->isLateTemplateParsed() && @@ -3558,58 +3713,23 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, if (PatternDecl->isFromASTFile()) ExternalSource->ReadLateParsedTemplates(LateParsedTemplateMap); - LateParsedTemplate *LPT = LateParsedTemplateMap.lookup(PatternDecl); - assert(LPT && "missing LateParsedTemplate"); - LateTemplateParser(OpaqueParser, *LPT); + auto LPTIter = LateParsedTemplateMap.find(PatternDecl); + assert(LPTIter != LateParsedTemplateMap.end() && + "missing LateParsedTemplate"); + LateTemplateParser(OpaqueParser, *LPTIter->second); Pattern = PatternDecl->getBody(PatternDecl); } - // FIXME: Check that the definition is visible before trying to instantiate - // it. This requires us to track the instantiation stack in order to know - // which definitions should be visible. - - if (!Pattern && !PatternDecl->isDefaulted()) { - if (DefinitionRequired) { - if (Function->getPrimaryTemplate()) - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_func_template) - << Function->getPrimaryTemplate(); - else - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_member) - << 1 << Function->getDeclName() << Function->getDeclContext(); - - if (PatternDecl) - Diag(PatternDecl->getLocation(), - diag::note_explicit_instantiation_here); - Function->setInvalidDecl(); - } else if (Function->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { - assert(!Recursive); - PendingInstantiations.push_back( - std::make_pair(Function, PointOfInstantiation)); - } else if (Function->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { - if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { - Diag(PointOfInstantiation, diag::warn_func_template_missing) - << Function; - Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); - if (getLangOpts().CPlusPlus11) - Diag(PointOfInstantiation, diag::note_inst_declaration_hint) - << Function; - } - } - - return; - } + // Note, we should never try to instantiate a deleted function template. + assert((Pattern || PatternDecl->isDefaulted()) && + "unexpected kind of function template definition"); // C++1y [temp.explicit]p10: // Except for inline functions, declarations with types deduced from their // initializer or return value, and class template specializations, other // explicit instantiation declarations have the effect of suppressing the // implicit instantiation of the entity to which they refer. - if (Function->getTemplateSpecializationKind() == - TSK_ExplicitInstantiationDeclaration && + if (TSK == TSK_ExplicitInstantiationDeclaration && !PatternDecl->isInlined() && !PatternDecl->getReturnType()->getContainedAutoType()) return; @@ -3631,6 +3751,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), "instantiating function definition"); + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Function->setHidden(false); + // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); @@ -4035,6 +4159,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), "instantiating variable initializer"); + // The instantiation is visible here, even if it was first declared in an + // unimported module. + Var->setHidden(false); + // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate // later, while we're still within our own instantiation context. @@ -4083,33 +4211,17 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, Def = PatternDecl->getDefinition(); } - // FIXME: Check that the definition is visible before trying to instantiate - // it. This requires us to track the instantiation stack in order to know - // which definitions should be visible. + TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); // If we don't have a definition of the variable template, we won't perform // any instantiation. Rather, we rely on the user to instantiate this // definition (or provide a specialization for it) in another translation // unit. - if (!Def) { - if (DefinitionRequired) { - if (VarSpec) - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_var_template) << Var; - else - Diag(PointOfInstantiation, - diag::err_explicit_instantiation_undefined_member) - << 2 << Var->getDeclName() << Var->getDeclContext(); - Diag(PatternDecl->getLocation(), - diag::note_explicit_instantiation_here); - if (VarSpec) - Var->setInvalidDecl(); - } else if (Var->getTemplateSpecializationKind() - == TSK_ExplicitInstantiationDefinition) { + if (!Def && !DefinitionRequired) { + if (TSK == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( std::make_pair(Var, PointOfInstantiation)); - } else if (Var->getTemplateSpecializationKind() - == TSK_ImplicitInstantiation) { + } else if (TSK == TSK_ImplicitInstantiation) { // Warn about missing definition at the end of translation unit. if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { Diag(PointOfInstantiation, diag::warn_var_template_missing) @@ -4118,12 +4230,20 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, if (getLangOpts().CPlusPlus11) Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var; } + return; } - return; } - TemplateSpecializationKind TSK = Var->getTemplateSpecializationKind(); + // FIXME: We need to track the instantiation stack in order to know which + // definitions should be visible within this instantiation. + // FIXME: Produce diagnostics when Var->getInstantiatedFromStaticDataMember(). + if (DiagnoseUninstantiableTemplate(PointOfInstantiation, Var, + /*InstantiatedFromMember*/false, + PatternDecl, Def, TSK, + /*Complain*/DefinitionRequired)) + return; + // Never instantiate an explicit specialization. if (TSK == TSK_ExplicitSpecialization) @@ -4483,22 +4603,36 @@ static bool isInstantiationOf(UsingShadowDecl *Pattern, Pattern); } -static bool isInstantiationOf(UsingDecl *Pattern, - UsingDecl *Instance, +static bool isInstantiationOf(UsingDecl *Pattern, UsingDecl *Instance, ASTContext &C) { return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); } -static bool isInstantiationOf(UnresolvedUsingValueDecl *Pattern, - UsingDecl *Instance, - ASTContext &C) { - return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); -} - -static bool isInstantiationOf(UnresolvedUsingTypenameDecl *Pattern, - UsingDecl *Instance, - ASTContext &C) { - return declaresSameEntity(C.getInstantiatedFromUsingDecl(Instance), Pattern); +template<typename T> +static bool isInstantiationOfUnresolvedUsingDecl(T *Pattern, Decl *Other, + ASTContext &Ctx) { + // An unresolved using declaration can instantiate to an unresolved using + // declaration, or to a using declaration or a using declaration pack. + // + // Multiple declarations can claim to be instantiated from an unresolved + // using declaration if it's a pack expansion. We want the UsingPackDecl + // in that case, not the individual UsingDecls within the pack. + bool OtherIsPackExpansion; + NamedDecl *OtherFrom; + if (auto *OtherUUD = dyn_cast<T>(Other)) { + OtherIsPackExpansion = OtherUUD->isPackExpansion(); + OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUUD); + } else if (auto *OtherUPD = dyn_cast<UsingPackDecl>(Other)) { + OtherIsPackExpansion = true; + OtherFrom = OtherUPD->getInstantiatedFromUsingDecl(); + } else if (auto *OtherUD = dyn_cast<UsingDecl>(Other)) { + OtherIsPackExpansion = false; + OtherFrom = Ctx.getInstantiatedFromUsingDecl(OtherUD); + } else { + return false; + } + return Pattern->isPackExpansion() == OtherIsPackExpansion && + declaresSameEntity(OtherFrom, Pattern); } static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, @@ -4519,49 +4653,40 @@ static bool isInstantiationOfStaticDataMember(VarDecl *Pattern, // Other is the prospective instantiation // D is the prospective pattern static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { - if (D->getKind() != Other->getKind()) { - if (UnresolvedUsingTypenameDecl *UUD - = dyn_cast<UnresolvedUsingTypenameDecl>(D)) { - if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { - return isInstantiationOf(UUD, UD, Ctx); - } - } + if (auto *UUD = dyn_cast<UnresolvedUsingTypenameDecl>(D)) + return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx); - if (UnresolvedUsingValueDecl *UUD - = dyn_cast<UnresolvedUsingValueDecl>(D)) { - if (UsingDecl *UD = dyn_cast<UsingDecl>(Other)) { - return isInstantiationOf(UUD, UD, Ctx); - } - } + if (auto *UUD = dyn_cast<UnresolvedUsingValueDecl>(D)) + return isInstantiationOfUnresolvedUsingDecl(UUD, Other, Ctx); + if (D->getKind() != Other->getKind()) return false; - } - if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(Other)) + if (auto *Record = dyn_cast<CXXRecordDecl>(Other)) return isInstantiationOf(cast<CXXRecordDecl>(D), Record); - if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Other)) + if (auto *Function = dyn_cast<FunctionDecl>(Other)) return isInstantiationOf(cast<FunctionDecl>(D), Function); - if (EnumDecl *Enum = dyn_cast<EnumDecl>(Other)) + if (auto *Enum = dyn_cast<EnumDecl>(Other)) return isInstantiationOf(cast<EnumDecl>(D), Enum); - if (VarDecl *Var = dyn_cast<VarDecl>(Other)) + if (auto *Var = dyn_cast<VarDecl>(Other)) if (Var->isStaticDataMember()) return isInstantiationOfStaticDataMember(cast<VarDecl>(D), Var); - if (ClassTemplateDecl *Temp = dyn_cast<ClassTemplateDecl>(Other)) + if (auto *Temp = dyn_cast<ClassTemplateDecl>(Other)) return isInstantiationOf(cast<ClassTemplateDecl>(D), Temp); - if (FunctionTemplateDecl *Temp = dyn_cast<FunctionTemplateDecl>(Other)) + if (auto *Temp = dyn_cast<FunctionTemplateDecl>(Other)) return isInstantiationOf(cast<FunctionTemplateDecl>(D), Temp); - if (ClassTemplatePartialSpecializationDecl *PartialSpec - = dyn_cast<ClassTemplatePartialSpecializationDecl>(Other)) + if (auto *PartialSpec = + dyn_cast<ClassTemplatePartialSpecializationDecl>(Other)) return isInstantiationOf(cast<ClassTemplatePartialSpecializationDecl>(D), PartialSpec); - if (FieldDecl *Field = dyn_cast<FieldDecl>(Other)) { + if (auto *Field = dyn_cast<FieldDecl>(Other)) { if (!Field->getDeclName()) { // This is an unnamed field. return declaresSameEntity(Ctx.getInstantiatedFromUnnamedFieldDecl(Field), @@ -4569,14 +4694,14 @@ static bool isInstantiationOf(ASTContext &Ctx, NamedDecl *D, Decl *Other) { } } - if (UsingDecl *Using = dyn_cast<UsingDecl>(Other)) + if (auto *Using = dyn_cast<UsingDecl>(Other)) return isInstantiationOf(cast<UsingDecl>(D), Using, Ctx); - if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(Other)) + if (auto *Shadow = dyn_cast<UsingShadowDecl>(Other)) return isInstantiationOf(cast<UsingShadowDecl>(D), Shadow, Ctx); - return D->getDeclName() && isa<NamedDecl>(Other) && - D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); + return D->getDeclName() && + D->getDeclName() == cast<NamedDecl>(Other)->getDeclName(); } template<typename ForwardIterator> @@ -4812,6 +4937,8 @@ NamedDecl *Sema::FindInstantiatedDecl(SourceLocation Loc, NamedDecl *D, } NamedDecl *Result = nullptr; + // FIXME: If the name is a dependent name, this lookup won't necessarily + // find it. Does that ever matter? if (D->getDeclName()) { DeclContext::lookup_result Found = ParentDC->lookup(D->getDeclName()); Result = findInstantiationOf(Context, D, Found.begin(), Found.end()); diff --git a/lib/Sema/SemaTemplateVariadic.cpp b/lib/Sema/SemaTemplateVariadic.cpp index 06afe87f515ee..54556b505ee0f 100644 --- a/lib/Sema/SemaTemplateVariadic.cpp +++ b/lib/Sema/SemaTemplateVariadic.cpp @@ -390,21 +390,18 @@ void Sema::collectUnexpandedParameterPacks(QualType T, void Sema::collectUnexpandedParameterPacks(TypeLoc TL, SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded).TraverseTypeLoc(TL); -} +} -void Sema::collectUnexpandedParameterPacks(CXXScopeSpec &SS, - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { - NestedNameSpecifier *Qualifier = SS.getScopeRep(); - if (!Qualifier) - return; - - NestedNameSpecifierLoc QualifierLoc(Qualifier, SS.location_data()); +void Sema::collectUnexpandedParameterPacks( + NestedNameSpecifierLoc NNS, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) - .TraverseNestedNameSpecifierLoc(QualifierLoc); + .TraverseNestedNameSpecifierLoc(NNS); } -void Sema::collectUnexpandedParameterPacks(const DeclarationNameInfo &NameInfo, - SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { +void Sema::collectUnexpandedParameterPacks( + const DeclarationNameInfo &NameInfo, + SmallVectorImpl<UnexpandedParameterPack> &Unexpanded) { CollectUnexpandedParameterPacksVisitor(Unexpanded) .TraverseDeclarationNameInfo(NameInfo); } @@ -639,7 +636,7 @@ bool Sema::CheckParameterPacksForExpansion( return true; } } - + return false; } @@ -772,7 +769,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { } if (Chunk.Fun.getExceptionSpecType() == EST_Dynamic) { - for (unsigned i = 0; i != Chunk.Fun.NumExceptions; ++i) { + for (unsigned i = 0; i != Chunk.Fun.getNumExceptions(); ++i) { if (Chunk.Fun.Exceptions[i] .Ty.get() ->containsUnexpandedParameterPack()) @@ -936,12 +933,71 @@ Sema::getTemplateArgumentPackExpansionPattern( llvm_unreachable("Invalid TemplateArgument Kind!"); } +Optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) { + assert(Arg.containsUnexpandedParameterPack()); + + // If this is a substituted pack, grab that pack. If not, we don't know + // the size yet. + // FIXME: We could find a size in more cases by looking for a substituted + // pack anywhere within this argument, but that's not necessary in the common + // case for 'sizeof...(A)' handling. + TemplateArgument Pack; + switch (Arg.getKind()) { + case TemplateArgument::Type: + if (auto *Subst = Arg.getAsType()->getAs<SubstTemplateTypeParmPackType>()) + Pack = Subst->getArgumentPack(); + else + return None; + break; + + case TemplateArgument::Expression: + if (auto *Subst = + dyn_cast<SubstNonTypeTemplateParmPackExpr>(Arg.getAsExpr())) + Pack = Subst->getArgumentPack(); + else if (auto *Subst = dyn_cast<FunctionParmPackExpr>(Arg.getAsExpr())) { + for (ParmVarDecl *PD : *Subst) + if (PD->isParameterPack()) + return None; + return Subst->getNumExpansions(); + } else + return None; + break; + + case TemplateArgument::Template: + if (SubstTemplateTemplateParmPackStorage *Subst = + Arg.getAsTemplate().getAsSubstTemplateTemplateParmPack()) + Pack = Subst->getArgumentPack(); + else + return None; + break; + + case TemplateArgument::Declaration: + case TemplateArgument::NullPtr: + case TemplateArgument::TemplateExpansion: + case TemplateArgument::Integral: + case TemplateArgument::Pack: + case TemplateArgument::Null: + return None; + } + + // Check that no argument in the pack is itself a pack expansion. + for (TemplateArgument Elem : Pack.pack_elements()) { + // There's no point recursing in this case; we would have already + // expanded this pack expansion into the enclosing pack if we could. + if (Elem.isPackExpansion()) + return None; + } + return Pack.pack_size(); +} + static void CheckFoldOperand(Sema &S, Expr *E) { if (!E) return; E = E->IgnoreImpCasts(); - if (isa<BinaryOperator>(E) || isa<AbstractConditionalOperator>(E)) { + auto *OCE = dyn_cast<CXXOperatorCallExpr>(E); + if ((OCE && OCE->isInfixBinaryOp()) || isa<BinaryOperator>(E) || + isa<AbstractConditionalOperator>(E)) { S.Diag(E->getExprLoc(), diag::err_fold_expression_bad_operand) << E->getSourceRange() << FixItHint::CreateInsertion(E->getLocStart(), "(") diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f3747eaa5cb55..ae9a3ee790e1a 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -106,6 +106,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_FastCall: \ case AttributeList::AT_StdCall: \ case AttributeList::AT_ThisCall: \ + case AttributeList::AT_RegCall: \ case AttributeList::AT_Pascal: \ case AttributeList::AT_SwiftCall: \ case AttributeList::AT_VectorCall: \ @@ -717,6 +718,7 @@ static void maybeSynthesizeBlockSignature(TypeProcessingState &state, /*NumExceptions=*/0, /*NoexceptExpr=*/nullptr, /*ExceptionSpecTokens=*/nullptr, + /*DeclsInPrototype=*/None, loc, loc, declarator)); // For consistency, make sure the state still has us as processing @@ -1000,55 +1002,27 @@ static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, return S.Context.getObjCObjectType(type, finalTypeArgs, { }, false); } -/// Apply Objective-C protocol qualifiers to the given type. -static QualType applyObjCProtocolQualifiers( - Sema &S, SourceLocation loc, SourceRange range, QualType type, - ArrayRef<ObjCProtocolDecl *> protocols, - const SourceLocation *protocolLocs, - bool failOnError = false) { - ASTContext &ctx = S.Context; - if (const ObjCObjectType *objT = dyn_cast<ObjCObjectType>(type.getTypePtr())){ - // FIXME: Check for protocols to which the class type is already - // known to conform. - - return ctx.getObjCObjectType(objT->getBaseType(), - objT->getTypeArgsAsWritten(), - protocols, - objT->isKindOfTypeAsWritten()); - } - - if (type->isObjCObjectType()) { - // Silently overwrite any existing protocol qualifiers. - // TODO: determine whether that's the right thing to do. - - // FIXME: Check for protocols to which the class type is already - // known to conform. - return ctx.getObjCObjectType(type, { }, protocols, false); - } - - // id<protocol-list> - if (type->isObjCIdType()) { - const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); - type = ctx.getObjCObjectType(ctx.ObjCBuiltinIdTy, { }, protocols, - objPtr->isKindOfType()); - return ctx.getObjCObjectPointerType(type); - } - - // Class<protocol-list> - if (type->isObjCClassType()) { - const ObjCObjectPointerType *objPtr = type->castAs<ObjCObjectPointerType>(); - type = ctx.getObjCObjectType(ctx.ObjCBuiltinClassTy, { }, protocols, - objPtr->isKindOfType()); - return ctx.getObjCObjectPointerType(type); +QualType Sema::BuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc, + bool FailOnError) { + QualType Result = QualType(Decl->getTypeForDecl(), 0); + if (!Protocols.empty()) { + bool HasError; + Result = Context.applyObjCProtocolQualifiers(Result, Protocols, + HasError); + if (HasError) { + Diag(SourceLocation(), diag::err_invalid_protocol_qualifiers) + << SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc); + if (FailOnError) Result = QualType(); + } + if (FailOnError && Result.isNull()) + return QualType(); } - S.Diag(loc, diag::err_invalid_protocol_qualifiers) - << range; - - if (failOnError) - return QualType(); - - return type; + return Result; } QualType Sema::BuildObjCObjectType(QualType BaseType, @@ -1072,12 +1046,14 @@ QualType Sema::BuildObjCObjectType(QualType BaseType, } if (!Protocols.empty()) { - Result = applyObjCProtocolQualifiers(*this, Loc, - SourceRange(ProtocolLAngleLoc, - ProtocolRAngleLoc), - Result, Protocols, - ProtocolLocs.data(), - FailOnError); + bool HasError; + Result = Context.applyObjCProtocolQualifiers(Result, Protocols, + HasError); + if (HasError) { + Diag(Loc, diag::err_invalid_protocol_qualifiers) + << SourceRange(ProtocolLAngleLoc, ProtocolRAngleLoc); + if (FailOnError) Result = QualType(); + } if (FailOnError && Result.isNull()) return QualType(); } @@ -1153,7 +1129,7 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( ActualTypeArgInfos.clear(); break; } - + assert(TypeArgInfo && "No type source info?"); ActualTypeArgInfos.push_back(TypeArgInfo); } @@ -1170,7 +1146,7 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( if (Result == T) return BaseType; - + // Create source information for this type. TypeSourceInfo *ResultTInfo = Context.CreateTypeSourceInfo(Result); TypeLoc ResultTL = ResultTInfo->getTypeLoc(); @@ -1183,6 +1159,20 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( ResultTL = ObjCObjectPointerTL.getPointeeLoc(); } + if (auto OTPTL = ResultTL.getAs<ObjCTypeParamTypeLoc>()) { + // Protocol qualifier information. + if (OTPTL.getNumProtocols() > 0) { + assert(OTPTL.getNumProtocols() == Protocols.size()); + OTPTL.setProtocolLAngleLoc(ProtocolLAngleLoc); + OTPTL.setProtocolRAngleLoc(ProtocolRAngleLoc); + for (unsigned i = 0, n = Protocols.size(); i != n; ++i) + OTPTL.setProtocolLoc(i, ProtocolLocs[i]); + } + + // We're done. Return the completed type to the parser. + return CreateParsedType(Result, ResultTInfo); + } + auto ObjCObjectTL = ResultTL.castAs<ObjCObjectTypeLoc>(); // Type argument information. @@ -1220,19 +1210,19 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( return CreateParsedType(Result, ResultTInfo); } -static StringRef getImageAccessAttrStr(AttributeList *attrs) { - if (attrs) { - - AttributeList *Next; +static OpenCLAccessAttr::Spelling getImageAccess(const AttributeList *Attrs) { + if (Attrs) { + const AttributeList *Next = Attrs; do { - AttributeList &Attr = *attrs; + const AttributeList &Attr = *Next; Next = Attr.getNext(); if (Attr.getKind() == AttributeList::AT_OpenCLAccess) { - return Attr.getName()->getName(); + return static_cast<OpenCLAccessAttr::Spelling>( + Attr.getSemanticSpelling()); } } while (Next); } - return ""; + return OpenCLAccessAttr::Keyword_read_only; } /// \brief Convert the specified declspec to the appropriate type @@ -1411,14 +1401,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.LongDoubleTy; else Result = Context.DoubleTy; - - if (S.getLangOpts().OpenCL && - !((S.getLangOpts().OpenCLVersion >= 120) || - S.getOpenCLOptions().cl_khr_fp64)) { - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension) - << Result << "cl_khr_fp64"; - declarator.setInvalidType(true); - } break; case DeclSpec::TST_float128: if (!S.Context.getTargetInfo().hasFloat128Type()) @@ -1470,48 +1452,6 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = S.GetTypeFromParser(DS.getRepAsType()); if (Result.isNull()) { declarator.setInvalidType(true); - } else if (S.getLangOpts().OpenCL) { - if (Result->getAs<AtomicType>()) { - StringRef TypeName = Result.getBaseTypeIdentifier()->getName(); - bool NoExtTypes = - llvm::StringSwitch<bool>(TypeName) - .Cases("atomic_int", "atomic_uint", "atomic_float", - "atomic_flag", true) - .Default(false); - if (!S.getOpenCLOptions().cl_khr_int64_base_atomics && !NoExtTypes) { - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension) - << Result << "cl_khr_int64_base_atomics"; - declarator.setInvalidType(true); - } - if (!S.getOpenCLOptions().cl_khr_int64_extended_atomics && - !NoExtTypes) { - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension) - << Result << "cl_khr_int64_extended_atomics"; - declarator.setInvalidType(true); - } - if (!S.getOpenCLOptions().cl_khr_fp64 && - !TypeName.compare("atomic_double")) { - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension) - << Result << "cl_khr_fp64"; - declarator.setInvalidType(true); - } - } else if (!S.getOpenCLOptions().cl_khr_gl_msaa_sharing && - (Result->isOCLImage2dArrayMSAADepthROType() || - Result->isOCLImage2dArrayMSAADepthWOType() || - Result->isOCLImage2dArrayMSAADepthRWType() || - Result->isOCLImage2dArrayMSAAROType() || - Result->isOCLImage2dArrayMSAARWType() || - Result->isOCLImage2dArrayMSAAWOType() || - Result->isOCLImage2dMSAADepthROType() || - Result->isOCLImage2dMSAADepthRWType() || - Result->isOCLImage2dMSAADepthWOType() || - Result->isOCLImage2dMSAAROType() || - Result->isOCLImage2dMSAARWType() || - Result->isOCLImage2dMSAAWOType())) { - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension) - << Result << "cl_khr_gl_msaa_sharing"; - declarator.setInvalidType(true); - } } // TypeQuals handled by caller. @@ -1623,11 +1563,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { #define GENERIC_IMAGE_TYPE(ImgType, Id) \ case DeclSpec::TST_##ImgType##_t: \ - Result = llvm::StringSwitch<QualType>( \ - getImageAccessAttrStr(DS.getAttributes().getList())) \ - .Cases("write_only", "__write_only", Context.Id##WOTy) \ - .Cases("read_write", "__read_write", Context.Id##RWTy) \ - .Default(Context.Id##ROTy); \ + switch (getImageAccess(DS.getAttributes().getList())) { \ + case OpenCLAccessAttr::Keyword_write_only: \ + Result = Context.Id##WOTy; break; \ + case OpenCLAccessAttr::Keyword_read_write: \ + Result = Context.Id##RWTy; break; \ + case OpenCLAccessAttr::Keyword_read_only: \ + Result = Context.Id##ROTy; break; \ + } \ break; #include "clang/Basic/OpenCLImageTypes.def" @@ -1637,6 +1580,10 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; } + if (S.getLangOpts().OpenCL && + S.checkOpenCLDisabledTypeDeclSpec(DS, Result)) + declarator.setInvalidType(true); + // Handle complex types. if (DS.getTypeSpecComplex() == DeclSpec::TSC_complex) { if (S.getLangOpts().Freestanding) @@ -1748,6 +1695,12 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, if (T.isNull()) return QualType(); + // Ignore any attempt to form a cv-qualified reference. + if (T->isReferenceType()) { + Qs.removeConst(); + Qs.removeVolatile(); + } + // Enforce C99 6.7.3p2: "Types other than pointer types derived from // object or incomplete types shall not be restrict-qualified." if (Qs.hasRestrict()) { @@ -1789,6 +1742,11 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, if (T.isNull()) return QualType(); + // Ignore any attempt to form a cv-qualified reference. + if (T->isReferenceType()) + CVRAU &= + ~(DeclSpec::TQ_const | DeclSpec::TQ_volatile | DeclSpec::TQ_atomic); + // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and // TQ_unaligned; unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned); @@ -2030,7 +1988,7 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, return Context.getRValueReferenceType(T); } -/// \brief Build a Pipe type. +/// \brief Build a Read-only Pipe type. /// /// \param T The type to which we'll be building a Pipe. /// @@ -2038,11 +1996,20 @@ QualType Sema::BuildReferenceType(QualType T, bool SpelledAsLValue, /// /// \returns A suitable pipe type, if there are no errors. Otherwise, returns a /// NULL type. -QualType Sema::BuildPipeType(QualType T, SourceLocation Loc) { - assert(!T->isObjCObjectType() && "Should build ObjCObjectPointerType"); +QualType Sema::BuildReadPipeType(QualType T, SourceLocation Loc) { + return Context.getReadPipeType(T); +} - // Build the pipe type. - return Context.getPipeType(T); +/// \brief Build a Write-only Pipe type. +/// +/// \param T The type to which we'll be building a Pipe. +/// +/// \param Loc We do not use it for now. +/// +/// \returns A suitable pipe type, if there are no errors. Otherwise, returns a +/// NULL type. +QualType Sema::BuildWritePipeType(QualType T, SourceLocation Loc) { + return Context.getWritePipeType(T); } /// Check whether the specified array size makes the array type a VLA. If so, @@ -2242,6 +2209,10 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(Loc, diag::err_opencl_vla); return QualType(); } + // CUDA device code doesn't support VLAs. + if (getLangOpts().CUDA && T->isVariableArrayType()) + CUDADiagIfDeviceCode(Loc, diag::err_cuda_vla) << CurrentCUDATarget(); + // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOpts().C99) { if (T->isVariableArrayType()) { @@ -2390,28 +2361,16 @@ static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, } continue; - // swift_context parameters must be the last parameter except for - // a possible swift_error parameter. case ParameterABI::SwiftContext: checkForSwiftCC(paramIndex); - if (!(paramIndex == numParams - 1 || - (paramIndex == numParams - 2 && - EPI.ExtParameterInfos[numParams - 1].getABI() - == ParameterABI::SwiftErrorResult))) { - S.Diag(getParamLoc(paramIndex), - diag::err_swift_context_not_before_swift_error_result); - } continue; - // swift_error parameters must be the last parameter. + // swift_error parameters must be preceded by a swift_context parameter. case ParameterABI::SwiftErrorResult: checkForSwiftCC(paramIndex); - if (paramIndex != numParams - 1) { - S.Diag(getParamLoc(paramIndex), - diag::err_swift_error_result_not_last); - } else if (paramIndex == 0 || - EPI.ExtParameterInfos[paramIndex - 1].getABI() - != ParameterABI::SwiftContext) { + if (paramIndex == 0 || + EPI.ExtParameterInfos[paramIndex - 1].getABI() != + ParameterABI::SwiftContext) { S.Diag(getParamLoc(paramIndex), diag::err_swift_error_result_not_after_swift_context); } @@ -2855,7 +2814,8 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, Error = 7; // Exception declaration break; case Declarator::TemplateParamContext: - Error = 8; // Template parameter + if (!SemaRef.getLangOpts().CPlusPlus1z) + Error = 8; // Template parameter break; case Declarator::BlockLiteralContext: Error = 9; // Block literal @@ -3212,6 +3172,7 @@ namespace { Pointer, BlockPointer, MemberPointer, + Array, }; } // end anonymous namespace @@ -3273,15 +3234,27 @@ namespace { // NSError** NSErrorPointerPointer, }; + + /// Describes a declarator chunk wrapping a pointer that marks inference as + /// unexpected. + // These values must be kept in sync with diagnostics. + enum class PointerWrappingDeclaratorKind { + /// Pointer is top-level. + None = -1, + /// Pointer is an array element. + Array = 0, + /// Pointer is the referent type of a C++ reference. + Reference = 1 + }; } // end anonymous namespace /// Classify the given declarator, whose type-specified is \c type, based on /// what kind of pointer it refers to. /// /// This is used to determine the default nullability. -static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, - QualType type, - Declarator &declarator) { +static PointerDeclaratorKind +classifyPointerDeclarator(Sema &S, QualType type, Declarator &declarator, + PointerWrappingDeclaratorKind &wrappingKind) { unsigned numNormalPointers = 0; // For any dependent type, we consider it a non-pointer. @@ -3293,6 +3266,10 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, DeclaratorChunk &chunk = declarator.getTypeObject(i); switch (chunk.Kind) { case DeclaratorChunk::Array: + if (numNormalPointers == 0) + wrappingKind = PointerWrappingDeclaratorKind::Array; + break; + case DeclaratorChunk::Function: case DeclaratorChunk::Pipe: break; @@ -3303,14 +3280,18 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, : PointerDeclaratorKind::SingleLevelPointer; case DeclaratorChunk::Paren: + break; + case DeclaratorChunk::Reference: - continue; + if (numNormalPointers == 0) + wrappingKind = PointerWrappingDeclaratorKind::Reference; + break; case DeclaratorChunk::Pointer: ++numNormalPointers; if (numNormalPointers > 2) return PointerDeclaratorKind::MultiLevelPointer; - continue; + break; } } @@ -3453,12 +3434,77 @@ static FileID getNullabilityCompletenessCheckFileID(Sema &S, return file; } -/// Check for consistent use of nullability. -static void checkNullabilityConsistency(TypeProcessingState &state, +/// Creates a fix-it to insert a C-style nullability keyword at \p pointerLoc, +/// taking into account whitespace before and after. +static void fixItNullability(Sema &S, DiagnosticBuilder &Diag, + SourceLocation PointerLoc, + NullabilityKind Nullability) { + assert(PointerLoc.isValid()); + if (PointerLoc.isMacroID()) + return; + + SourceLocation FixItLoc = S.getLocForEndOfToken(PointerLoc); + if (!FixItLoc.isValid() || FixItLoc == PointerLoc) + return; + + const char *NextChar = S.SourceMgr.getCharacterData(FixItLoc); + if (!NextChar) + return; + + SmallString<32> InsertionTextBuf{" "}; + InsertionTextBuf += getNullabilitySpelling(Nullability); + InsertionTextBuf += " "; + StringRef InsertionText = InsertionTextBuf.str(); + + if (isWhitespace(*NextChar)) { + InsertionText = InsertionText.drop_back(); + } else if (NextChar[-1] == '[') { + if (NextChar[0] == ']') + InsertionText = InsertionText.drop_back().drop_front(); + else + InsertionText = InsertionText.drop_front(); + } else if (!isIdentifierBody(NextChar[0], /*allow dollar*/true) && + !isIdentifierBody(NextChar[-1], /*allow dollar*/true)) { + InsertionText = InsertionText.drop_back().drop_front(); + } + + Diag << FixItHint::CreateInsertion(FixItLoc, InsertionText); +} + +static void emitNullabilityConsistencyWarning(Sema &S, + SimplePointerKind PointerKind, + SourceLocation PointerLoc) { + assert(PointerLoc.isValid()); + + if (PointerKind == SimplePointerKind::Array) { + S.Diag(PointerLoc, diag::warn_nullability_missing_array); + } else { + S.Diag(PointerLoc, diag::warn_nullability_missing) + << static_cast<unsigned>(PointerKind); + } + + if (PointerLoc.isMacroID()) + return; + + auto addFixIt = [&](NullabilityKind Nullability) { + auto Diag = S.Diag(PointerLoc, diag::note_nullability_fix_it); + Diag << static_cast<unsigned>(Nullability); + Diag << static_cast<unsigned>(PointerKind); + fixItNullability(S, Diag, PointerLoc, Nullability); + }; + addFixIt(NullabilityKind::Nullable); + addFixIt(NullabilityKind::NonNull); +} + +/// Complains about missing nullability if the file containing \p pointerLoc +/// has other uses of nullability (either the keywords or the \c assume_nonnull +/// pragma). +/// +/// If the file has \e not seen other uses of nullability, this particular +/// pointer is saved for possible later diagnosis. See recordNullabilitySeen(). +static void checkNullabilityConsistency(Sema &S, SimplePointerKind pointerKind, SourceLocation pointerLoc) { - Sema &S = state.getSema(); - // Determine which file we're performing consistency checking for. FileID file = getNullabilityCompletenessCheckFileID(S, pointerLoc); if (file.isInvalid()) @@ -3468,10 +3514,16 @@ static void checkNullabilityConsistency(TypeProcessingState &state, // about anything. FileNullability &fileNullability = S.NullabilityMap[file]; if (!fileNullability.SawTypeNullability) { - // If this is the first pointer declarator in the file, record it. + // If this is the first pointer declarator in the file, and the appropriate + // warning is on, record it in case we need to diagnose it retroactively. + diag::kind diagKind; + if (pointerKind == SimplePointerKind::Array) + diagKind = diag::warn_nullability_missing_array; + else + diagKind = diag::warn_nullability_missing; + if (fileNullability.PointerLoc.isInvalid() && - !S.Context.getDiagnostics().isIgnored(diag::warn_nullability_missing, - pointerLoc)) { + !S.Context.getDiagnostics().isIgnored(diagKind, pointerLoc)) { fileNullability.PointerLoc = pointerLoc; fileNullability.PointerKind = static_cast<unsigned>(pointerKind); } @@ -3480,8 +3532,66 @@ static void checkNullabilityConsistency(TypeProcessingState &state, } // Complain about missing nullability. - S.Diag(pointerLoc, diag::warn_nullability_missing) - << static_cast<unsigned>(pointerKind); + emitNullabilityConsistencyWarning(S, pointerKind, pointerLoc); +} + +/// Marks that a nullability feature has been used in the file containing +/// \p loc. +/// +/// If this file already had pointer types in it that were missing nullability, +/// the first such instance is retroactively diagnosed. +/// +/// \sa checkNullabilityConsistency +static void recordNullabilitySeen(Sema &S, SourceLocation loc) { + FileID file = getNullabilityCompletenessCheckFileID(S, loc); + if (file.isInvalid()) + return; + + FileNullability &fileNullability = S.NullabilityMap[file]; + if (fileNullability.SawTypeNullability) + return; + fileNullability.SawTypeNullability = true; + + // If we haven't seen any type nullability before, now we have. Retroactively + // diagnose the first unannotated pointer, if there was one. + if (fileNullability.PointerLoc.isInvalid()) + return; + + auto kind = static_cast<SimplePointerKind>(fileNullability.PointerKind); + emitNullabilityConsistencyWarning(S, kind, fileNullability.PointerLoc); +} + +/// Returns true if any of the declarator chunks before \p endIndex include a +/// level of indirection: array, pointer, reference, or pointer-to-member. +/// +/// Because declarator chunks are stored in outer-to-inner order, testing +/// every chunk before \p endIndex is testing all chunks that embed the current +/// chunk as part of their type. +/// +/// It is legal to pass the result of Declarator::getNumTypeObjects() as the +/// end index, in which case all chunks are tested. +static bool hasOuterPointerLikeChunk(const Declarator &D, unsigned endIndex) { + unsigned i = endIndex; + while (i != 0) { + // Walk outwards along the declarator chunks. + --i; + const DeclaratorChunk &DC = D.getTypeObject(i); + switch (DC.Kind) { + case DeclaratorChunk::Paren: + break; + case DeclaratorChunk::Array: + case DeclaratorChunk::Pointer: + case DeclaratorChunk::Reference: + case DeclaratorChunk::MemberPointer: + return true; + case DeclaratorChunk::Function: + case DeclaratorChunk::BlockPointer: + case DeclaratorChunk::Pipe: + // These are invalid anyway, so just ignore. + break; + } + } + return false; } static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, @@ -3561,24 +3671,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Are we in an assume-nonnull region? bool inAssumeNonNullRegion = false; - if (S.PP.getPragmaAssumeNonNullLoc().isValid()) { + SourceLocation assumeNonNullLoc = S.PP.getPragmaAssumeNonNullLoc(); + if (assumeNonNullLoc.isValid()) { inAssumeNonNullRegion = true; - // Determine which file we saw the assume-nonnull region in. - FileID file = getNullabilityCompletenessCheckFileID( - S, S.PP.getPragmaAssumeNonNullLoc()); - if (file.isValid()) { - FileNullability &fileNullability = S.NullabilityMap[file]; - - // If we haven't seen any type nullability before, now we have. - if (!fileNullability.SawTypeNullability) { - if (fileNullability.PointerLoc.isValid()) { - S.Diag(fileNullability.PointerLoc, diag::warn_nullability_missing) - << static_cast<unsigned>(fileNullability.PointerKind); - } - - fileNullability.SawTypeNullability = true; - } - } + recordNullabilitySeen(S, assumeNonNullLoc); } // Whether to complain about missing nullability specifiers or not. @@ -3593,6 +3689,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, CAMN_Yes } complainAboutMissingNullability = CAMN_No; unsigned NumPointersRemaining = 0; + auto complainAboutInferringWithinChunk = PointerWrappingDeclaratorKind::None; if (IsTypedefName) { // For typedefs, we do not infer any nullability (the default), @@ -3600,7 +3697,17 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // inner pointers. complainAboutMissingNullability = CAMN_InnerPointers; - if (T->canHaveNullability() && !T->getNullability(S.Context)) { + auto isDependentNonPointerType = [](QualType T) -> bool { + // Note: This is intended to be the same check as Type::canHaveNullability + // except with all of the ambiguous cases being treated as 'false' rather + // than 'true'. + return T->isDependentType() && !T->isAnyPointerType() && + !T->isBlockPointerType() && !T->isMemberPointerType(); + }; + + if (T->canHaveNullability() && !T->getNullability(S.Context) && + !isDependentNonPointerType(T)) { + // Note that we allow but don't require nullability on dependent types. ++NumPointersRemaining; } @@ -3651,11 +3758,12 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // fallthrough case Declarator::FileContext: - case Declarator::KNRTypeListContext: + case Declarator::KNRTypeListContext: { complainAboutMissingNullability = CAMN_Yes; // Nullability inference depends on the type and declarator. - switch (classifyPointerDeclarator(S, T, D)) { + auto wrappingKind = PointerWrappingDeclaratorKind::None; + switch (classifyPointerDeclarator(S, T, D, wrappingKind)) { case PointerDeclaratorKind::NonPointer: case PointerDeclaratorKind::MultiLevelPointer: // Cannot infer nullability. @@ -3664,6 +3772,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case PointerDeclaratorKind::SingleLevelPointer: // Infer _Nonnull if we are in an assumes-nonnull region. if (inAssumeNonNullRegion) { + complainAboutInferringWithinChunk = wrappingKind; inferNullability = NullabilityKind::NonNull; inferNullabilityCS = (context == Declarator::ObjCParameterContext || context == Declarator::ObjCResultContext); @@ -3704,6 +3813,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; } break; + } case Declarator::ConversionIdContext: complainAboutMissingNullability = CAMN_Yes; @@ -3729,6 +3839,23 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + // Local function that returns true if its argument looks like a va_list. + auto isVaList = [&S](QualType T) -> bool { + auto *typedefTy = T->getAs<TypedefType>(); + if (!typedefTy) + return false; + TypedefDecl *vaListTypedef = S.Context.getBuiltinVaListDecl(); + do { + if (typedefTy->getDecl() == vaListTypedef) + return true; + if (auto *name = typedefTy->getDecl()->getIdentifier()) + if (name->isStr("va_list")) + return true; + typedefTy = typedefTy->desugar()->getAs<TypedefType>(); + } while (typedefTy); + return false; + }; + // Local function that checks the nullability for a given pointer declarator. // Returns true if _Nonnull was inferred. auto inferPointerNullability = [&](SimplePointerKind pointerKind, @@ -3762,6 +3889,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, ->setObjCDeclQualifier(ObjCDeclSpec::DQ_CSNullability); } + if (pointerLoc.isValid() && + complainAboutInferringWithinChunk != + PointerWrappingDeclaratorKind::None) { + auto Diag = + S.Diag(pointerLoc, diag::warn_nullability_inferred_on_nested_type); + Diag << static_cast<int>(complainAboutInferringWithinChunk); + fixItNullability(S, Diag, pointerLoc, NullabilityKind::NonNull); + } + if (inferNullabilityInnerOnly) inferNullabilityInnerOnlyComplete = true; return nullabilityAttr; @@ -3779,27 +3915,42 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Fallthrough. case CAMN_Yes: - checkNullabilityConsistency(state, pointerKind, pointerLoc); + checkNullabilityConsistency(S, pointerKind, pointerLoc); } return nullptr; }; // If the type itself could have nullability but does not, infer pointer // nullability and perform consistency checking. - if (T->canHaveNullability() && S.ActiveTemplateInstantiations.empty() && - !T->getNullability(S.Context)) { - SimplePointerKind pointerKind = SimplePointerKind::Pointer; - if (T->isBlockPointerType()) - pointerKind = SimplePointerKind::BlockPointer; - else if (T->isMemberPointerType()) - pointerKind = SimplePointerKind::MemberPointer; + if (S.ActiveTemplateInstantiations.empty()) { + if (T->canHaveNullability() && !T->getNullability(S.Context)) { + if (isVaList(T)) { + // Record that we've seen a pointer, but do nothing else. + if (NumPointersRemaining > 0) + --NumPointersRemaining; + } else { + SimplePointerKind pointerKind = SimplePointerKind::Pointer; + if (T->isBlockPointerType()) + pointerKind = SimplePointerKind::BlockPointer; + else if (T->isMemberPointerType()) + pointerKind = SimplePointerKind::MemberPointer; + + if (auto *attr = inferPointerNullability( + pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), + D.getMutableDeclSpec().getAttributes().getListRef())) { + T = Context.getAttributedType( + AttributedType::getNullabilityAttrKind(*inferNullability),T,T); + attr->setUsedAsTypeAttr(); + } + } + } - if (auto *attr = inferPointerNullability( - pointerKind, D.getDeclSpec().getTypeSpecTypeLoc(), - D.getMutableDeclSpec().getAttributes().getListRef())) { - T = Context.getAttributedType( - AttributedType::getNullabilityAttrKind(*inferNullability), T, T); - attr->setUsedAsTypeAttr(); + if (complainAboutMissingNullability == CAMN_Yes && + T->isArrayType() && !T->getNullability(S.Context) && !isVaList(T) && + D.isPrototypeContext() && + !hasOuterPointerLikeChunk(D, D.getNumTypeObjects())) { + checkNullabilityConsistency(S, SimplePointerKind::Array, + D.getDeclSpec().getTypeSpecTypeLoc()); } } @@ -3925,31 +4076,13 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // C99 6.7.5.2p1: ... and then only in the outermost array type // derivation. - unsigned x = chunkIndex; - while (x != 0) { - // Walk outwards along the declarator chunks. - x--; - const DeclaratorChunk &DC = D.getTypeObject(x); - switch (DC.Kind) { - case DeclaratorChunk::Paren: - continue; - case DeclaratorChunk::Array: - case DeclaratorChunk::Pointer: - case DeclaratorChunk::Reference: - case DeclaratorChunk::MemberPointer: - S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) << - (ASM == ArrayType::Static ? "'static'" : "type qualifier"); - if (ASM == ArrayType::Static) - ASM = ArrayType::Normal; - ATI.TypeQuals = 0; - D.setInvalidType(true); - break; - case DeclaratorChunk::Function: - case DeclaratorChunk::BlockPointer: - case DeclaratorChunk::Pipe: - // These are invalid anyway, so just ignore. - break; - } + if (hasOuterPointerLikeChunk(D, chunkIndex)) { + S.Diag(DeclType.Loc, diag::err_array_static_not_outermost) << + (ASM == ArrayType::Static ? "'static'" : "type qualifier"); + if (ASM == ArrayType::Static) + ASM = ArrayType::Normal; + ATI.TypeQuals = 0; + D.setInvalidType(true); } } const AutoType *AT = T->getContainedAutoType(); @@ -3964,6 +4097,16 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, break; } + // Array parameters can be marked nullable as well, although it's not + // necessary if they're marked 'static'. + if (complainAboutMissingNullability == CAMN_Yes && + !hasNullabilityAttr(DeclType.getAttrs()) && + ASM != ArrayType::Static && + D.isPrototypeContext() && + !hasOuterPointerLikeChunk(D, chunkIndex)) { + checkNullabilityConsistency(S, SimplePointerKind::Array, DeclType.Loc); + } + T = S.BuildArrayType(T, ASM, ArraySize, ATI.TypeQuals, SourceRange(DeclType.Loc, DeclType.EndLoc), Name); break; @@ -4032,7 +4175,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // FIXME: This really should be in BuildFunctionType. if (T->isHalfType()) { if (S.getLangOpts().OpenCL) { - if (!S.getOpenCLOptions().cl_khr_fp16) { + if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) { S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) << T << 0 /*pointer hint*/; D.setInvalidType(true); @@ -4044,13 +4187,26 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + if (LangOpts.OpenCL) { // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a // function. - if (LangOpts.OpenCL && (T->isBlockPointerType() || T->isImageType() || - T->isSamplerT() || T->isPipeType())) { - S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) - << T << 1 /*hint off*/; - D.setInvalidType(true); + if (T->isBlockPointerType() || T->isImageType() || T->isSamplerT() || + T->isPipeType()) { + S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) + << T << 1 /*hint off*/; + D.setInvalidType(true); + } + // OpenCL doesn't support variadic functions and blocks + // (s6.9.e and s6.12.5 OpenCL v2.0) except for printf. + // We also allow here any toolchain reserved identifiers. + if (FTI.isVariadic && + !(D.getIdentifier() && + ((D.getIdentifier()->getName() == "printf" && + LangOpts.OpenCLVersion >= 120) || + D.getIdentifier()->getName().startswith("__")))) { + S.Diag(D.getIdentifierLoc(), diag::err_opencl_variadic_function); + D.setInvalidType(true); + } } // Methods cannot return interface types. All ObjC objects are @@ -4143,7 +4299,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Exception specs are not allowed in typedefs. Complain, but add it // anyway. - if (IsTypedefName && FTI.getExceptionSpecType()) + if (IsTypedefName && FTI.getExceptionSpecType() && !LangOpts.CPlusPlus1z) S.Diag(FTI.getExceptionSpecLocBeg(), diag::err_exception_spec_in_typedef) << (D.getContext() == Declarator::AliasDeclContext || @@ -4154,6 +4310,19 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.isAmbiguous) warnAboutAmbiguousFunction(S, D, DeclType, T); + // GNU warning -Wstrict-prototypes + // Warn if a function declaration is without a prototype. + // This warning is issued for all kinds of unprototyped function + // declarations (i.e. function type typedef, function pointer etc.) + // C99 6.7.5.3p14: + // The empty list in a function declarator that is not part of a + // definition of that function specifies that no information + // about the number or types of the parameters is supplied. + if (D.getFunctionDefinitionKind() == FDK_Declaration && + FTI.NumParams == 0 && !LangOpts.CPlusPlus) + S.Diag(DeclType.Loc, diag::warn_strict_prototypes) + << 0 << FixItHint::CreateInsertion(FTI.getRParenLoc(), "void"); + FunctionType::ExtInfo EI(getCCForDeclaratorChunk(S, D, FTI, chunkIndex)); if (!FTI.NumParams && !FTI.isVariadic && !LangOpts.CPlusPlus) { @@ -4239,7 +4408,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, // Disallow half FP parameters. // FIXME: This really should be in BuildFunctionType. if (S.getLangOpts().OpenCL) { - if (!S.getOpenCLOptions().cl_khr_fp16) { + if (!S.getOpenCLOptions().isEnabled("cl_khr_fp16")) { S.Diag(Param->getLocation(), diag::err_opencl_half_param) << ParamTy; D.setInvalidType(); @@ -4290,7 +4459,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (FTI.getExceptionSpecType() == EST_Dynamic) { // FIXME: It's rather inefficient to have to split into two vectors // here. - unsigned N = FTI.NumExceptions; + unsigned N = FTI.getNumExceptions(); DynamicExceptions.reserve(N); DynamicExceptionRanges.reserve(N); for (unsigned I = 0; I != N; ++I) { @@ -4374,7 +4543,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } case DeclaratorChunk::Pipe: { - T = S.BuildPipeType(T, DeclType.Loc ); + T = S.BuildReadPipeType(T, DeclType.Loc); + processTypeAttrs(state, T, TAL_DeclSpec, + D.getDeclSpec().getAttributes().getList()); break; } } @@ -4738,6 +4909,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_StdCall; case AttributedType::attr_thiscall: return AttributeList::AT_ThisCall; + case AttributedType::attr_regcall: + return AttributeList::AT_RegCall; case AttributedType::attr_pascal: return AttributeList::AT_Pascal; case AttributedType::attr_swiftcall: @@ -4908,11 +5081,9 @@ namespace { TL.getWrittenBuiltinSpecs() = DS.getWrittenBuiltinSpecs(); // Try to have a meaningful source location. if (TL.getWrittenSignSpec() != TSS_unspecified) - // Sign spec loc overrides the others (e.g., 'unsigned long'). - TL.setBuiltinLoc(DS.getTypeSpecSignLoc()); - else if (TL.getWrittenWidthSpec() != TSW_unspecified) - // Width spec loc overrides type spec loc (e.g., 'short int'). - TL.setBuiltinLoc(DS.getTypeSpecWidthLoc()); + TL.expandBuiltinRange(DS.getTypeSpecSignLoc()); + if (TL.getWrittenWidthSpec() != TSW_unspecified) + TL.expandBuiltinRange(DS.getTypeSpecWidthRange()); } } void VisitElaboratedTypeLoc(ElaboratedTypeLoc TL) { @@ -5537,7 +5708,7 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, if (Class->isArcWeakrefUnavailable()) { S.Diag(AttrLoc, diag::err_arc_unsupported_weak_class); S.Diag(ObjT->getInterfaceDecl()->getLocation(), - diag::note_class_declared); + diag::note_class_declared); } } } @@ -5811,23 +5982,9 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, bool Sema::checkNullabilityTypeSpecifier(QualType &type, NullabilityKind nullability, SourceLocation nullabilityLoc, - bool isContextSensitive) { - // We saw a nullability type specifier. If this is the first one for - // this file, note that. - FileID file = getNullabilityCompletenessCheckFileID(*this, nullabilityLoc); - if (!file.isInvalid()) { - FileNullability &fileNullability = NullabilityMap[file]; - if (!fileNullability.SawTypeNullability) { - // If we have already seen a pointer declarator without a nullability - // annotation, complain about it. - if (fileNullability.PointerLoc.isValid()) { - Diag(fileNullability.PointerLoc, diag::warn_nullability_missing) - << static_cast<unsigned>(fileNullability.PointerKind); - } - - fileNullability.SawTypeNullability = true; - } - } + bool isContextSensitive, + bool allowOnArrayType) { + recordNullabilitySeen(*this, nullabilityLoc); // Check for existing nullability attributes on the type. QualType desugared = type; @@ -5881,7 +6038,8 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, } // If this definitely isn't a pointer type, reject the specifier. - if (!desugared->canHaveNullability()) { + if (!desugared->canHaveNullability() && + !(allowOnArrayType && desugared->isArrayType())) { Diag(nullabilityLoc, diag::err_nullability_nonpointer) << DiagNullabilityKind(nullability, isContextSensitive) << type; return true; @@ -5891,7 +6049,12 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, // attributes, require that the type be a single-level pointer. if (isContextSensitive) { // Make sure that the pointee isn't itself a pointer type. - QualType pointeeType = desugared->getPointeeType(); + const Type *pointeeType; + if (desugared->isArrayType()) + pointeeType = desugared->getArrayElementTypeNoTypeQual(); + else + pointeeType = desugared->getPointeeType().getTypePtr(); + if (pointeeType->isAnyPointerType() || pointeeType->isObjCObjectPointerType() || pointeeType->isMemberPointerType()) { @@ -5914,6 +6077,13 @@ bool Sema::checkNullabilityTypeSpecifier(QualType &type, } bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { + if (isa<ObjCTypeParamType>(type)) { + // Build the attributed type to record where __kindof occurred. + type = Context.getAttributedType(AttributedType::attr_objc_kindof, + type, type); + return false; + } + // Find out if it's an Objective-C object or object pointer type; const ObjCObjectPointerType *ptrType = type->getAs<ObjCObjectPointerType>(); const ObjCObjectType *objType = ptrType ? ptrType->getObjectType() @@ -6070,6 +6240,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { return AttributedType::attr_stdcall; case AttributeList::AT_ThisCall: return AttributedType::attr_thiscall; + case AttributeList::AT_RegCall: + return AttributedType::attr_regcall; case AttributeList::AT_Pascal: return AttributedType::attr_pascal; case AttributeList::AT_SwiftCall: @@ -6523,6 +6695,11 @@ static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr, S.Diag(TypedefTy->getDecl()->getLocStart(), diag::note_opencl_typedef_access_qualifier) << PrevAccessQual; + } else if (CurType->isPipeType()) { + if (Attr.getSemanticSpelling() == OpenCLAccessAttr::Keyword_write_only) { + QualType ElemType = CurType->getAs<PipeType>()->getElementType(); + CurType = S.Context.getWritePipeType(ElemType); + } } } @@ -6637,12 +6814,22 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // don't want to distribute the nullability specifier past any // dependent type, because that complicates the user model. if (type->canHaveNullability() || type->isDependentType() || + type->isArrayType() || !distributeNullabilityTypeAttr(state, type, attr)) { + unsigned endIndex; + if (TAL == TAL_DeclChunk) + endIndex = state.getCurrentChunkIndex(); + else + endIndex = state.getDeclarator().getNumTypeObjects(); + bool allowOnArrayType = + state.getDeclarator().isPrototypeContext() && + !hasOuterPointerLikeChunk(state.getDeclarator(), endIndex); if (state.getSema().checkNullabilityTypeSpecifier( type, mapNullabilityAttrKind(attr.getKind()), attr.getLoc(), - attr.isContextSensitiveKeywordAttribute())) { + attr.isContextSensitiveKeywordAttribute(), + allowOnArrayType)) { attr.setInvalid(); } @@ -6879,6 +7066,14 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, return false; } D = ED->getDefinition(); + } else if (auto *FD = dyn_cast<FunctionDecl>(D)) { + if (auto *Pattern = FD->getTemplateInstantiationPattern()) + FD = Pattern; + D = FD->getDefinition(); + } else if (auto *VD = dyn_cast<VarDecl>(D)) { + if (auto *Pattern = VD->getTemplateInstantiationPattern()) + VD = Pattern; + D = VD->getDefinition(); } assert(D && "missing definition for pattern of instantiated definition"); @@ -6886,7 +7081,7 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, if (isVisible(D)) return true; - // The external source may have additional definitions of this type that are + // The external source may have additional definitions of this entity that are // visible, so complete the redeclaration chain now and ask again. if (auto *Source = Context.getExternalSource()) { Source->CompleteRedeclChain(D); diff --git a/lib/Sema/TreeTransform.h b/lib/Sema/TreeTransform.h index 7224eef848dee..3ab6019f0ec31 100644 --- a/lib/Sema/TreeTransform.h +++ b/lib/Sema/TreeTransform.h @@ -457,6 +457,10 @@ public: return cast_or_null<NamedDecl>(getDerived().TransformDecl(Loc, D)); } + /// Transform the set of declarations in an OverloadExpr. + bool TransformOverloadExprDecls(OverloadExpr *Old, bool RequiresADL, + LookupResult &R); + /// \brief Transform the given nested-name-specifier with source-location /// information. /// @@ -699,6 +703,12 @@ public: QualType RebuildMemberPointerType(QualType PointeeType, QualType ClassType, SourceLocation Sigil); + QualType RebuildObjCTypeParamType(const ObjCTypeParamDecl *Decl, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc); + /// \brief Build an Objective-C object type. /// /// By default, performs semantic analysis when building the object type. @@ -815,7 +825,7 @@ public: /// \brief Rebuild an unresolved typename type, given the decl that /// the UnresolvedUsingTypenameDecl was transformed to. - QualType RebuildUnresolvedUsingType(Decl *D); + QualType RebuildUnresolvedUsingType(SourceLocation NameLoc, Decl *D); /// \brief Build a new typedef type. QualType RebuildTypedefType(TypedefNameDecl *Typedef) { @@ -1007,11 +1017,9 @@ public: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: { NamedDecl *SomeDecl = Result.getRepresentativeDecl(); - unsigned Kind = 0; - if (isa<TypedefDecl>(SomeDecl)) Kind = 1; - else if (isa<TypeAliasDecl>(SomeDecl)) Kind = 2; - else if (isa<ClassTemplateDecl>(SomeDecl)) Kind = 3; - SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << Kind; + Sema::NonTagKind NTK = SemaRef.getNonTagTypeDeclKind(SomeDecl, Kind); + SemaRef.Diag(IdLoc, diag::err_tag_reference_non_tag) << SomeDecl + << NTK << Kind; SemaRef.Diag(SomeDecl->getLocation(), diag::note_declared_at); break; } @@ -1056,7 +1064,8 @@ public: QualType RebuildAtomicType(QualType ValueType, SourceLocation KWLoc); /// \brief Build a new pipe type given its value type. - QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc); + QualType RebuildPipeType(QualType ValueType, SourceLocation KWLoc, + bool isReadPipe); /// \brief Build a new template name given a nested name specifier, a flag /// indicating whether the "template" keyword was provided, and the template @@ -3216,6 +3225,9 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init, if (ExprWithCleanups *ExprTemp = dyn_cast<ExprWithCleanups>(Init)) Init = ExprTemp->getSubExpr(); + if (auto *AIL = dyn_cast<ArrayInitLoopExpr>(Init)) + Init = AIL->getCommonExpr(); + if (MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(Init)) Init = MTE->GetTemporaryExpr(); @@ -3438,15 +3450,13 @@ TreeTransform<Derived>::TransformNestedNameSpecifierLoc( NestedNameSpecifier *QNNS = Q.getNestedNameSpecifier(); switch (QNNS->getKind()) { - case NestedNameSpecifier::Identifier: - if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, - *QNNS->getAsIdentifier(), - Q.getLocalBeginLoc(), - Q.getLocalEndLoc(), - ObjectType, false, SS, - FirstQualifierInScope, false)) + case NestedNameSpecifier::Identifier: { + Sema::NestedNameSpecInfo IdInfo(QNNS->getAsIdentifier(), + Q.getLocalBeginLoc(), Q.getLocalEndLoc(), ObjectType); + if (SemaRef.BuildCXXNestedNameSpecifier(/*Scope=*/nullptr, IdInfo, false, + SS, FirstQualifierInScope, false)) return NestedNameSpecifierLoc(); - + } break; case NestedNameSpecifier::Namespace: { @@ -5118,6 +5128,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec( } ESI.Exceptions = Exceptions; + if (ESI.Exceptions.empty()) + ESI.Type = EST_DynamicNone; return false; } @@ -5153,7 +5165,7 @@ TreeTransform<Derived>::TransformUnresolvedUsingType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || D != T->getDecl()) { - Result = getDerived().RebuildUnresolvedUsingType(D); + Result = getDerived().RebuildUnresolvedUsingType(TL.getNameLoc(), D); if (Result.isNull()) return QualType(); } @@ -5480,7 +5492,9 @@ QualType TreeTransform<Derived>::TransformPipeType(TypeLocBuilder &TLB, QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ValueType != TL.getValueLoc().getType()) { - Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc()); + const PipeType *PT = Result->getAs<PipeType>(); + bool isReadPipe = PT->isReadOnly(); + Result = getDerived().RebuildPipeType(ValueType, TL.getKWLoc(), isReadPipe); if (Result.isNull()) return QualType(); } @@ -5699,7 +5713,9 @@ TreeTransform<Derived>::TransformElaboratedType(TypeLocBuilder &TLB, if (TypeAliasTemplateDecl *TAT = dyn_cast_or_null<TypeAliasTemplateDecl>( Template.getAsTemplateDecl())) { SemaRef.Diag(TL.getNamedTypeLoc().getBeginLoc(), - diag::err_tag_reference_non_tag) << 4; + diag::err_tag_reference_non_tag) + << TAT << Sema::NTK_TypeAliasTemplate + << ElaboratedType::getTagTypeKindForKeyword(T->getKeyword()); SemaRef.Diag(TAT->getLocation(), diag::note_declared_at); } } @@ -5946,6 +5962,39 @@ TreeTransform<Derived>::TransformObjCInterfaceType(TypeLocBuilder &TLB, template<typename Derived> QualType +TreeTransform<Derived>::TransformObjCTypeParamType(TypeLocBuilder &TLB, + ObjCTypeParamTypeLoc TL) { + const ObjCTypeParamType *T = TL.getTypePtr(); + ObjCTypeParamDecl *OTP = cast_or_null<ObjCTypeParamDecl>( + getDerived().TransformDecl(T->getDecl()->getLocation(), T->getDecl())); + if (!OTP) + return QualType(); + + QualType Result = TL.getType(); + if (getDerived().AlwaysRebuild() || + OTP != T->getDecl()) { + Result = getDerived().RebuildObjCTypeParamType(OTP, + TL.getProtocolLAngleLoc(), + llvm::makeArrayRef(TL.getTypePtr()->qual_begin(), + TL.getNumProtocols()), + TL.getProtocolLocs(), + TL.getProtocolRAngleLoc()); + if (Result.isNull()) + return QualType(); + } + + ObjCTypeParamTypeLoc NewTL = TLB.push<ObjCTypeParamTypeLoc>(Result); + if (TL.getNumProtocols()) { + NewTL.setProtocolLAngleLoc(TL.getProtocolLAngleLoc()); + for (unsigned i = 0, n = TL.getNumProtocols(); i != n; ++i) + NewTL.setProtocolLoc(i, TL.getProtocolLoc(i)); + NewTL.setProtocolRAngleLoc(TL.getProtocolRAngleLoc()); + } + return Result; +} + +template<typename Derived> +QualType TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, ObjCObjectTypeLoc TL) { // Transform base type. @@ -6617,6 +6666,7 @@ template<typename Derived> StmtResult TreeTransform<Derived>::TransformCoroutineBodyStmt(CoroutineBodyStmt *S) { // The coroutine body should be re-formed by the caller if necessary. + // FIXME: The coroutine body is always rebuilt by ActOnFinishFunctionBody return getDerived().TransformStmt(S->getBody()); } @@ -7626,6 +7676,96 @@ StmtResult TreeTransform<Derived>::TransformOMPTargetParallelForSimdDirective( return Res; } +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetSimdDirective( + OMPTargetSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_simd, DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTeamsDistributeDirective( + OMPTeamsDistributeDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_teams_distribute, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTeamsDistributeSimdDirective( + OMPTeamsDistributeSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_teams_distribute_simd, DirName, nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTeamsDistributeParallelForSimdDirective( + OMPTeamsDistributeParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_teams_distribute_parallel_for_simd, DirName, nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTeamsDistributeParallelForDirective( + OMPTeamsDistributeParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_teams_distribute_parallel_for, + DirName, nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetTeamsDirective( + OMPTargetTeamsDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_teams, DirName, + nullptr, D->getLocStart()); + auto Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetTeamsDistributeDirective( + OMPTargetTeamsDistributeDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_teams_distribute, + DirName, nullptr, D->getLocStart()); + auto Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult +TreeTransform<Derived>::TransformOMPTargetTeamsDistributeParallelForDirective( + OMPTargetTeamsDistributeParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_target_teams_distribute_parallel_for, DirName, nullptr, + D->getLocStart()); + auto Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -8866,6 +9006,19 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { Desig.AddDesignator(Designator::getField(D.getFieldName(), D.getDotLoc(), D.getFieldLoc())); + if (D.getField()) { + FieldDecl *Field = cast_or_null<FieldDecl>( + getDerived().TransformDecl(D.getFieldLoc(), D.getField())); + if (Field != D.getField()) + // Rebuild the expression when the transformed FieldDecl is + // different to the already assigned FieldDecl. + ExprChanged = true; + } else { + // Ensure that the designator expression is rebuilt when there isn't + // a resolved FieldDecl in the designator as we don't want to assign + // a FieldDecl to a pattern designator that will be instantiated again. + ExprChanged = true; + } continue; } @@ -8935,6 +9088,20 @@ TreeTransform<Derived>::TransformNoInitExpr( template<typename Derived> ExprResult +TreeTransform<Derived>::TransformArrayInitLoopExpr(ArrayInitLoopExpr *E) { + llvm_unreachable("Unexpected ArrayInitLoopExpr outside of initializer"); + return ExprError(); +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformArrayInitIndexExpr(ArrayInitIndexExpr *E) { + llvm_unreachable("Unexpected ArrayInitIndexExpr outside of initializer"); + return ExprError(); +} + +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformImplicitValueInitExpr( ImplicitValueInitExpr *E) { TemporaryBase Rebase(*this, E->getLocStart(), DeclarationName()); @@ -9655,44 +9822,72 @@ TreeTransform<Derived>::TransformCXXPseudoDestructorExpr( Destroyed); } -template<typename Derived> -ExprResult -TreeTransform<Derived>::TransformUnresolvedLookupExpr( - UnresolvedLookupExpr *Old) { - LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), - Sema::LookupOrdinaryName); - +template <typename Derived> +bool TreeTransform<Derived>::TransformOverloadExprDecls(OverloadExpr *Old, + bool RequiresADL, + LookupResult &R) { // Transform all the decls. - for (UnresolvedLookupExpr::decls_iterator I = Old->decls_begin(), - E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>( - getDerived().TransformDecl(Old->getNameLoc(), - *I)); + bool AllEmptyPacks = true; + for (auto *OldD : Old->decls()) { + Decl *InstD = getDerived().TransformDecl(Old->getNameLoc(), OldD); if (!InstD) { // Silently ignore these if a UsingShadowDecl instantiated to nothing. // This can happen because of dependent hiding. - if (isa<UsingShadowDecl>(*I)) + if (isa<UsingShadowDecl>(OldD)) continue; else { R.clear(); - return ExprError(); + return true; } } + // Expand using pack declarations. + NamedDecl *SingleDecl = cast<NamedDecl>(InstD); + ArrayRef<NamedDecl*> Decls = SingleDecl; + if (auto *UPD = dyn_cast<UsingPackDecl>(InstD)) + Decls = UPD->expansions(); + // Expand using declarations. - if (isa<UsingDecl>(InstD)) { - UsingDecl *UD = cast<UsingDecl>(InstD); - for (auto *I : UD->shadows()) - R.addDecl(I); - continue; + for (auto *D : Decls) { + if (auto *UD = dyn_cast<UsingDecl>(D)) { + for (auto *SD : UD->shadows()) + R.addDecl(SD); + } else { + R.addDecl(D); + } } - R.addDecl(InstD); + AllEmptyPacks &= Decls.empty(); + }; + + // C++ [temp.res]/8.4.2: + // The program is ill-formed, no diagnostic required, if [...] lookup for + // a name in the template definition found a using-declaration, but the + // lookup in the corresponding scope in the instantiation odoes not find + // any declarations because the using-declaration was a pack expansion and + // the corresponding pack is empty + if (AllEmptyPacks && !RequiresADL) { + getSema().Diag(Old->getNameLoc(), diag::err_using_pack_expansion_empty) + << isa<UnresolvedMemberExpr>(Old) << Old->getNameInfo().getName(); + return true; } // Resolve a kind, but don't do any further analysis. If it's // ambiguous, the callee needs to deal with it. R.resolveKind(); + return false; +} + +template<typename Derived> +ExprResult +TreeTransform<Derived>::TransformUnresolvedLookupExpr( + UnresolvedLookupExpr *Old) { + LookupResult R(SemaRef, Old->getName(), Old->getNameLoc(), + Sema::LookupOrdinaryName); + + // Transform the declaration set. + if (TransformOverloadExprDecls(Old, Old->requiresADL(), R)) + return ExprError(); // Rebuild the nested-name qualifier, if present. CXXScopeSpec SS; @@ -10222,9 +10417,23 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition( Class, E->getIntroducerRange(), NewCallOpTSI, E->getCallOperator()->getLocEnd(), - NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams()); + NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(), + E->getCallOperator()->isConstexpr()); + 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::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); @@ -10546,35 +10755,9 @@ TreeTransform<Derived>::TransformUnresolvedMemberExpr(UnresolvedMemberExpr *Old) LookupResult R(SemaRef, Old->getMemberNameInfo(), Sema::LookupOrdinaryName); - // Transform all the decls. - for (UnresolvedMemberExpr::decls_iterator I = Old->decls_begin(), - E = Old->decls_end(); I != E; ++I) { - NamedDecl *InstD = static_cast<NamedDecl*>( - getDerived().TransformDecl(Old->getMemberLoc(), - *I)); - if (!InstD) { - // Silently ignore these if a UsingShadowDecl instantiated to nothing. - // This can happen because of dependent hiding. - if (isa<UsingShadowDecl>(*I)) - continue; - else { - R.clear(); - return ExprError(); - } - } - - // Expand using declarations. - if (isa<UsingDecl>(InstD)) { - UsingDecl *UD = cast<UsingDecl>(InstD); - for (auto *I : UD->shadows()) - R.addDecl(I); - continue; - } - - R.addDecl(InstD); - } - - R.resolveKind(); + // Transform the declaration set. + if (TransformOverloadExprDecls(Old, /*RequiresADL*/false, R)) + return ExprError(); // Determine the naming class. if (Old->getNamingClass()) { @@ -10704,6 +10887,51 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { E->getRParenLoc(), None, None); } + // Try to compute the result without performing a partial substitution. + Optional<unsigned> Result = 0; + for (const TemplateArgument &Arg : PackArgs) { + if (!Arg.isPackExpansion()) { + Result = *Result + 1; + continue; + } + + TemplateArgumentLoc ArgLoc; + InventTemplateArgumentLoc(Arg, ArgLoc); + + // Find the pattern of the pack expansion. + SourceLocation Ellipsis; + Optional<unsigned> OrigNumExpansions; + TemplateArgumentLoc Pattern = + getSema().getTemplateArgumentPackExpansionPattern(ArgLoc, Ellipsis, + OrigNumExpansions); + + // Substitute under the pack expansion. Do not expand the pack (yet). + TemplateArgumentLoc OutPattern; + Sema::ArgumentPackSubstitutionIndexRAII SubstIndex(getSema(), -1); + if (getDerived().TransformTemplateArgument(Pattern, OutPattern, + /*Uneval*/ true)) + return true; + + // See if we can determine the number of arguments from the result. + Optional<unsigned> NumExpansions = + getSema().getFullyPackExpandedSize(OutPattern.getArgument()); + if (!NumExpansions) { + // No: we must be in an alias template expansion, and we're going to need + // to actually expand the packs. + Result = None; + break; + } + + Result = *Result + *NumExpansions; + } + + // Common case: we could determine the number of expansions without + // substituting. + if (Result) + return getDerived().RebuildSizeOfPackExpr(E->getOperatorLoc(), E->getPack(), + E->getPackLoc(), + E->getRParenLoc(), *Result, None); + TemplateArgumentListInfo TransformedPackArgs(E->getPackLoc(), E->getPackLoc()); { @@ -10716,6 +10944,8 @@ TreeTransform<Derived>::TransformSizeOfPackExpr(SizeOfPackExpr *E) { return ExprError(); } + // Check whether we managed to fully-expand the pack. + // FIXME: Is it possible for us to do so and not hit the early exit path? SmallVector<TemplateArgument, 8> Args; bool PartialSubstitution = false; for (auto &Loc : TransformedPackArgs.arguments()) { @@ -11152,6 +11382,9 @@ TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { } else if (E->getReceiverKind() == ObjCMessageExpr::SuperClass || E->getReceiverKind() == ObjCMessageExpr::SuperInstance) { + if (!E->getMethodDecl()) + return ExprError(); + // Build a new class message send to 'super'. SmallVector<SourceLocation, 16> SelLocs; E->getSelectorLocs(SelLocs); @@ -11476,6 +11709,19 @@ TreeTransform<Derived>::RebuildMemberPointerType(QualType PointeeType, } template<typename Derived> +QualType TreeTransform<Derived>::RebuildObjCTypeParamType( + const ObjCTypeParamDecl *Decl, + SourceLocation ProtocolLAngleLoc, + ArrayRef<ObjCProtocolDecl *> Protocols, + ArrayRef<SourceLocation> ProtocolLocs, + SourceLocation ProtocolRAngleLoc) { + return SemaRef.BuildObjCTypeParamType(Decl, + ProtocolLAngleLoc, Protocols, + ProtocolLocs, ProtocolRAngleLoc, + /*FailOnError=*/true); +} + +template<typename Derived> QualType TreeTransform<Derived>::RebuildObjCObjectType( QualType BaseType, SourceLocation Loc, @@ -11626,21 +11872,48 @@ QualType TreeTransform<Derived>::RebuildFunctionNoProtoType(QualType T) { } template<typename Derived> -QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(Decl *D) { +QualType TreeTransform<Derived>::RebuildUnresolvedUsingType(SourceLocation Loc, + Decl *D) { assert(D && "no decl found"); if (D->isInvalidDecl()) return QualType(); // FIXME: Doesn't account for ObjCInterfaceDecl! TypeDecl *Ty; - if (isa<UsingDecl>(D)) { - UsingDecl *Using = cast<UsingDecl>(D); + if (auto *UPD = dyn_cast<UsingPackDecl>(D)) { + // A valid resolved using typename pack expansion decl can have multiple + // UsingDecls, but they must each have exactly one type, and it must be + // the same type in every case. But we must have at least one expansion! + if (UPD->expansions().empty()) { + getSema().Diag(Loc, diag::err_using_pack_expansion_empty) + << UPD->isCXXClassMember() << UPD; + return QualType(); + } + + // We might still have some unresolved types. Try to pick a resolved type + // if we can. The final instantiation will check that the remaining + // unresolved types instantiate to the type we pick. + QualType FallbackT; + QualType T; + for (auto *E : UPD->expansions()) { + QualType ThisT = RebuildUnresolvedUsingType(Loc, E); + if (ThisT.isNull()) + continue; + else if (ThisT->getAs<UnresolvedUsingType>()) + FallbackT = ThisT; + else if (T.isNull()) + T = ThisT; + else + assert(getSema().Context.hasSameType(ThisT, T) && + "mismatched resolved types in using pack expansion"); + } + return T.isNull() ? FallbackT : T; + } else if (auto *Using = dyn_cast<UsingDecl>(D)) { assert(Using->hasTypename() && "UnresolvedUsingTypenameDecl transformed to non-typename using"); // A valid resolved using typename decl points to exactly one type decl. assert(++Using->shadow_begin() == Using->shadow_end()); Ty = cast<TypeDecl>((*Using->shadow_begin())->getTargetDecl()); - } else { assert(isa<UnresolvedUsingTypenameDecl>(D) && "UnresolvedUsingTypenameDecl transformed to non-using decl"); @@ -11690,8 +11963,10 @@ QualType TreeTransform<Derived>::RebuildAtomicType(QualType ValueType, template<typename Derived> QualType TreeTransform<Derived>::RebuildPipeType(QualType ValueType, - SourceLocation KWLoc) { - return SemaRef.BuildPipeType(ValueType, KWLoc); + SourceLocation KWLoc, + bool isReadPipe) { + return isReadPipe ? SemaRef.BuildReadPipeType(ValueType, KWLoc) + : SemaRef.BuildWritePipeType(ValueType, KWLoc); } template<typename Derived> diff --git a/lib/Sema/TypeLocBuilder.h b/lib/Sema/TypeLocBuilder.h index 3828218597684..9c77045d2e12f 100644 --- a/lib/Sema/TypeLocBuilder.h +++ b/lib/Sema/TypeLocBuilder.h @@ -39,7 +39,7 @@ class TypeLocBuilder { #endif /// The inline buffer. - enum { BufferMaxAlignment = llvm::AlignOf<void*>::Alignment }; + enum { BufferMaxAlignment = alignof(void *) }; llvm::AlignedCharArray<BufferMaxAlignment, InlineCapacity> InlineBuffer; unsigned NumBytesAtAlign4, NumBytesAtAlign8; |