diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2016-08-16 21:17:51 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2016-08-16 21:17:51 +0000 |
commit | e7145dcb9f6563389ebbfa0572ef7589bdd94b1b (patch) | |
tree | b1b30c4998f6e9769784be87d402e4f8db13e34d /contrib/llvm/tools/clang/lib/Sema | |
parent | 3ca95b020283db6244cab92ede73c969253b6a31 (diff) | |
parent | 7fd6ba58d980ec2bf312a80444948501dd27d020 (diff) |
Update clang to release_39 branch r276489, and resolve conflicts.
Notes
Notes:
svn path=/projects/clang390-import/; revision=304241
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema')
46 files changed, 14559 insertions, 6216 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 5f74343fbd95..67762bde3439 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp @@ -889,7 +889,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD, // the initializer of that declaration & we didn't already suggest // an initialization fixit. if (!SuggestInitializationFixit(S, VD)) - S.Diag(VD->getLocStart(), diag::note_uninit_var_def) + S.Diag(VD->getLocStart(), diag::note_var_declared_here) << VD->getDeclName(); return true; @@ -1071,6 +1071,34 @@ namespace { }; } // anonymous namespace +static StringRef getFallthroughAttrSpelling(Preprocessor &PP, + SourceLocation Loc) { + TokenValue FallthroughTokens[] = { + tok::l_square, tok::l_square, + PP.getIdentifierInfo("fallthrough"), + tok::r_square, tok::r_square + }; + + TokenValue ClangFallthroughTokens[] = { + tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), + tok::coloncolon, PP.getIdentifierInfo("fallthrough"), + tok::r_square, tok::r_square + }; + + bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z; + + StringRef MacroName; + if (PreferClangAttr) + MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); + if (MacroName.empty()) + MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens); + if (MacroName.empty() && !PreferClangAttr) + MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens); + if (MacroName.empty()) + MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]"; + return MacroName; +} + static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, bool PerFunction) { // Only perform this analysis when using C++11. There is no good workflow @@ -1129,15 +1157,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, } if (!(B->empty() && Term && isa<BreakStmt>(Term))) { Preprocessor &PP = S.getPreprocessor(); - TokenValue Tokens[] = { - tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"), - tok::coloncolon, PP.getIdentifierInfo("fallthrough"), - tok::r_square, tok::r_square - }; - StringRef AnnotationSpelling = "[[clang::fallthrough]]"; - StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens); - if (!MacroName.empty()) - AnnotationSpelling = MacroName; + StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L); SmallString<64> TextToInsert(AnnotationSpelling); TextToInsert += "; "; S.Diag(L, diag::note_insert_fallthrough_fixit) << @@ -1151,7 +1171,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC, } for (const auto *F : FM.getFallthroughStmts()) - S.Diag(F->getLocStart(), diag::warn_fallthrough_attr_invalid_placement); + S.Diag(F->getLocStart(), diag::err_fallthrough_attr_invalid_placement); } static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM, @@ -1302,21 +1322,27 @@ static void diagnoseRepeatedUseOfWeak(Sema &S, Ivar } ObjectKind; - const NamedDecl *D = Key.getProperty(); - if (isa<VarDecl>(D)) + const NamedDecl *KeyProp = Key.getProperty(); + if (isa<VarDecl>(KeyProp)) ObjectKind = Variable; - else if (isa<ObjCPropertyDecl>(D)) + else if (isa<ObjCPropertyDecl>(KeyProp)) ObjectKind = Property; - else if (isa<ObjCMethodDecl>(D)) + else if (isa<ObjCMethodDecl>(KeyProp)) ObjectKind = ImplicitProperty; - else if (isa<ObjCIvarDecl>(D)) + else if (isa<ObjCIvarDecl>(KeyProp)) ObjectKind = Ivar; else llvm_unreachable("Unexpected weak object kind!"); + // Do not warn about IBOutlet weak property receivers being set to null + // since they are typically only used from the main thread. + if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp)) + if (Prop->hasAttr<IBOutletAttr>()) + continue; + // Show the first time the object was read. S.Diag(FirstRead->getLocStart(), DiagKind) - << int(ObjectKind) << D << int(FunctionKind) + << int(ObjectKind) << KeyProp << int(FunctionKind) << FirstRead->getSourceRange(); // Print all the other accesses as notes. @@ -1871,7 +1897,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, if (cast<DeclContext>(D)->isDependentContext()) return; - if (Diags.hasUncompilableErrorOccurred() || Diags.hasFatalErrorOccurred()) { + if (Diags.hasUncompilableErrorOccurred()) { // Flush out any possibly unreachable diagnostics. flushDiagnostics(S, fscope); return; @@ -2038,7 +2064,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P, !Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart()); bool FallThroughDiagPerFunction = !Diags.isIgnored( diag::warn_unannotated_fallthrough_per_function, D->getLocStart()); - if (FallThroughDiagFull || FallThroughDiagPerFunction) { + if (FallThroughDiagFull || FallThroughDiagPerFunction || + fscope->HasFallthroughStmt) { DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull); } diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp index 3c61c95ad8ec..cae9393f9f3a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp @@ -159,6 +159,7 @@ struct ParsedAttrInfo { unsigned HasCustomParsing : 1; unsigned IsTargetSpecific : 1; unsigned IsType : 1; + unsigned IsStmt : 1; unsigned IsKnownToGCC : 1; bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr, @@ -204,6 +205,10 @@ bool AttributeList::isTypeAttr() const { return getInfo(*this).IsType; } +bool AttributeList::isStmtAttr() const { + return getInfo(*this).IsStmt; +} + bool AttributeList::existsInTarget(const TargetInfo &Target) const { return getInfo(*this).ExistsInTarget(Target); } diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp index 18e9a5911641..9a4f0d921bf4 100644 --- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp @@ -309,7 +309,7 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) { if (!Interface) { // Assign an empty StringRef but with non-null data to distinguish // between empty because we didn't process the DeclContext yet. - CachedParentName = StringRef((const char *)~0U, 0); + CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0); return StringRef(); } diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp index 6f6c4ca5848f..b9d2843b0558 100644 --- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp @@ -15,10 +15,10 @@ #include "clang/AST/ASTContext.h" #include "clang/AST/DeclCXX.h" #include "clang/AST/Expr.h" +#include "clang/AST/LocInfoType.h" #include "clang/AST/TypeLoc.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/TargetInfo.h" -#include "clang/Sema/LocInfoType.h" #include "clang/Sema/ParsedTemplate.h" #include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" @@ -289,6 +289,7 @@ bool Declarator::isDeclarationOfFunction() const { case TST_decimal32: case TST_decimal64: case TST_double: + case TST_float128: case TST_enum: case TST_error: case TST_float: @@ -302,6 +303,8 @@ bool Declarator::isDeclarationOfFunction() const { case TST_unspecified: case TST_void: case TST_wchar: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" return false; case TST_decltype_auto: @@ -455,6 +458,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_half: return "half"; case DeclSpec::TST_float: return "float"; case DeclSpec::TST_double: return "double"; + case DeclSpec::TST_float128: return "__float128"; case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool"; case DeclSpec::TST_decimal32: return "_Decimal32"; case DeclSpec::TST_decimal64: return "_Decimal64"; @@ -474,6 +478,10 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T, case DeclSpec::TST_underlyingType: return "__underlying_type"; case DeclSpec::TST_unknown_anytype: return "__unknown_anytype"; case DeclSpec::TST_atomic: return "_Atomic"; +#define GENERIC_IMAGE_TYPE(ImgType, Id) \ + case DeclSpec::TST_##ImgType##_t: \ + return #ImgType "_t"; +#include "clang/Basic/OpenCLImageTypes.def" case DeclSpec::TST_error: return "(error)"; } llvm_unreachable("Unknown typespec!"); @@ -486,6 +494,7 @@ const char *DeclSpec::getSpecifierName(TQ T) { case DeclSpec::TQ_restrict: return "restrict"; case DeclSpec::TQ_volatile: return "volatile"; case DeclSpec::TQ_atomic: return "_Atomic"; + case DeclSpec::TQ_unaligned: return "__unaligned"; } llvm_unreachable("Unknown typespec!"); } @@ -787,6 +796,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec, case TQ_const: TQ_constLoc = Loc; return false; case TQ_restrict: TQ_restrictLoc = Loc; return false; case TQ_volatile: TQ_volatileLoc = Loc; return false; + case TQ_unaligned: TQ_unalignedLoc = Loc; return false; case TQ_atomic: TQ_atomicLoc = Loc; return false; } @@ -953,10 +963,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) { TypeSpecSign != TSS_unspecified || TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || TypeQualifiers)) { - const unsigned NumLocs = 8; + const unsigned NumLocs = 9; SourceLocation ExtraLocs[NumLocs] = { TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, - TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc + TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc }; FixItHint Hints[NumLocs]; SourceLocation FirstLoc; diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp index 53263bac546f..0bdb19490bc5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp @@ -381,7 +381,7 @@ void IdentifierResolver::updatingIdentifier(IdentifierInfo &II) { PP.getExternalSource()->updateOutOfDateIdentifier(II); if (II.isFromAST()) - II.setChangedSinceDeserialization(); + II.setFETokenInfoChangedSinceDeserialization(); } //===----------------------------------------------------------------------===// diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp index c394d24d5fdc..bdbe06c4969d 100644 --- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp @@ -270,7 +270,8 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D, /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively /// walking the AST as needed. -void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) { +void JumpScopeChecker::BuildScopeInformation(Stmt *S, + unsigned &origParentScope) { // If this is a statement, rather than an expression, scopes within it don't // propagate out into the enclosing scope. Otherwise we have to worry // about block literals, which have the lifetime of their enclosing statement. @@ -278,7 +279,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S)) ? origParentScope : independentParentScope); - bool SkipFirstSubStmt = false; + unsigned StmtsToSkip = 0u; // If we found a label, remember that it is in ParentScope scope. switch (S->getStmtClass()) { @@ -303,11 +304,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) break; case Stmt::SwitchStmtClass: - // Evaluate the condition variable before entering the scope of the switch - // statement. + // Evaluate the C++17 init stmt and condition variable + // before entering the scope of the switch statement. + if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) { + BuildScopeInformation(Init, ParentScope); + ++StmtsToSkip; + } if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) { BuildScopeInformation(Var, ParentScope); - SkipFirstSubStmt = true; + ++StmtsToSkip; } // Fall through @@ -318,199 +323,248 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) Jumps.push_back(S); break; + case Stmt::IfStmtClass: { + IfStmt *IS = cast<IfStmt>(S); + if (!IS->isConstexpr()) + break; + + 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())); + 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())); + 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())); + BuildScopeInformation(Else, NewParentScope); + } + return; + } + case Stmt::CXXTryStmtClass: { CXXTryStmt *TS = cast<CXXTryStmt>(S); - unsigned newParentScope; - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_cxx_try, - diag::note_exits_cxx_try, - TS->getSourceRange().getBegin())); - if (Stmt *TryBlock = TS->getTryBlock()) - BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); + { + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_cxx_try, + diag::note_exits_cxx_try, + TS->getSourceRange().getBegin())); + if (Stmt *TryBlock = TS->getTryBlock()) + BuildScopeInformation(TryBlock, NewParentScope); + } // Jump from the catch into the try is not allowed either. for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { CXXCatchStmt *CS = TS->getHandler(I); + unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_catch, diag::note_exits_cxx_catch, CS->getSourceRange().getBegin())); - BuildScopeInformation(CS->getHandlerBlock(), - (newParentScope = Scopes.size()-1)); + BuildScopeInformation(CS->getHandlerBlock(), NewParentScope); } return; } case Stmt::SEHTryStmtClass: { SEHTryStmt *TS = cast<SEHTryStmt>(S); - unsigned newParentScope; - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_seh_try, - diag::note_exits_seh_try, - TS->getSourceRange().getBegin())); - if (Stmt *TryBlock = TS->getTryBlock()) - BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1)); + { + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_seh_try, + diag::note_exits_seh_try, + TS->getSourceRange().getBegin())); + if (Stmt *TryBlock = TS->getTryBlock()) + BuildScopeInformation(TryBlock, NewParentScope); + } // Jump from __except or __finally into the __try are not allowed either. if (SEHExceptStmt *Except = TS->getExceptHandler()) { + unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_seh_except, diag::note_exits_seh_except, Except->getSourceRange().getBegin())); - BuildScopeInformation(Except->getBlock(), - (newParentScope = Scopes.size()-1)); + BuildScopeInformation(Except->getBlock(), NewParentScope); } else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) { + unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_seh_finally, diag::note_exits_seh_finally, Finally->getSourceRange().getBegin())); - BuildScopeInformation(Finally->getBlock(), - (newParentScope = Scopes.size()-1)); + BuildScopeInformation(Finally->getBlock(), NewParentScope); } return; } - default: - break; - } - - for (Stmt *SubStmt : S->children()) { - if (SkipFirstSubStmt) { - SkipFirstSubStmt = false; - continue; - } - - if (!SubStmt) continue; - - // Cases, labels, and defaults aren't "scope parents". It's also - // important to handle these iteratively instead of recursively in - // 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(); - else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) - Next = LS->getSubStmt(); - else - break; - - LabelAndGotoScopes[SubStmt] = ParentScope; - SubStmt = Next; - } - + case Stmt::DeclStmtClass: { // If this is a declstmt with a VLA definition, it defines a scope from here // to the end of the containing context. - if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { - // The decl statement creates a scope if any of the decls in it are VLAs - // or have the cleanup attribute. - for (auto *I : DS->decls()) - BuildScopeInformation(I, ParentScope); - continue; - } + DeclStmt *DS = cast<DeclStmt>(S); + // The decl statement creates a scope if any of the decls in it are VLAs + // or have the cleanup attribute. + for (auto *I : DS->decls()) + BuildScopeInformation(I, origParentScope); + return; + } + + case Stmt::ObjCAtTryStmtClass: { // Disallow jumps into any part of an @try statement by pushing a scope and // walking all sub-stmts in that scope. - if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { - unsigned newParentScope; - // Recursively walk the AST for the @try part. + ObjCAtTryStmt *AT = cast<ObjCAtTryStmt>(S); + // Recursively walk the AST for the @try part. + { + unsigned NewParentScope = Scopes.size(); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_try, diag::note_exits_objc_try, AT->getAtTryLoc())); if (Stmt *TryPart = AT->getTryBody()) - BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1)); - - // Jump from the catch to the finally or try is not valid. - for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { - ObjCAtCatchStmt *AC = AT->getCatchStmt(I); - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_objc_catch, - diag::note_exits_objc_catch, - AC->getAtCatchLoc())); - // @catches are nested and it isn't - BuildScopeInformation(AC->getCatchBody(), - (newParentScope = Scopes.size()-1)); - } + BuildScopeInformation(TryPart, NewParentScope); + } - // Jump from the finally to the try or catch is not valid. - if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_objc_finally, - diag::note_exits_objc_finally, - AF->getAtFinallyLoc())); - BuildScopeInformation(AF, (newParentScope = Scopes.size()-1)); - } + // Jump from the catch to the finally or try is not valid. + for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) { + ObjCAtCatchStmt *AC = AT->getCatchStmt(I); + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_catch, + diag::note_exits_objc_catch, + AC->getAtCatchLoc())); + // @catches are nested and it isn't + BuildScopeInformation(AC->getCatchBody(), NewParentScope); + } - continue; + // Jump from the finally to the try or catch is not valid. + if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_finally, + diag::note_exits_objc_finally, + AF->getAtFinallyLoc())); + BuildScopeInformation(AF, NewParentScope); } - unsigned newParentScope; + return; + } + + case Stmt::ObjCAtSynchronizedStmtClass: { // Disallow jumps into the protected statement of an @synchronized, but // allow jumps into the object expression it protects. - if (ObjCAtSynchronizedStmt *AS = - dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)) { - // Recursively walk the AST for the @synchronized object expr, it is - // evaluated in the normal scope. - BuildScopeInformation(AS->getSynchExpr(), ParentScope); - - // Recursively walk the AST for the @synchronized part, protected by a new - // scope. - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_objc_synchronized, - diag::note_exits_objc_synchronized, - AS->getAtSynchronizedLoc())); - BuildScopeInformation(AS->getSynchBody(), - (newParentScope = Scopes.size()-1)); - continue; - } + ObjCAtSynchronizedStmt *AS = cast<ObjCAtSynchronizedStmt>(S); + // Recursively walk the AST for the @synchronized object expr, it is + // evaluated in the normal scope. + BuildScopeInformation(AS->getSynchExpr(), ParentScope); + + // Recursively walk the AST for the @synchronized part, protected by a new + // scope. + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_synchronized, + diag::note_exits_objc_synchronized, + AS->getAtSynchronizedLoc())); + BuildScopeInformation(AS->getSynchBody(), NewParentScope); + return; + } + case Stmt::ObjCAutoreleasePoolStmtClass: { // Disallow jumps into the protected statement of an @autoreleasepool. - if (ObjCAutoreleasePoolStmt *AS = - dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)) { - // Recursively walk the AST for the @autoreleasepool part, protected by a - // new scope. - Scopes.push_back(GotoScope(ParentScope, - diag::note_protected_by_objc_autoreleasepool, - diag::note_exits_objc_autoreleasepool, - AS->getAtLoc())); - BuildScopeInformation(AS->getSubStmt(), - (newParentScope = Scopes.size() - 1)); - continue; - } + ObjCAutoreleasePoolStmt *AS = cast<ObjCAutoreleasePoolStmt>(S); + // Recursively walk the AST for the @autoreleasepool part, protected by a + // new scope. + unsigned NewParentScope = Scopes.size(); + Scopes.push_back(GotoScope(ParentScope, + diag::note_protected_by_objc_autoreleasepool, + diag::note_exits_objc_autoreleasepool, + AS->getAtLoc())); + BuildScopeInformation(AS->getSubStmt(), NewParentScope); + return; + } + case Stmt::ExprWithCleanupsClass: { // Disallow jumps past full-expressions that use blocks with // non-trivial cleanups of their captures. This is theoretically // implementable but a lot of work which we haven't felt up to doing. - if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) { - for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { - const BlockDecl *BDecl = EWC->getObject(i); - for (const auto &CI : BDecl->captures()) { - VarDecl *variable = CI.getVariable(); - BuildScopeInformation(variable, BDecl, ParentScope); - } + ExprWithCleanups *EWC = cast<ExprWithCleanups>(S); + for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) { + const BlockDecl *BDecl = EWC->getObject(i); + for (const auto &CI : BDecl->captures()) { + VarDecl *variable = CI.getVariable(); + BuildScopeInformation(variable, BDecl, origParentScope); } } + break; + } + case Stmt::MaterializeTemporaryExprClass: { // Disallow jumps out of scopes containing temporaries lifetime-extended to // automatic storage duration. - if (MaterializeTemporaryExpr *MTE = - dyn_cast<MaterializeTemporaryExpr>(SubStmt)) { - if (MTE->getStorageDuration() == SD_Automatic) { - SmallVector<const Expr *, 4> CommaLHS; - SmallVector<SubobjectAdjustment, 4> Adjustments; - const Expr *ExtendedObject = - MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments( - CommaLHS, Adjustments); - if (ExtendedObject->getType().isDestructedType()) { - Scopes.push_back(GotoScope(ParentScope, 0, - diag::note_exits_temporary_dtor, - ExtendedObject->getExprLoc())); - ParentScope = Scopes.size()-1; - } + MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S); + if (MTE->getStorageDuration() == SD_Automatic) { + SmallVector<const Expr *, 4> CommaLHS; + SmallVector<SubobjectAdjustment, 4> Adjustments; + const Expr *ExtendedObject = + MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments( + CommaLHS, Adjustments); + if (ExtendedObject->getType().isDestructedType()) { + Scopes.push_back(GotoScope(ParentScope, 0, + diag::note_exits_temporary_dtor, + ExtendedObject->getExprLoc())); + origParentScope = Scopes.size()-1; } } + break; + } + + case Stmt::CaseStmtClass: + case Stmt::DefaultStmtClass: + case Stmt::LabelStmtClass: + LabelAndGotoScopes[S] = ParentScope; + break; + + default: + break; + } + + for (Stmt *SubStmt : S->children()) { + if (!SubStmt) + continue; + if (StmtsToSkip) { + --StmtsToSkip; + continue; + } + + // Cases, labels, and defaults aren't "scope parents". It's also + // important to handle these iteratively instead of recursively in + // 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(); + else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt)) + Next = LS->getSubStmt(); + else + break; + + LabelAndGotoScopes[SubStmt] = ParentScope; + SubStmt = Next; + } // Recursively walk the AST. BuildScopeInformation(SubStmt, ParentScope); diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp index 0f93421ac21b..eee4c00324ba 100644 --- a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp @@ -197,6 +197,11 @@ void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) { Sources[i]->ReadMethodPool(Sel); } +void MultiplexExternalSemaSource::updateOutOfDateSelector(Selector Sel) { + for(size_t i = 0; i < Sources.size(); ++i) + Sources[i]->updateOutOfDateSelector(Sel); +} + void MultiplexExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl<NamespaceDecl*> &Namespaces){ for(size_t i = 0; i < Sources.size(); ++i) @@ -204,7 +209,7 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces( } void MultiplexExternalSemaSource::ReadUndefinedButUsed( - llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined){ + llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) { for(size_t i = 0; i < Sources.size(); ++i) Sources[i]->ReadUndefinedButUsed(Undefined); } diff --git a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp index 7c70048acfbf..ae5b181c6728 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp @@ -18,7 +18,7 @@ using namespace clang; -void Scope::Init(Scope *parent, unsigned flags) { +void Scope::setFlags(Scope *parent, unsigned flags) { AnyParent = parent; Flags = flags; @@ -83,6 +83,10 @@ void Scope::Init(Scope *parent, unsigned flags) { else incrementMSManglingNumber(); } +} + +void Scope::Init(Scope *parent, unsigned flags) { + setFlags(parent, flags); DeclsInScope.clear(); UsingDirectives.clear(); @@ -130,7 +134,7 @@ void Scope::mergeNRVOIntoParent() { getParent()->addNRVOCandidate(NRVO.getPointer()); } -void Scope::dump() const { dumpImpl(llvm::errs()); } +LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); } void Scope::dumpImpl(raw_ostream &OS) const { unsigned Flags = getFlags(); diff --git a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp index cbd7ef7abb41..4b2e13e20deb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp @@ -28,6 +28,7 @@ void FunctionScopeInfo::Clear() { HasBranchIntoScope = false; HasIndirectGoto = false; HasDroppedStmt = false; + HasOMPDeclareReductionCombiner = false; ObjCShouldCallSuper = false; ObjCIsDesignatedInit = false; ObjCWarnForNoDesignatedInitChain = false; @@ -85,11 +86,13 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) { if (BaseProp) { D = getBestPropertyDecl(BaseProp); - const Expr *DoubleBase = BaseProp->getBase(); - if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase)) - DoubleBase = OVE->getSourceExpr(); + if (BaseProp->isObjectReceiver()) { + const Expr *DoubleBase = BaseProp->getBase(); + if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase)) + DoubleBase = OVE->getSourceExpr(); - IsExact = DoubleBase->isObjCSelfExpr(); + IsExact = DoubleBase->isObjCSelfExpr(); + } } break; } @@ -212,7 +215,7 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) { // Has there been a read from the object using this Expr? FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse = - std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true)); + llvm::find(llvm::reverse(Uses->second), WeakUseTy(E, true)); if (ThisUse == Uses->second.rend()) return; diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp index 39b8cc9f0c63..a242ace9f64e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp @@ -52,13 +52,14 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); } PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context, const Preprocessor &PP) { PrintingPolicy Policy = Context.getPrintingPolicy(); + // Our printing policy is copied over the ASTContext printing policy whenever + // a diagnostic is emitted, so recompute it. Policy.Bool = Context.getLangOpts().Bool; if (!Policy.Bool) { - if (const MacroInfo * - BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) { + if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) { Policy.Bool = BoolMacro->isObjectLike() && - BoolMacro->getNumTokens() == 1 && - BoolMacro->getReplacementToken(0).is(tok::kw__Bool); + BoolMacro->getNumTokens() == 1 && + BoolMacro->getReplacementToken(0).is(tok::kw__Bool); } } @@ -79,14 +80,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()), CollectStats(false), CodeCompleter(CodeCompleter), CurContext(nullptr), OriginalLexicalContext(nullptr), - PackContext(nullptr), MSStructPragmaOn(false), + MSStructPragmaOn(false), MSPointerToMemberRepresentationMethod( LangOpts.getMSPointerToMemberRepresentationMethod()), - VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), - DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr), - CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr), + VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)), + PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr), + ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr), + VisContext(nullptr), IsBuildingRecoveryCallExpr(false), - ExprNeedsCleanups(false), LateTemplateParser(nullptr), + Cleanup{}, LateTemplateParser(nullptr), LateTemplateParserCleanup(nullptr), OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr), CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr), @@ -122,7 +124,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer, // Tell diagnostics how to render things from the AST library. Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context); - ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, false, nullptr, false); + ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, CleanupInfo{}, nullptr, + false); FunctionScopes.push_back(new FunctionScopeInfo(Diags)); @@ -191,6 +194,11 @@ void Sema::Initialize() { PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope); } + // Create the internal type for the *StringMakeConstantString builtins. + DeclarationName ConstantString = &Context.Idents.get("__NSConstantString"); + if (IdResolver.begin(ConstantString) == IdResolver.end()) + PushOnScopeChains(Context.getCFConstantStringDecl(), TUScope); + // Initialize Microsoft "predefined C++ types". if (getLangOpts().MSVCCompat) { if (getLangOpts().CPlusPlus && @@ -201,25 +209,17 @@ void Sema::Initialize() { addImplicitTypedef("size_t", Context.getSizeType()); } - // Initialize predefined OpenCL types. + // Initialize predefined OpenCL types and supported optional core features. if (getLangOpts().OpenCL) { - addImplicitTypedef("image1d_t", Context.OCLImage1dTy); - addImplicitTypedef("image1d_array_t", Context.OCLImage1dArrayTy); - addImplicitTypedef("image1d_buffer_t", Context.OCLImage1dBufferTy); - addImplicitTypedef("image2d_t", Context.OCLImage2dTy); - addImplicitTypedef("image2d_array_t", Context.OCLImage2dArrayTy); - addImplicitTypedef("image3d_t", Context.OCLImage3dTy); +#define OPENCLEXT(Ext) \ + if (Context.getTargetInfo().getSupportedOpenCLOpts().is_##Ext##_supported_core( \ + getLangOpts().OpenCLVersion)) \ + getOpenCLOptions().Ext = 1; +#include "clang/Basic/OpenCLExtensions.def" + addImplicitTypedef("sampler_t", Context.OCLSamplerTy); addImplicitTypedef("event_t", Context.OCLEventTy); if (getLangOpts().OpenCLVersion >= 200) { - addImplicitTypedef("image2d_depth_t", Context.OCLImage2dDepthTy); - addImplicitTypedef("image2d_array_depth_t", - Context.OCLImage2dArrayDepthTy); - addImplicitTypedef("image2d_msaa_t", Context.OCLImage2dMSAATy); - addImplicitTypedef("image2d_array_msaa_t", Context.OCLImage2dArrayMSAATy); - addImplicitTypedef("image2d_msaa_depth_t", Context.OCLImage2dMSAADepthTy); - addImplicitTypedef("image2d_array_msaa_depth_t", - Context.OCLImage2dArrayMSAADepthTy); addImplicitTypedef("clk_event_t", Context.OCLClkEventTy); addImplicitTypedef("queue_t", Context.OCLQueueTy); addImplicitTypedef("ndrange_t", Context.OCLNDRangeTy); @@ -261,7 +261,6 @@ void Sema::Initialize() { Sema::~Sema() { llvm::DeleteContainerSeconds(LateParsedTemplateMap); - if (PackContext) FreePackedContext(); if (VisContext) FreeVisContext(); // Kill all the active scopes. for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I) @@ -470,13 +469,12 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) { return false; } -/// Obtains a sorted list of functions that are undefined but ODR-used. +/// Obtains a sorted list of functions and variables that are undefined but +/// ODR-used. void Sema::getUndefinedButUsed( SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) { - for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator - I = UndefinedButUsed.begin(), E = UndefinedButUsed.end(); - I != E; ++I) { - NamedDecl *ND = I->first; + for (const auto &UndefinedUse : UndefinedButUsed) { + NamedDecl *ND = UndefinedUse.first; // Ignore attributes that have become invalid. if (ND->isInvalidDecl()) continue; @@ -491,30 +489,15 @@ void Sema::getUndefinedButUsed( !FD->getMostRecentDecl()->isInlined()) continue; } else { - if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly) + auto *VD = cast<VarDecl>(ND); + if (VD->hasDefinition() != VarDecl::DeclarationOnly) continue; - if (ND->isExternallyVisible()) + if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline()) continue; } - Undefined.push_back(std::make_pair(ND, I->second)); + Undefined.push_back(std::make_pair(ND, UndefinedUse.second)); } - - // Sort (in order of use site) so that we're not dependent on the iteration - // order through an llvm::DenseMap. - SourceManager &SM = Context.getSourceManager(); - std::sort(Undefined.begin(), Undefined.end(), - [&SM](const std::pair<NamedDecl *, SourceLocation> &l, - const std::pair<NamedDecl *, SourceLocation> &r) { - if (l.second.isValid() && !r.second.isValid()) - return true; - if (!l.second.isValid() && r.second.isValid()) - return false; - if (l.second != r.second) - return SM.isBeforeInTranslationUnit(l.second, r.second); - return SM.isBeforeInTranslationUnit(l.first->getLocation(), - r.first->getLocation()); - }); } /// checkUndefinedButUsed - Check for undefined objects with internal linkage @@ -541,14 +524,22 @@ static void checkUndefinedButUsed(Sema &S) { if (!ND->isExternallyVisible()) { S.Diag(ND->getLocation(), diag::warn_undefined_internal) << isa<VarDecl>(ND) << ND; - } else { - assert(cast<FunctionDecl>(ND)->getMostRecentDecl()->isInlined() && + } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) { + (void)FD; + assert(FD->getMostRecentDecl()->isInlined() && "used object requires definition but isn't inline or internal?"); + // FIXME: This is ill-formed; we should reject. S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND; + } else { + assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() && + "used var requires definition but isn't inline or internal?"); + S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND; } if (I->second.isValid()) S.Diag(I->second, diag::note_used_here); } + + S.UndefinedButUsed.clear(); } void Sema::LoadExternalWeakUndeclaredIdentifiers() { @@ -744,6 +735,12 @@ void Sema::ActOnEndOfTranslationUnit() { !Diags.isIgnored(diag::warn_delegating_ctor_cycle, SourceLocation())) CheckDelegatingCtorCycles(); + if (!Diags.hasErrorOccurred()) { + if (ExternalSource) + ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); + checkUndefinedButUsed(*this); + } + if (TUKind == TU_Module) { // If we are building a module, resolve all of the exported declarations // now. @@ -877,10 +874,6 @@ void Sema::ActOnEndOfTranslationUnit() { } } - if (ExternalSource) - ExternalSource->ReadUndefinedButUsed(UndefinedButUsed); - checkUndefinedButUsed(*this); - emitAndClearUnusedLocalTypedefWarnings(); } @@ -1260,14 +1253,14 @@ void Sema::ActOnComment(SourceRange Comment) { ExternalSemaSource::~ExternalSemaSource() {} void ExternalSemaSource::ReadMethodPool(Selector Sel) { } +void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { } void ExternalSemaSource::ReadKnownNamespaces( SmallVectorImpl<NamespaceDecl *> &Namespaces) { } void ExternalSemaSource::ReadUndefinedButUsed( - llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) { -} + llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {} void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector< FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &) {} @@ -1281,10 +1274,10 @@ void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const { } OS << Message; - if (TheDecl && isa<NamedDecl>(TheDecl)) { - std::string Name = cast<NamedDecl>(TheDecl)->getNameAsString(); - if (!Name.empty()) - OS << " '" << Name << '\''; + if (auto *ND = dyn_cast_or_null<NamedDecl>(TheDecl)) { + OS << " '"; + ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), true); + OS << "'"; } OS << '\n'; @@ -1509,7 +1502,8 @@ IdentifierInfo *Sema::getFloat128Identifier() const { void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD, CapturedRegionKind K) { CapturingScopeInfo *CSI = new CapturedRegionScopeInfo( - getDiagnostics(), S, CD, RD, CD->getContextParam(), K); + getDiagnostics(), S, CD, RD, CD->getContextParam(), K, + (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0); CSI->ReturnType = Context.VoidTy; FunctionScopes.push_back(CSI); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp index e9772bc52049..98a918bd7d63 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp @@ -291,9 +291,10 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived, SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack while (true) { - if (Derived->isDependentContext() && !Derived->hasDefinition()) + if (Derived->isDependentContext() && !Derived->hasDefinition() && + !Derived->isLambda()) return AR_dependent; - + for (const auto &I : Derived->bases()) { const CXXRecordDecl *RD; @@ -410,14 +411,8 @@ static AccessResult MatchesFriend(Sema &S, return AR_accessible; if (EC.isDependent()) { - CanQualType FriendTy - = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend)); - - for (EffectiveContext::record_iterator - I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) { - CanQualType ContextTy - = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I)); - if (MightInstantiateTo(S, ContextTy, FriendTy)) + for (const CXXRecordDecl *Context : EC.Records) { + if (MightInstantiateTo(Context, Friend)) return AR_dependent; } } @@ -1615,10 +1610,10 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc, /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, + DeclAccessPair Found, const InitializedEntity &Entity, - AccessSpecifier Access, bool IsCopyBindingRefToTemp) { - if (!getLangOpts().AccessControl || Access == AS_public) + if (!getLangOpts().AccessControl || Found.getAccess() == AS_public) return AR_accessible; PartialDiagnostic PD(PDiag()); @@ -1652,17 +1647,17 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, } - return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD); + return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD); } /// Checks access to a constructor. Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, CXXConstructorDecl *Constructor, + DeclAccessPair Found, const InitializedEntity &Entity, - AccessSpecifier Access, const PartialDiagnostic &PD) { if (!getLangOpts().AccessControl || - Access == AS_public) + Found.getAccess() == AS_public) return AR_accessible; CXXRecordDecl *NamingClass = Constructor->getParent(); @@ -1670,16 +1665,28 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc, // Initializing a base sub-object is an instance method call on an // object of the derived class. Otherwise, we have an instance method // call on an object of the constructed type. + // + // FIXME: If we have a parent, we're initializing the base class subobject + // in aggregate initialization. It's not clear whether the object class + // should be the base class or the derived class in that case. CXXRecordDecl *ObjectClass; - if (Entity.getKind() == InitializedEntity::EK_Base) { + if ((Entity.getKind() == InitializedEntity::EK_Base || + Entity.getKind() == InitializedEntity::EK_Delegating) && + !Entity.getParent()) { ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent(); + } else if (auto *Shadow = + dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) { + // If we're using an inheriting constructor to construct an object, + // the object class is the derived class, not the base class. + ObjectClass = Shadow->getParent(); } else { ObjectClass = NamingClass; } - AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass, - DeclAccessPair::make(Constructor, Access), - Context.getTypeDeclType(ObjectClass)); + AccessTarget AccessEntity( + Context, AccessTarget::Member, NamingClass, + DeclAccessPair::make(Constructor, Found.getAccess()), + Context.getTypeDeclType(ObjectClass)); AccessEntity.setDiag(PD); return CheckAccess(*this, UseLoc, AccessEntity); @@ -1767,9 +1774,9 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) { // while the ParsingDeclarator is active. EffectiveContext EC(CurContext); switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) { - case AR_accessible: return Sema::AR_accessible; - case AR_inaccessible: return Sema::AR_inaccessible; - case AR_dependent: return Sema::AR_dependent; + case ::AR_accessible: return Sema::AR_accessible; + case ::AR_inaccessible: return Sema::AR_inaccessible; + case ::AR_dependent: return Sema::AR_dependent; } llvm_unreachable("invalid access result"); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp index 5a29bad29f4d..0d7fba5c6709 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp @@ -25,103 +25,37 @@ using namespace clang; // Pragma 'pack' and 'options align' //===----------------------------------------------------------------------===// -namespace { - struct PackStackEntry { - // We just use a sentinel to represent when the stack is set to mac68k - // alignment. - static const unsigned kMac68kAlignmentSentinel = ~0U; - - unsigned Alignment; - IdentifierInfo *Name; - }; - - /// PragmaPackStack - Simple class to wrap the stack used by #pragma - /// pack. - class PragmaPackStack { - typedef std::vector<PackStackEntry> stack_ty; - - /// Alignment - The current user specified alignment. - unsigned Alignment; - - /// Stack - Entries in the #pragma pack stack, consisting of saved - /// alignments and optional names. - stack_ty Stack; - - public: - PragmaPackStack() : Alignment(0) {} - - void setAlignment(unsigned A) { Alignment = A; } - unsigned getAlignment() { return Alignment; } - - /// push - Push the current alignment onto the stack, optionally - /// using the given \arg Name for the record, if non-zero. - void push(IdentifierInfo *Name) { - PackStackEntry PSE = { Alignment, Name }; - Stack.push_back(PSE); - } - - /// pop - Pop a record from the stack and restore the current - /// alignment to the previous value. If \arg Name is non-zero then - /// the first such named record is popped, otherwise the top record - /// is popped. Returns true if the pop succeeded. - bool pop(IdentifierInfo *Name, bool IsReset); - }; -} // end anonymous namespace. - -bool PragmaPackStack::pop(IdentifierInfo *Name, bool IsReset) { - // If name is empty just pop top. - if (!Name) { - // An empty stack is a special case... - if (Stack.empty()) { - // If this isn't a reset, it is always an error. - if (!IsReset) - return false; - - // Otherwise, it is an error only if some alignment has been set. - if (!Alignment) - return false; - - // Otherwise, reset to the default alignment. - Alignment = 0; - } else { - Alignment = Stack.back().Alignment; - Stack.pop_back(); - } - - return true; - } - - // Otherwise, find the named record. - for (unsigned i = Stack.size(); i != 0; ) { - --i; - if (Stack[i].Name == Name) { - // Found it, pop up to and including this record. - Alignment = Stack[i].Alignment; - Stack.erase(Stack.begin() + i, Stack.end()); - return true; - } +Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S, + StringRef SlotLabel, + bool ShouldAct) + : S(S), SlotLabel(SlotLabel), ShouldAct(ShouldAct) { + if (ShouldAct) { + S.VtorDispStack.SentinelAction(PSK_Push, SlotLabel); + S.DataSegStack.SentinelAction(PSK_Push, SlotLabel); + S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel); + S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel); + S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel); } - - return false; } - -/// FreePackedContext - Deallocate and null out PackContext. -void Sema::FreePackedContext() { - delete static_cast<PragmaPackStack*>(PackContext); - PackContext = nullptr; +Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() { + if (ShouldAct) { + S.VtorDispStack.SentinelAction(PSK_Pop, SlotLabel); + S.DataSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel); + S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel); + } } void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) { - // If there is no pack context, we don't need any attributes. - if (!PackContext) + // If there is no pack value, we don't need any attributes. + if (!PackStack.CurrentValue) return; - PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext); - // Otherwise, check to see if we need a max field alignment attribute. - if (unsigned Alignment = Stack->getAlignment()) { - if (Alignment == PackStackEntry::kMac68kAlignmentSentinel) + if (unsigned Alignment = PackStack.CurrentValue) { + if (Alignment == Sema::kMac68kAlignmentSentinel) RD->addAttr(AlignMac68kAttr::CreateImplicit(Context)); else RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context, @@ -136,18 +70,15 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { // FIXME: We should merge AddAlignmentAttributesForRecord with // AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes // all active pragmas and applies them as attributes to class definitions. - if (VtorDispModeStack.back() != getLangOpts().VtorDispMode) + if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode) RD->addAttr( - MSVtorDispAttr::CreateImplicit(Context, VtorDispModeStack.back())); + MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue)); } void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, SourceLocation PragmaLoc) { - if (!PackContext) - PackContext = new PragmaPackStack(); - - PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); - + PragmaMsStackAction Action = Sema::PSK_Reset; + unsigned Alignment = 0; switch (Kind) { // For all targets we support native and natural are the same. // @@ -155,15 +86,15 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, case POAK_Native: case POAK_Power: case POAK_Natural: - Context->push(nullptr); - Context->setAlignment(0); + Action = Sema::PSK_Push_Set; + Alignment = 0; break; // Note that '#pragma options align=packed' is not equivalent to attribute // packed, it has a different precedence relative to attribute aligned. case POAK_Packed: - Context->push(nullptr); - Context->setAlignment(1); + Action = Sema::PSK_Push_Set; + Alignment = 1; break; case POAK_Mac68k: @@ -172,24 +103,31 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind, Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported); return; } - Context->push(nullptr); - Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel); + Action = Sema::PSK_Push_Set; + Alignment = Sema::kMac68kAlignmentSentinel; break; case POAK_Reset: // Reset just pops the top of the stack, or resets the current alignment to // default. - if (!Context->pop(nullptr, /*IsReset=*/true)) { - Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) - << "stack empty"; + Action = Sema::PSK_Pop; + if (PackStack.Stack.empty()) { + if (PackStack.CurrentValue) { + Action = Sema::PSK_Reset; + } else { + Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed) + << "stack empty"; + return; + } } break; } + + PackStack.Act(PragmaLoc, Action, StringRef(), Alignment); } -void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, - Expr *alignment, SourceLocation PragmaLoc, - SourceLocation LParenLoc, SourceLocation RParenLoc) { +void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action, + StringRef SlotLabel, Expr *alignment) { Expr *Alignment = static_cast<Expr *>(alignment); // If specified then alignment must be a "small" power of two. @@ -210,87 +148,48 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name, AlignmentVal = (unsigned) Val.getZExtValue(); } - - if (!PackContext) - PackContext = new PragmaPackStack(); - - PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext); - - switch (Kind) { - case Sema::PPK_Default: // pack([n]) - Context->setAlignment(AlignmentVal); - break; - - case Sema::PPK_Show: // pack(show) + if (Action == Sema::PSK_Show) { // Show the current alignment, making sure to show the right value // for the default. - AlignmentVal = Context->getAlignment(); // FIXME: This should come from the target. + AlignmentVal = PackStack.CurrentValue; if (AlignmentVal == 0) AlignmentVal = 8; - if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel) + if (AlignmentVal == Sema::kMac68kAlignmentSentinel) Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k"; else Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal; - break; - - case Sema::PPK_Push: // pack(push [, id] [, [n]) - Context->push(Name); - // Set the new alignment if specified. - if (Alignment) - Context->setAlignment(AlignmentVal); - break; - - case Sema::PPK_Pop: // pack(pop [, id] [, n]) - // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: - // "#pragma pack(pop, identifier, n) is undefined" - if (Alignment && Name) + } + // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack: + // "#pragma pack(pop, identifier, n) is undefined" + if (Action & Sema::PSK_Pop) { + if (Alignment && !SlotLabel.empty()) Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment); - - // Do the pop. - if (!Context->pop(Name, /*IsReset=*/false)) { - // If a name was specified then failure indicates the name - // wasn't found. Otherwise failure indicates the stack was - // empty. - Diag(PragmaLoc, diag::warn_pragma_pop_failed) - << "pack" << (Name ? "no record matching name" : "stack empty"); - - // FIXME: Warn about popping named records as MSVC does. - } else { - // Pop succeeded, set the new alignment if specified. - if (Alignment) - Context->setAlignment(AlignmentVal); - } - break; + if (PackStack.Stack.empty()) + Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty"; } + + PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal); } void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) { MSStructPragmaOn = (Kind == PMSST_ON); } -void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg) { - // FIXME: Serialize this. - switch (Kind) { - case PCK_Unknown: - llvm_unreachable("unexpected pragma comment kind"); - case PCK_Linker: - Consumer.HandleLinkerOptionPragma(Arg); - return; - case PCK_Lib: - Consumer.HandleDependentLibrary(Arg); - return; - case PCK_Compiler: - case PCK_ExeStr: - case PCK_User: - return; // We ignore all of these. - } - llvm_unreachable("invalid pragma comment kind"); +void Sema::ActOnPragmaMSComment(SourceLocation CommentLoc, + PragmaMSCommentKind Kind, StringRef Arg) { + auto *PCD = PragmaCommentDecl::Create( + Context, Context.getTranslationUnitDecl(), CommentLoc, Kind, Arg); + Context.getTranslationUnitDecl()->addDecl(PCD); + Consumer.HandleTopLevelDecl(DeclGroupRef(PCD)); } -void Sema::ActOnPragmaDetectMismatch(StringRef Name, StringRef Value) { - // FIXME: Serialize this. - Consumer.HandleDetectMismatch(Name, Value); +void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name, + StringRef Value) { + auto *PDMD = PragmaDetectMismatchDecl::Create( + Context, Context.getTranslationUnitDecl(), Loc, Name, Value); + Context.getTranslationUnitDecl()->addDecl(PDMD); + Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD)); } void Sema::ActOnPragmaMSPointersToMembers( @@ -300,29 +199,13 @@ void Sema::ActOnPragmaMSPointersToMembers( ImplicitMSInheritanceAttrLoc = PragmaLoc; } -void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind, +void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action, SourceLocation PragmaLoc, MSVtorDispAttr::Mode Mode) { - switch (Kind) { - case PVDK_Set: - VtorDispModeStack.back() = Mode; - break; - case PVDK_Push: - VtorDispModeStack.push_back(Mode); - break; - case PVDK_Reset: - VtorDispModeStack.clear(); - VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)); - break; - case PVDK_Pop: - VtorDispModeStack.pop_back(); - if (VtorDispModeStack.empty()) { - Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp" - << "stack empty"; - VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)); - } - break; - } + if (Action & PSK_Pop && VtorDispStack.Stack.empty()) + Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp" + << "stack empty"; + VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode); } template<typename ValueType> @@ -331,7 +214,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, llvm::StringRef StackSlotLabel, ValueType Value) { if (Action == PSK_Reset) { - CurrentValue = nullptr; + CurrentValue = DefaultValue; return; } if (Action & PSK_Push) @@ -339,8 +222,9 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation, else if (Action & PSK_Pop) { if (!StackSlotLabel.empty()) { // If we've got a label, try to find it and jump there. - auto I = std::find_if(Stack.rbegin(), Stack.rend(), - [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; }); + auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) { + return x.StackSlotLabel == StackSlotLabel; + }); // If we found the label so pop from there. if (I != Stack.rend()) { CurrentValue = I->Value; @@ -467,7 +351,8 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope, if (VD->isUsed()) Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name; - VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation())); + VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused, + IdTok.getLocation())); } void Sema::AddCFAuditedAttribute(Decl *D) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp index 61dfdd3f7206..90af6d5a927f 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp @@ -11,11 +11,14 @@ /// //===----------------------------------------------------------------------===// -#include "clang/Sema/Sema.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Decl.h" +#include "clang/AST/ExprCXX.h" #include "clang/Lex/Preprocessor.h" +#include "clang/Sema/Lookup.h" +#include "clang/Sema/Sema.h" #include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/Template.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/SmallVector.h" using namespace clang; @@ -67,33 +70,30 @@ Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) { // Ph - preference in host mode // Pd - preference in device mode // H - handled in (x) -// Preferences: b-best, f-fallback, l-last resort, n-never. +// Preferences: N:native, SS:same side, HD:host-device, WS:wrong side, --:never. // -// | F | T | Ph | Pd | H | -// |----+----+----+----+-----+ -// | d | d | b | b | (b) | -// | d | g | n | n | (a) | -// | d | h | l | l | (e) | -// | d | hd | f | f | (c) | -// | g | d | b | b | (b) | -// | g | g | n | n | (a) | -// | g | h | l | l | (e) | -// | g | hd | f | f | (c) | -// | h | d | l | l | (e) | -// | h | g | b | b | (b) | -// | h | h | b | b | (b) | -// | h | hd | f | f | (c) | -// | hd | d | l | f | (d) | -// | hd | g | f | n |(d/a)| -// | hd | h | f | l | (d) | -// | hd | hd | b | b | (b) | +// | F | T | Ph | Pd | H | +// |----+----+-----+-----+-----+ +// | d | d | N | N | (c) | +// | d | g | -- | -- | (a) | +// | d | h | -- | -- | (e) | +// | d | hd | HD | HD | (b) | +// | g | d | N | N | (c) | +// | g | g | -- | -- | (a) | +// | g | h | -- | -- | (e) | +// | g | hd | HD | HD | (b) | +// | h | d | -- | -- | (e) | +// | h | g | N | N | (c) | +// | h | h | N | N | (c) | +// | h | hd | HD | HD | (b) | +// | hd | d | WS | SS | (d) | +// | hd | g | SS | -- |(d/a)| +// | hd | h | SS | WS | (d) | +// | hd | hd | HD | HD | (b) | Sema::CUDAFunctionPreference Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, const FunctionDecl *Callee) { - assert(getLangOpts().CUDATargetOverloads && - "Should not be called w/o enabled target overloads."); - assert(Callee && "Callee must be valid."); CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee); CUDAFunctionTarget CallerTarget = @@ -111,130 +111,62 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller, (CallerTarget == CFT_HostDevice && getLangOpts().CUDAIsDevice))) return CFP_Never; - // (b) Best case scenarios + // (b) Calling HostDevice is OK for everyone. + if (CalleeTarget == CFT_HostDevice) + return CFP_HostDevice; + + // (c) Best case scenarios if (CalleeTarget == CallerTarget || (CallerTarget == CFT_Host && CalleeTarget == CFT_Global) || (CallerTarget == CFT_Global && CalleeTarget == CFT_Device)) - return CFP_Best; - - // (c) Calling HostDevice is OK as a fallback that works for everyone. - if (CalleeTarget == CFT_HostDevice) - return CFP_Fallback; - - // Figure out what should be returned 'last resort' cases. Normally - // those would not be allowed, but we'll consider them if - // CUDADisableTargetCallChecks is true. - CUDAFunctionPreference QuestionableResult = - getLangOpts().CUDADisableTargetCallChecks ? CFP_LastResort : CFP_Never; + return CFP_Native; // (d) HostDevice behavior depends on compilation mode. if (CallerTarget == CFT_HostDevice) { - // Calling a function that matches compilation mode is OK. - // Calling a function from the other side is frowned upon. - if (getLangOpts().CUDAIsDevice) - return CalleeTarget == CFT_Device ? CFP_Fallback : QuestionableResult; - else - return (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global) - ? CFP_Fallback - : QuestionableResult; + // It's OK to call a compilation-mode matching function from an HD one. + if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) || + (!getLangOpts().CUDAIsDevice && + (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))) + return CFP_SameSide; + + // Calls from HD to non-mode-matching functions (i.e., to host functions + // when compiling in device mode or to device functions when compiling in + // host mode) are allowed at the sema level, but eventually rejected if + // they're ever codegened. TODO: Reject said calls earlier. + return CFP_WrongSide; } // (e) Calling across device/host boundary is not something you should do. if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) || (CallerTarget == CFT_Device && CalleeTarget == CFT_Host) || (CallerTarget == CFT_Global && CalleeTarget == CFT_Host)) - return QuestionableResult; + return CFP_Never; llvm_unreachable("All cases should've been handled by now."); } -bool Sema::CheckCUDATarget(const FunctionDecl *Caller, - const FunctionDecl *Callee) { - // With target overloads enabled, we only disallow calling - // combinations with CFP_Never. - if (getLangOpts().CUDATargetOverloads) - return IdentifyCUDAPreference(Caller,Callee) == CFP_Never; - - // The CUDADisableTargetCallChecks short-circuits this check: we assume all - // cross-target calls are valid. - if (getLangOpts().CUDADisableTargetCallChecks) - return false; - - CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller), - CalleeTarget = IdentifyCUDATarget(Callee); - - // If one of the targets is invalid, the check always fails, no matter what - // the other target is. - if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget) - return true; - - // CUDA B.1.1 "The __device__ qualifier declares a function that is [...] - // Callable from the device only." - if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device) - return true; - - // CUDA B.1.2 "The __global__ qualifier declares a function that is [...] - // Callable from the host only." - // CUDA B.1.3 "The __host__ qualifier declares a function that is [...] - // Callable from the host only." - if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) && - (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)) - return true; - - // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together - // however, in which case the function is compiled for both the host and the - // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code - // paths between host and device." - if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) { - // If the caller is implicit then the check always passes. - if (Caller->isImplicit()) return false; - - bool InDeviceMode = getLangOpts().CUDAIsDevice; - if (!InDeviceMode && CalleeTarget != CFT_Host) - return true; - if (InDeviceMode && CalleeTarget != CFT_Device) { - // Allow host device functions to call host functions if explicitly - // requested. - if (CalleeTarget == CFT_Host && - getLangOpts().CUDAAllowHostCallsFromHostDevice) { - Diag(Caller->getLocation(), - diag::warn_host_calls_from_host_device) - << Callee->getNameAsString() << Caller->getNameAsString(); - return false; - } - - return true; - } - } - - return false; -} - -template <typename T, typename FetchDeclFn> -static void EraseUnwantedCUDAMatchesImpl(Sema &S, const FunctionDecl *Caller, - llvm::SmallVectorImpl<T> &Matches, - FetchDeclFn FetchDecl) { - assert(S.getLangOpts().CUDATargetOverloads && - "Should not be called w/o enabled target overloads."); +template <typename T> +static void EraseUnwantedCUDAMatchesImpl( + Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches, + std::function<const FunctionDecl *(const T &)> FetchDecl) { if (Matches.size() <= 1) return; + // Gets the CUDA function preference for a call from Caller to Match. + auto GetCFP = [&](const T &Match) { + return S.IdentifyCUDAPreference(Caller, FetchDecl(Match)); + }; + // Find the best call preference among the functions in Matches. - Sema::CUDAFunctionPreference P, BestCFP = Sema::CFP_Never; - for (auto const &Match : Matches) { - P = S.IdentifyCUDAPreference(Caller, FetchDecl(Match)); - if (P > BestCFP) - BestCFP = P; - } + Sema::CUDAFunctionPreference BestCFP = GetCFP(*std::max_element( + Matches.begin(), Matches.end(), + [&](const T &M1, const T &M2) { return GetCFP(M1) < GetCFP(M2); })); // Erase all functions with lower priority. - for (unsigned I = 0, N = Matches.size(); I != N;) - if (S.IdentifyCUDAPreference(Caller, FetchDecl(Matches[I])) < BestCFP) { - Matches[I] = Matches[--N]; - Matches.resize(N); - } else { - ++I; - } + Matches.erase( + llvm::remove_if(Matches, + [&](const T &Match) { return GetCFP(Match) < BestCFP; }), + Matches.end()); } void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller, @@ -273,12 +205,9 @@ static bool resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1, Sema::CUDAFunctionTarget Target2, Sema::CUDAFunctionTarget *ResolvedTarget) { - if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) { - // TODO: this shouldn't happen, really. Methods cannot be marked __global__. - // Clang should detect this earlier and produce an error. Then this - // condition can be changed to an assertion. - return true; - } + // Only free functions and static member functions may be global. + assert(Target1 != Sema::CFT_Global); + assert(Target2 != Sema::CFT_Global); if (Target1 == Sema::CFT_HostDevice) { *ResolvedTarget = Target2; @@ -422,3 +351,132 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl, return false; } + +bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) { + if (!CD->isDefined() && CD->isTemplateInstantiation()) + InstantiateFunctionDefinition(Loc, CD->getFirstDecl()); + + // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered + // empty at a point in the translation unit, if it is either a + // trivial constructor + if (CD->isTrivial()) + return true; + + // ... or it satisfies all of the following conditions: + // The constructor function has been defined. + // The constructor function has no parameters, + // and the function body is an empty compound statement. + if (!(CD->hasTrivialBody() && CD->getNumParams() == 0)) + return false; + + // Its class has no virtual functions and no virtual base classes. + if (CD->getParent()->isDynamicClass()) + return false; + + // The only form of initializer allowed is an empty constructor. + // This will recursively check all base classes and member initializers + if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) { + if (const CXXConstructExpr *CE = + dyn_cast<CXXConstructExpr>(CI->getInit())) + return isEmptyCudaConstructor(Loc, CE->getConstructor()); + return false; + })) + return false; + + return true; +} + +bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) { + // No destructor -> no problem. + if (!DD) + return true; + + if (!DD->isDefined() && DD->isTemplateInstantiation()) + InstantiateFunctionDefinition(Loc, DD->getFirstDecl()); + + // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered + // empty at a point in the translation unit, if it is either a + // trivial constructor + if (DD->isTrivial()) + return true; + + // ... or it satisfies all of the following conditions: + // The destructor function has been defined. + // and the function body is an empty compound statement. + if (!DD->hasTrivialBody()) + return false; + + const CXXRecordDecl *ClassDecl = DD->getParent(); + + // Its class has no virtual functions and no virtual base classes. + if (ClassDecl->isDynamicClass()) + return false; + + // Only empty destructors are allowed. This will recursively check + // destructors for all base classes... + if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) { + if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl()) + return isEmptyCudaDestructor(Loc, RD->getDestructor()); + return true; + })) + return false; + + // ... and member fields. + if (!llvm::all_of(ClassDecl->fields(), [&](const FieldDecl *Field) { + if (CXXRecordDecl *RD = Field->getType() + ->getBaseElementTypeUnsafe() + ->getAsCXXRecordDecl()) + return isEmptyCudaDestructor(Loc, RD->getDestructor()); + return true; + })) + return false; + + return true; +} + +// With -fcuda-host-device-constexpr, an unattributed constexpr function is +// treated as implicitly __host__ __device__, unless: +// * it is a variadic function (device-side variadic functions are not +// allowed), or +// * 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, + const LookupResult &Previous) { + assert(getLangOpts().CUDA && "May be called only for CUDA compilations."); + if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() || + NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() || + NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>()) + return; + + // Is D a __device__ function with the same signature as NewD, ignoring CUDA + // attributes? + auto IsMatchingDeviceFn = [&](NamedDecl *D) { + if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D)) + D = Using->getTargetDecl(); + FunctionDecl *OldD = D->getAsFunction(); + return OldD && OldD->hasAttr<CUDADeviceAttr>() && + !OldD->hasAttr<CUDAHostAttr>() && + !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false, + /* ConsiderCudaAttrs = */ false); + }; + auto It = llvm::find_if(Previous, IsMatchingDeviceFn); + if (It != Previous.end()) { + // We found a __device__ function with the same name and signature as NewD + // (ignoring CUDA attrs). This is an error unless that function is defined + // in a system header, in which case we simply return without making NewD + // host+device. + NamedDecl *Match = *It; + if (!getSourceManager().isInSystemHeader(Match->getLocation())) { + Diag(NewD->getLocation(), + diag::err_cuda_unattributed_constexpr_cannot_overload_device) + << NewD->getName(); + Diag(Match->getLocation(), + diag::note_cuda_conflicting_device_function_declared_here); + } + return; + } + + NewD->addAttr(CUDAHostAttr::CreateImplicit(Context)); + NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context)); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp index f7aace625a92..ab0e709a97e7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp @@ -117,8 +117,18 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, // specializations, we're entering into the definition of that // class template partial specialization. if (ClassTemplatePartialSpecializationDecl *PartialSpec - = ClassTemplate->findPartialSpecialization(ContextType)) + = ClassTemplate->findPartialSpecialization(ContextType)) { + // A declaration of the partial specialization must be visible. + // We can always recover here, because this only happens when we're + // entering the context, and that can't happen in a SFINAE context. + assert(!isSFINAEContext() && + "partial specialization scope specifier in SFINAE context?"); + if (!hasVisibleDeclaration(PartialSpec)) + diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, + MissingImportKind::PartialSpecialization, + /*Recover*/true); return PartialSpec; + } } } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. @@ -195,6 +205,8 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, TagDecl *tag = dyn_cast<TagDecl>(DC); // If this is a dependent type, then we consider it complete. + // FIXME: This is wrong; we should require a (visible) definition to + // exist in this case too. if (!tag || tag->isDependentContext()) return false; @@ -218,10 +230,23 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS, // Fixed enum types are complete, but they aren't valid as scopes // until we see a definition, so awkwardly pull out this special // case. - // FIXME: The definition might not be visible; complain if it is not. const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType); - if (!enumType || enumType->getDecl()->isCompleteDefinition()) + if (!enumType) return false; + if (enumType->getDecl()->isCompleteDefinition()) { + // If we know about the definition but it is not visible, complain. + NamedDecl *SuggestedDef = nullptr; + if (!hasVisibleDefinition(enumType->getDecl(), &SuggestedDef, + /*OnlyNeedComplete*/false)) { + // If the user is going to see an error here, recover by making the + // definition visible. + bool TreatAsComplete = !isSFINAEContext(); + diagnoseMissingImport(loc, SuggestedDef, MissingImportKind::Definition, + /*Recover*/TreatAsComplete); + return !TreatAsComplete; + } + return false; + } // Try to instantiate the definition, if this is a specialization of an // enumeration temploid. @@ -606,6 +631,10 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) << Name); + if (Corrected.getCorrectionSpecifier()) + SS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), + SourceRange(Found.getNameLoc())); + if (NamedDecl *ND = Corrected.getFoundDecl()) Found.addDecl(ND); Found.setLookupName(Corrected.getCorrection()); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index ad1d7da4d070..e83dd0716780 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp @@ -22,6 +22,7 @@ #include "clang/AST/RecordLayout.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" +#include "clang/Lex/Preprocessor.h" #include "clang/Sema/Initialization.h" #include "llvm/ADT/SmallVector.h" #include <set> @@ -640,8 +641,8 @@ void CastOperation::CheckDynamicCast() { // If we're dynamic_casting from a prvalue to an rvalue reference, we need // to materialize the prvalue before we bind the reference to it. if (SrcExpr.get()->isRValue()) - SrcExpr = new (Self.Context) MaterializeTemporaryExpr( - SrcType, SrcExpr.get(), /*IsLValueReference*/false); + SrcExpr = Self.CreateMaterializeTemporaryExpr( + SrcType, SrcExpr.get(), /*IsLValueReference*/ false); SrcPointee = SrcType; } @@ -1313,16 +1314,13 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType, } std::string PathDisplayStr; std::set<unsigned> DisplayedPaths; - for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end(); - PI != PE; ++PI) { - if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) { + for (clang::CXXBasePath &Path : Paths) { + if (DisplayedPaths.insert(Path.back().SubobjectNumber).second) { // We haven't displayed a path to this particular base // class subobject yet. PathDisplayStr += "\n "; - for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(), - EE = PI->rend(); - EI != EE; ++EI) - PathDisplayStr += EI->Base->getType().getAsString() + " -> "; + for (CXXBasePathElement &PE : llvm::reverse(Path)) + PathDisplayStr += PE.Base->getType().getAsString() + " -> "; PathDisplayStr += QualType(DestType).getAsString(); } } @@ -1402,8 +1400,10 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType, // Lock down the inheritance model right now in MS ABI, whether or not the // pointee types are the same. - if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) + if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) { (void)Self.isCompleteType(OpRange.getBegin(), SrcType); + (void)Self.isCompleteType(OpRange.getBegin(), DestType); + } // T == T, modulo cv if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(), @@ -1646,8 +1646,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 = new (Self.Context) MaterializeTemporaryExpr( - SrcType, SrcExpr.get(), /*IsLValueReference*/ false); + SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(), + /*IsLValueReference*/ false); return TC_Success; } @@ -1724,6 +1724,97 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr, } } +/// Diagnose casts that change the calling convention of a pointer to a function +/// defined in the current TU. +static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr, + QualType DstType, SourceRange OpRange) { + // Check if this cast would change the calling convention of a function + // pointer type. + QualType SrcType = SrcExpr.get()->getType(); + if (Self.Context.hasSameType(SrcType, DstType) || + !SrcType->isFunctionPointerType() || !DstType->isFunctionPointerType()) + return; + const auto *SrcFTy = + SrcType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>(); + const auto *DstFTy = + DstType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>(); + CallingConv SrcCC = SrcFTy->getCallConv(); + CallingConv DstCC = DstFTy->getCallConv(); + if (SrcCC == DstCC) + return; + + // We have a calling convention cast. Check if the source is a pointer to a + // known, specific function that has already been defined. + Expr *Src = SrcExpr.get()->IgnoreParenImpCasts(); + if (auto *UO = dyn_cast<UnaryOperator>(Src)) + if (UO->getOpcode() == UO_AddrOf) + Src = UO->getSubExpr()->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(Src); + if (!DRE) + return; + auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl()); + const FunctionDecl *Definition; + if (!FD || !FD->hasBody(Definition)) + return; + + // Only warn if we are casting from the default convention to a non-default + // convention. This can happen when the programmer forgot to apply the calling + // convention to the function definition and then inserted this cast to + // satisfy the type system. + CallingConv DefaultCC = Self.getASTContext().getDefaultCallingConvention( + FD->isVariadic(), FD->isCXXInstanceMember()); + if (DstCC == DefaultCC || SrcCC != DefaultCC) + return; + + // Diagnose this cast, as it is probably bad. + StringRef SrcCCName = FunctionType::getNameForCallConv(SrcCC); + StringRef DstCCName = FunctionType::getNameForCallConv(DstCC); + Self.Diag(OpRange.getBegin(), diag::warn_cast_calling_conv) + << SrcCCName << DstCCName << OpRange; + + // The checks above are cheaper than checking if the diagnostic is enabled. + // However, it's worth checking if the warning is enabled before we construct + // a fixit. + if (Self.Diags.isIgnored(diag::warn_cast_calling_conv, OpRange.getBegin())) + return; + + // Try to suggest a fixit to change the calling convention of the function + // whose address was taken. Try to use the latest macro for the convention. + // For example, users probably want to write "WINAPI" instead of "__stdcall" + // to match the Windows header declarations. + SourceLocation NameLoc = Definition->getNameInfo().getLoc(); + Preprocessor &PP = Self.getPreprocessor(); + SmallVector<TokenValue, 6> AttrTokens; + SmallString<64> CCAttrText; + llvm::raw_svector_ostream OS(CCAttrText); + if (Self.getLangOpts().MicrosoftExt) { + // __stdcall or __vectorcall + OS << "__" << DstCCName; + IdentifierInfo *II = PP.getIdentifierInfo(OS.str()); + AttrTokens.push_back(II->isKeyword(Self.getLangOpts()) + ? TokenValue(II->getTokenID()) + : TokenValue(II)); + } else { + // __attribute__((stdcall)) or __attribute__((vectorcall)) + OS << "__attribute__((" << DstCCName << "))"; + AttrTokens.push_back(tok::kw___attribute); + AttrTokens.push_back(tok::l_paren); + AttrTokens.push_back(tok::l_paren); + IdentifierInfo *II = PP.getIdentifierInfo(DstCCName); + AttrTokens.push_back(II->isKeyword(Self.getLangOpts()) + ? TokenValue(II->getTokenID()) + : TokenValue(II)); + AttrTokens.push_back(tok::r_paren); + AttrTokens.push_back(tok::r_paren); + } + StringRef AttrSpelling = PP.getLastMacroWithSpelling(NameLoc, AttrTokens); + if (!AttrSpelling.empty()) + CCAttrText = AttrSpelling; + OS << ' '; + Self.Diag(NameLoc, diag::note_change_calling_conv_fixit) + << FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText); +} + static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, const Expr *SrcExpr, QualType DestType, Sema &Self) { @@ -1750,6 +1841,32 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc, } } +static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType, + ExprResult &Result) { + // We can only fix an overloaded reinterpret_cast if + // - it is a template with explicit arguments that resolves to an lvalue + // unambiguously, or + // - it is the only function in an overload set that may have its address + // taken. + + Expr *E = Result.get(); + // TODO: what if this fails because of DiagnoseUseOfDecl or something + // like it? + if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( + Result, + Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr + ) && + Result.isUsable()) + return true; + + // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization + // preserves Result. + Result = E; + if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result)) + return false; + return Result.isUsable(); +} + static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType DestType, bool CStyle, SourceRange OpRange, @@ -1761,21 +1878,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, QualType SrcType = SrcExpr.get()->getType(); // Is the source an overloaded name? (i.e. &foo) - // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ... + // If so, reinterpret_cast generally can not help us here (13.4, p1, bullet 5) if (SrcType == Self.Context.OverloadTy) { - // ... unless foo<int> resolves to an lvalue unambiguously. - // TODO: what if this fails because of DiagnoseUseOfDecl or something - // like it? - ExprResult SingleFunctionExpr = SrcExpr; - if (Self.ResolveAndFixSingleFunctionTemplateSpecialization( - SingleFunctionExpr, - Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr - ) && SingleFunctionExpr.isUsable()) { - SrcExpr = SingleFunctionExpr; - SrcType = SrcExpr.get()->getType(); - } else { + ExprResult FixedExpr = SrcExpr; + if (!fixOverloadedReinterpretCastExpr(Self, DestType, FixedExpr)) return TC_NotApplicable; - } + + assert(FixedExpr.isUsable() && "Invalid result fixing overloaded expr"); + SrcExpr = FixedExpr; + SrcType = SrcExpr.get()->getType(); } if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) { @@ -2008,7 +2119,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr, } if (CStyle) DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); - + + DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange); + // Not casting away constness, so the only remaining check is for compatible // pointer categories. @@ -2313,6 +2426,22 @@ void CastOperation::CheckCStyleCast() { return; } + // OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type. + if (Self.getLangOpts().OpenCL && DestType->isEventT()) { + llvm::APSInt CastInt; + if (SrcExpr.get()->EvaluateAsInt(CastInt, Self.Context)) { + if (0 == CastInt) { + Kind = CK_ZeroToOCLEvent; + return; + } + Self.Diag(OpRange.getBegin(), + diag::error_opencl_cast_non_zero_to_event_t) + << CastInt.toString(10) << SrcExpr.get()->getSourceRange(); + SrcExpr = ExprError(); + return; + } + } + // Reject any other conversions to non-scalar types. Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar) << DestType << SrcExpr.get()->getSourceRange(); @@ -2427,6 +2556,7 @@ void CastOperation::CheckCStyleCast() { } DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType); + DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange); DiagnoseBadFunctionCast(Self, SrcExpr, DestType); Kind = Self.PrepareScalarCast(SrcExpr, DestType); if (SrcExpr.isInvalid()) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp index 6c2834b750ae..0c25e01787c1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp @@ -36,9 +36,12 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.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; @@ -258,6 +261,459 @@ static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall, return false; } +static inline bool isBlockPointer(Expr *Arg) { + return Arg->getType()->isBlockPointerType(); +} + +/// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local +/// void*, which is a requirement of device side enqueue. +static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) { + const BlockPointerType *BPT = + cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); + ArrayRef<QualType> Params = + BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes(); + unsigned ArgCounter = 0; + bool IllegalParams = false; + // Iterate through the block parameters until either one is found that is not + // a local void*, or the block is valid. + for (ArrayRef<QualType>::iterator I = Params.begin(), E = Params.end(); + I != E; ++I, ++ArgCounter) { + if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() || + (*I)->getPointeeType().getQualifiers().getAddressSpace() != + LangAS::opencl_local) { + // Get the location of the error. If a block literal has been passed + // (BlockExpr) then we can point straight to the offending argument, + // else we just point to the variable reference. + SourceLocation ErrorLoc; + if (isa<BlockExpr>(BlockArg)) { + BlockDecl *BD = cast<BlockExpr>(BlockArg)->getBlockDecl(); + ErrorLoc = BD->getParamDecl(ArgCounter)->getLocStart(); + } else if (isa<DeclRefExpr>(BlockArg)) { + ErrorLoc = cast<DeclRefExpr>(BlockArg)->getLocStart(); + } + S.Diag(ErrorLoc, + diag::err_opencl_enqueue_kernel_blocks_non_local_void_args); + IllegalParams = true; + } + } + + return IllegalParams; +} + +/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the +/// get_kernel_work_group_size +/// and get_kernel_preferred_work_group_size_multiple builtin functions. +static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) { + if (checkArgCount(S, TheCall, 1)) + return true; + + Expr *BlockArg = TheCall->getArg(0); + if (!isBlockPointer(BlockArg)) { + S.Diag(BlockArg->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) << "block"; + return true; + } + return checkOpenCLBlockArgs(S, BlockArg); +} + +static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall, + unsigned Start, unsigned End); + +/// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all +/// 'local void*' parameter of passed block. +static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall, + Expr *BlockArg, + unsigned NumNonVarArgs) { + const BlockPointerType *BPT = + cast<BlockPointerType>(BlockArg->getType().getCanonicalType()); + unsigned NumBlockParams = + BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams(); + unsigned TotalNumArgs = TheCall->getNumArgs(); + + // For each argument passed to the block, a corresponding uint needs to + // be passed to describe the size of the local memory. + if (TotalNumArgs != NumBlockParams + NumNonVarArgs) { + S.Diag(TheCall->getLocStart(), + diag::err_opencl_enqueue_kernel_local_size_args); + return true; + } + + // Check that the sizes of the local memory are specified by integers. + return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs, + TotalNumArgs - 1); +} + +/// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different +/// overload formats specified in Table 6.13.17.1. +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// void (^block)(void)) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// uint num_events_in_wait_list, +/// clk_event_t *event_wait_list, +/// clk_event_t *event_ret, +/// void (^block)(void)) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// void (^block)(local void*, ...), +/// uint size0, ...) +/// int enqueue_kernel(queue_t queue, +/// kernel_enqueue_flags_t flags, +/// const ndrange_t ndrange, +/// uint num_events_in_wait_list, +/// clk_event_t *event_wait_list, +/// clk_event_t *event_ret, +/// void (^block)(local void*, ...), +/// uint size0, ...) +static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) { + unsigned NumArgs = TheCall->getNumArgs(); + + if (NumArgs < 4) { + S.Diag(TheCall->getLocStart(), diag::err_typecheck_call_too_few_args); + return true; + } + + Expr *Arg0 = TheCall->getArg(0); + Expr *Arg1 = TheCall->getArg(1); + Expr *Arg2 = TheCall->getArg(2); + Expr *Arg3 = TheCall->getArg(3); + + // First argument always needs to be a queue_t type. + if (!Arg0->getType()->isQueueT()) { + S.Diag(TheCall->getArg(0)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.OCLQueueTy; + return true; + } + + // Second argument always needs to be a kernel_enqueue_flags_t enum value. + if (!Arg1->getType()->isIntegerType()) { + S.Diag(TheCall->getArg(1)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << "'kernel_enqueue_flags_t' (i.e. uint)"; + return true; + } + + // Third argument is always an ndrange_t type. + if (!Arg2->getType()->isNDRangeT()) { + S.Diag(TheCall->getArg(2)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.OCLNDRangeTy; + return true; + } + + // With four arguments, there is only one form that the function could be + // called in: no events and no variable arguments. + if (NumArgs == 4) { + // check that the last argument is the right block type. + if (!isBlockPointer(Arg3)) { + S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) + << "block"; + return true; + } + // we have a block type, check the prototype + const BlockPointerType *BPT = + cast<BlockPointerType>(Arg3->getType().getCanonicalType()); + if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) { + S.Diag(Arg3->getLocStart(), + diag::err_opencl_enqueue_kernel_blocks_no_args); + return true; + } + return false; + } + // we can have block + varargs. + if (isBlockPointer(Arg3)) + return (checkOpenCLBlockArgs(S, Arg3) || + checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg3, 4)); + // last two cases with either exactly 7 args or 7 args and varargs. + if (NumArgs >= 7) { + // check common block argument. + Expr *Arg6 = TheCall->getArg(6); + if (!isBlockPointer(Arg6)) { + S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type) + << "block"; + return true; + } + if (checkOpenCLBlockArgs(S, Arg6)) + return true; + + // Forth argument has to be any integer type. + if (!Arg3->getType()->isIntegerType()) { + S.Diag(TheCall->getArg(3)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << "integer"; + return true; + } + // check remaining common arguments. + 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()) { + 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() && + Arg5->getType()->getPointeeType()->isClkEventT())) { + S.Diag(TheCall->getArg(5)->getLocStart(), + diag::err_opencl_enqueue_kernel_expected_type) + << S.Context.getPointerType(S.Context.OCLClkEventTy); + return true; + } + + if (NumArgs == 7) + return false; + + return checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg6, 7); + } + + // None of the specific case has been detected, give generic error + S.Diag(TheCall->getLocStart(), + diag::err_opencl_enqueue_kernel_incorrect_args); + return true; +} + +/// Returns OpenCL access qual. +static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) { + return D->getAttr<OpenCLAccessAttr>(); +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) { + const Expr *Arg0 = Call->getArg(0); + // First argument type should always be pipe. + if (!Arg0->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Arg0->getSourceRange(); + return true; + } + OpenCLAccessAttr *AccessQual = + getOpenCLArgAccess(cast<DeclRefExpr>(Arg0)->getDecl()); + // Validates the access qualifier is compatible with the call. + // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be + // read_only and write_only, and assumed to be read_only if no qualifier is + // specified. + switch (Call->getDirectCallee()->getBuiltinID()) { + case Builtin::BIread_pipe: + case Builtin::BIreserve_read_pipe: + case Builtin::BIcommit_read_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIsub_group_commit_read_pipe: + if (!(!AccessQual || AccessQual->isReadOnly())) { + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "read_only" << Arg0->getSourceRange(); + return true; + } + break; + case Builtin::BIwrite_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (!(AccessQual && AccessQual->isWriteOnly())) { + S.Diag(Arg0->getLocStart(), + diag::err_opencl_builtin_pipe_invalid_access_modifier) + << "write_only" << Arg0->getSourceRange(); + return true; + } + break; + default: + break; + } + return false; +} + +/// Returns true if pipe element type is different from the pointer. +static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) { + const Expr *Arg0 = Call->getArg(0); + const Expr *ArgIdx = Call->getArg(Idx); + const PipeType *PipeTy = cast<PipeType>(Arg0->getType()); + const QualType EltTy = PipeTy->getElementType(); + const PointerType *ArgTy = ArgIdx->getType()->getAs<PointerType>(); + // The Idx argument should be a pointer and the type of the pointer and + // the type of pipe element should also be the same. + if (!ArgTy || + !S.Context.hasSameType( + EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.getPointerType(EltTy) + << ArgIdx->getType() << ArgIdx->getSourceRange(); + return true; + } + return false; +} + +// \brief Performs semantic analysis for the read/write_pipe call. +// \param S Reference to the semantic analyzer. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) { + // OpenCL v2.0 s6.13.16.2 - The built-in read/write + // functions have two forms. + switch (Call->getNumArgs()) { + case 2: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 2 arguments should be + // read/write_pipe(pipe T, T*). + // Check packet type T. + if (checkOpenCLPipePacketType(S, Call, 1)) + return true; + } break; + + case 4: { + if (checkOpenCLPipeArg(S, Call)) + return true; + // The call with 4 arguments should be + // read/write_pipe(pipe T, reserve_id_t, uint, T*). + // Check reserve_id_t. + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.OCLReserveIDTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + // Check the index. + const Expr *Arg2 = Call->getArg(2); + if (!Arg2->getType()->isIntegerType() && + !Arg2->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.UnsignedIntTy + << Arg2->getType() << Arg2->getSourceRange(); + return true; + } + + // Check packet type T. + if (checkOpenCLPipePacketType(S, Call, 3)) + return true; + } break; + default: + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the {work_group_/sub_group_ +// /_}reserve_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // Check the reserve size. + if (!Call->getArg(1)->getType()->isIntegerType() && + !Call->getArg(1)->getType()->isUnsignedIntegerType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.UnsignedIntTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on {work_group_/sub_group_ +// /_}commit_{read/write}_pipe +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 2)) + return true; + + if (checkOpenCLPipeArg(S, Call)) + return true; + + // Check reserve_id_t. + if (!Call->getArg(1)->getType()->isReserveIDT()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg) + << Call->getDirectCallee() << S.Context.OCLReserveIDTy + << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange(); + return true; + } + + return false; +} + +// \brief Performs a semantic analysis on the call to built-in Pipe +// Query Functions. +// \param S Reference to the semantic analyzer. +// \param Call The call to the builtin function to be analyzed. +// \return True if a semantic error was found, false otherwise. +static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) { + if (checkArgCount(S, Call, 1)) + return true; + + if (!Call->getArg(0)->getType()->isPipeType()) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg) + << Call->getDirectCallee() << Call->getArg(0)->getSourceRange(); + return true; + } + + return false; +} +// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions. +// \brief Performs semantic analysis for the to_global/local/private call. +// \param S Reference to the semantic analyzer. +// \param BuiltinID ID of the builtin function. +// \param Call A pointer to the builtin call. +// \return True if a semantic error has been found, false otherwise. +static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID, + CallExpr *Call) { + if (Call->getNumArgs() != 1) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num) + << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + auto RT = Call->getArg(0)->getType(); + if (!RT->isPointerType() || RT->getPointeeType() + .getAddressSpace() == LangAS::opencl_constant) { + S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg) + << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange(); + return true; + } + + RT = RT->getPointeeType(); + auto Qual = RT.getQualifiers(); + switch (BuiltinID) { + case Builtin::BIto_global: + Qual.setAddressSpace(LangAS::opencl_global); + break; + case Builtin::BIto_local: + Qual.setAddressSpace(LangAS::opencl_local); + break; + default: + Qual.removeAddressSpace(); + } + Call->setType(S.Context.getPointerType(S.Context.getQualifiedType( + RT.getUnqualifiedType(), Qual))); + + return false; +} + ExprResult Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, CallExpr *TheCall) { @@ -530,27 +986,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, case Builtin::BI__builtin___vsnprintf_chk: SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3); break; - case Builtin::BI__builtin_call_with_static_chain: if (SemaBuiltinCallWithStaticChain(*this, TheCall)) return ExprError(); break; - case Builtin::BI__exception_code: - case Builtin::BI_exception_code: { + case Builtin::BI_exception_code: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope, diag::err_seh___except_block)) return ExprError(); break; - } case Builtin::BI__exception_info: - case Builtin::BI_exception_info: { + case Builtin::BI_exception_info: if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope, diag::err_seh___except_filter)) return ExprError(); break; - } - case Builtin::BI__GetExceptionInfo: if (checkArgCount(*this, TheCall, 1)) return ExprError(); @@ -563,7 +1014,56 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID, TheCall->setType(Context.VoidPtrTy); break; - + // OpenCL v2.0, s6.13.16 - Pipe functions + case Builtin::BIread_pipe: + case Builtin::BIwrite_pipe: + // Since those two functions are declared with var args, we need a semantic + // check for the argument. + if (SemaBuiltinRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIreserve_read_pipe: + case Builtin::BIreserve_write_pipe: + case Builtin::BIwork_group_reserve_read_pipe: + case Builtin::BIwork_group_reserve_write_pipe: + case Builtin::BIsub_group_reserve_read_pipe: + case Builtin::BIsub_group_reserve_write_pipe: + if (SemaBuiltinReserveRWPipe(*this, TheCall)) + return ExprError(); + // Since return type of reserve_read/write_pipe built-in function is + // reserve_id_t, which is not defined in the builtin def file , we used int + // as return type and need to override the return type of these functions. + TheCall->setType(Context.OCLReserveIDTy); + break; + case Builtin::BIcommit_read_pipe: + case Builtin::BIcommit_write_pipe: + case Builtin::BIwork_group_commit_read_pipe: + case Builtin::BIwork_group_commit_write_pipe: + case Builtin::BIsub_group_commit_read_pipe: + case Builtin::BIsub_group_commit_write_pipe: + if (SemaBuiltinCommitRWPipe(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_pipe_num_packets: + case Builtin::BIget_pipe_max_packets: + if (SemaBuiltinPipePackets(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIto_global: + case Builtin::BIto_local: + case Builtin::BIto_private: + if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall)) + return ExprError(); + break; + // OpenCL v2.0, s6.13.17 - Enqueue kernel functions. + case Builtin::BIenqueue_kernel: + if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall)) + return ExprError(); + break; + case Builtin::BIget_kernel_work_group_size: + case Builtin::BIget_kernel_preferred_work_group_size_multiple: + if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall)) + return ExprError(); } // Since the target specific builtins for each arch overlap, only check those @@ -843,7 +1343,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall, return true; } - if (IsLdrex) { TheCall->setType(ValType); return false; @@ -931,7 +1430,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, if (BuiltinID == AArch64::BI__builtin_arm_rsr64 || BuiltinID == AArch64::BI__builtin_arm_wsr64) - return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, false); + return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true); if (BuiltinID == AArch64::BI__builtin_arm_rsr || BuiltinID == AArch64::BI__builtin_arm_rsrp || @@ -1091,19 +1590,58 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) { } bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; + int i = 0, l = 0, u = 0; switch (BuiltinID) { - default: return false; + default: + return false; case X86::BI__builtin_cpu_supports: return SemaBuiltinCpuSupports(*this, TheCall); case X86::BI__builtin_ms_va_start: return SemaBuiltinMSVAStart(TheCall); - case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break; - case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break; + 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; + 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: case X86::BI__builtin_ia32_vpermil2pd256: case X86::BI__builtin_ia32_vpermil2ps: - case X86::BI__builtin_ia32_vpermil2ps256: i = 3, l = 0; u = 3; break; + case X86::BI__builtin_ia32_vpermil2ps256: + i = 3; l = 0; u = 3; + break; case X86::BI__builtin_ia32_cmpb128_mask: case X86::BI__builtin_ia32_cmpw128_mask: case X86::BI__builtin_ia32_cmpd128_mask: @@ -1127,29 +1665,205 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case X86::BI__builtin_ia32_ucmpb512_mask: case X86::BI__builtin_ia32_ucmpw512_mask: case X86::BI__builtin_ia32_ucmpd512_mask: - case X86::BI__builtin_ia32_ucmpq512_mask: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_ucmpq512_mask: + case X86::BI__builtin_ia32_vpcomub: + case X86::BI__builtin_ia32_vpcomuw: + case X86::BI__builtin_ia32_vpcomud: + case X86::BI__builtin_ia32_vpcomuq: + case X86::BI__builtin_ia32_vpcomb: + case X86::BI__builtin_ia32_vpcomw: + case X86::BI__builtin_ia32_vpcomd: + case X86::BI__builtin_ia32_vpcomq: + i = 2; l = 0; u = 7; + break; case X86::BI__builtin_ia32_roundps: case X86::BI__builtin_ia32_roundpd: case X86::BI__builtin_ia32_roundps256: - case X86::BI__builtin_ia32_roundpd256: i = 1, l = 0; u = 15; break; + case X86::BI__builtin_ia32_roundpd256: + i = 1; l = 0; u = 15; + break; case X86::BI__builtin_ia32_roundss: - case X86::BI__builtin_ia32_roundsd: i = 2, l = 0; u = 15; break; + case X86::BI__builtin_ia32_roundsd: + case X86::BI__builtin_ia32_rangepd128_mask: + case X86::BI__builtin_ia32_rangepd256_mask: + case X86::BI__builtin_ia32_rangepd512_mask: + case X86::BI__builtin_ia32_rangeps128_mask: + case X86::BI__builtin_ia32_rangeps256_mask: + case X86::BI__builtin_ia32_rangeps512_mask: + case X86::BI__builtin_ia32_getmantsd_round_mask: + case X86::BI__builtin_ia32_getmantss_round_mask: + i = 2; l = 0; u = 15; + break; case X86::BI__builtin_ia32_cmpps: case X86::BI__builtin_ia32_cmpss: case X86::BI__builtin_ia32_cmppd: case X86::BI__builtin_ia32_cmpsd: case X86::BI__builtin_ia32_cmpps256: case X86::BI__builtin_ia32_cmppd256: + case X86::BI__builtin_ia32_cmpps128_mask: + case X86::BI__builtin_ia32_cmppd128_mask: + case X86::BI__builtin_ia32_cmpps256_mask: + case X86::BI__builtin_ia32_cmppd256_mask: case X86::BI__builtin_ia32_cmpps512_mask: - case X86::BI__builtin_ia32_cmppd512_mask: i = 2; l = 0; u = 31; break; - case X86::BI__builtin_ia32_vpcomub: - case X86::BI__builtin_ia32_vpcomuw: - case X86::BI__builtin_ia32_vpcomud: - case X86::BI__builtin_ia32_vpcomuq: - case X86::BI__builtin_ia32_vpcomb: - case X86::BI__builtin_ia32_vpcomw: - case X86::BI__builtin_ia32_vpcomd: - case X86::BI__builtin_ia32_vpcomq: i = 2; l = 0; u = 7; break; + case X86::BI__builtin_ia32_cmppd512_mask: + case X86::BI__builtin_ia32_cmpsd_mask: + case X86::BI__builtin_ia32_cmpss_mask: + i = 2; l = 0; u = 31; + break; + case X86::BI__builtin_ia32_xabort: + i = 0; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_pshufw: + case X86::BI__builtin_ia32_aeskeygenassist128: + i = 1; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_vcvtps2ph: + case X86::BI__builtin_ia32_vcvtps2ph256: + case X86::BI__builtin_ia32_rndscaleps_128_mask: + case X86::BI__builtin_ia32_rndscalepd_128_mask: + case X86::BI__builtin_ia32_rndscaleps_256_mask: + case X86::BI__builtin_ia32_rndscalepd_256_mask: + case X86::BI__builtin_ia32_rndscaleps_mask: + case X86::BI__builtin_ia32_rndscalepd_mask: + case X86::BI__builtin_ia32_reducepd128_mask: + case X86::BI__builtin_ia32_reducepd256_mask: + case X86::BI__builtin_ia32_reducepd512_mask: + case X86::BI__builtin_ia32_reduceps128_mask: + case X86::BI__builtin_ia32_reduceps256_mask: + case X86::BI__builtin_ia32_reduceps512_mask: + case X86::BI__builtin_ia32_prold512_mask: + case X86::BI__builtin_ia32_prolq512_mask: + case X86::BI__builtin_ia32_prold128_mask: + case X86::BI__builtin_ia32_prold256_mask: + case X86::BI__builtin_ia32_prolq128_mask: + case X86::BI__builtin_ia32_prolq256_mask: + case X86::BI__builtin_ia32_prord128_mask: + 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: + case X86::BI__builtin_ia32_fpclassps256_mask: + case X86::BI__builtin_ia32_fpclassps512_mask: + case X86::BI__builtin_ia32_fpclasspd512_mask: + case X86::BI__builtin_ia32_fpclasssd_mask: + case X86::BI__builtin_ia32_fpclassss_mask: + i = 1; l = 0; u = 255; + break; + case X86::BI__builtin_ia32_palignr: + case X86::BI__builtin_ia32_insertps128: + case X86::BI__builtin_ia32_dpps: + case X86::BI__builtin_ia32_dppd: + case X86::BI__builtin_ia32_dpps256: + case X86::BI__builtin_ia32_mpsadbw128: + case X86::BI__builtin_ia32_mpsadbw256: + case X86::BI__builtin_ia32_pcmpistrm128: + case X86::BI__builtin_ia32_pcmpistri128: + case X86::BI__builtin_ia32_pcmpistria128: + case X86::BI__builtin_ia32_pcmpistric128: + case X86::BI__builtin_ia32_pcmpistrio128: + case X86::BI__builtin_ia32_pcmpistris128: + case X86::BI__builtin_ia32_pcmpistriz128: + case X86::BI__builtin_ia32_pclmulqdq128: + case X86::BI__builtin_ia32_vperm2f128_pd256: + case X86::BI__builtin_ia32_vperm2f128_ps256: + case X86::BI__builtin_ia32_vperm2f128_si256: + case X86::BI__builtin_ia32_permti256: + i = 2; l = -128; u = 255; + 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: + case X86::BI__builtin_ia32_shuf_f64x2_mask: + case X86::BI__builtin_ia32_shuf_i32x4_mask: + case X86::BI__builtin_ia32_shuf_i64x2_mask: + case X86::BI__builtin_ia32_dbpsadbw128_mask: + case X86::BI__builtin_ia32_dbpsadbw256_mask: + case X86::BI__builtin_ia32_dbpsadbw512_mask: + i = 2; l = 0; u = 255; + 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_fixupimmpd128_mask: + case X86::BI__builtin_ia32_fixupimmpd128_maskz: + case X86::BI__builtin_ia32_fixupimmpd256_mask: + case X86::BI__builtin_ia32_fixupimmpd256_maskz: + case X86::BI__builtin_ia32_fixupimmps128_mask: + case X86::BI__builtin_ia32_fixupimmps128_maskz: + case X86::BI__builtin_ia32_fixupimmps256_mask: + case X86::BI__builtin_ia32_fixupimmps256_maskz: + case X86::BI__builtin_ia32_pternlogd512_mask: + case X86::BI__builtin_ia32_pternlogd512_maskz: + case X86::BI__builtin_ia32_pternlogq512_mask: + case X86::BI__builtin_ia32_pternlogq512_maskz: + case X86::BI__builtin_ia32_pternlogd128_mask: + case X86::BI__builtin_ia32_pternlogd128_maskz: + case X86::BI__builtin_ia32_pternlogd256_mask: + case X86::BI__builtin_ia32_pternlogd256_maskz: + case X86::BI__builtin_ia32_pternlogq128_mask: + case X86::BI__builtin_ia32_pternlogq128_maskz: + case X86::BI__builtin_ia32_pternlogq256_mask: + case X86::BI__builtin_ia32_pternlogq256_maskz: + i = 3; l = 0; u = 255; + break; + case X86::BI__builtin_ia32_pcmpestrm128: + case X86::BI__builtin_ia32_pcmpestri128: + case X86::BI__builtin_ia32_pcmpestria128: + case X86::BI__builtin_ia32_pcmpestric128: + case X86::BI__builtin_ia32_pcmpestrio128: + case X86::BI__builtin_ia32_pcmpestris128: + case X86::BI__builtin_ia32_pcmpestriz128: + i = 4; l = -128; u = 255; + break; + case X86::BI__builtin_ia32_rndscalesd_round_mask: + case X86::BI__builtin_ia32_rndscaless_round_mask: + i = 4; l = 0; u = 255; + break; } return SemaBuiltinConstantArgRange(TheCall, i, l, u); } @@ -1534,10 +2248,10 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) { } static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { - if (Ordering < AtomicExpr::AO_ABI_memory_order_relaxed || - Ordering > AtomicExpr::AO_ABI_memory_order_seq_cst) + if (!llvm::isValidAtomicOrderingCABI(Ordering)) return false; + auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering; switch (Op) { case AtomicExpr::AO__c11_atomic_init: llvm_unreachable("There is no ordering argument for an init"); @@ -1545,15 +2259,15 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) { case AtomicExpr::AO__c11_atomic_load: case AtomicExpr::AO__atomic_load_n: case AtomicExpr::AO__atomic_load: - return Ordering != AtomicExpr::AO_ABI_memory_order_release && - Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel; + return OrderingCABI != llvm::AtomicOrderingCABI::release && + OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: - return Ordering != AtomicExpr::AO_ABI_memory_order_consume && - Ordering != AtomicExpr::AO_ABI_memory_order_acquire && - Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel; + return OrderingCABI != llvm::AtomicOrderingCABI::consume && + OrderingCABI != llvm::AtomicOrderingCABI::acquire && + OrderingCABI != llvm::AtomicOrderingCABI::acq_rel; default: return true; @@ -1572,6 +2286,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // C __c11_atomic_load(A *, int) Load, // void __atomic_load(A *, CP, int) + LoadCopy, + // void __atomic_store(A *, CP, int) Copy, // C __c11_atomic_add(A *, M, int) Arithmetic, @@ -1584,8 +2300,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // bool __atomic_compare_exchange(A *, C *, CP, bool, int, int) GNUCmpXchg } Form = Init; - const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 4, 5, 6 }; - const unsigned NumVals[] = { 1, 0, 1, 1, 1, 2, 2, 3 }; + const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 }; + const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 }; // where: // C is an appropriate type, // A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins, @@ -1615,8 +2331,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, Form = Load; break; - case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_load: + Form = LoadCopy; + break; + + case AtomicExpr::AO__c11_atomic_store: case AtomicExpr::AO__atomic_store: case AtomicExpr::AO__atomic_store_n: Form = Copy; @@ -1680,7 +2399,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // Inspect the first argument of the atomic operation. Expr *Ptr = TheCall->getArg(0); - Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get(); + ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr); + if (ConvertedPtr.isInvalid()) + return ExprError(); + + Ptr = ConvertedPtr.get(); const PointerType *pointerType = Ptr->getType()->getAs<PointerType>(); if (!pointerType) { Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer) @@ -1703,7 +2426,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return ExprError(); } ValType = AtomTy->getAs<AtomicType>()->getValueType(); - } else if (Form != Load && Op != AtomicExpr::AO__atomic_load) { + } else if (Form != Load && Form != LoadCopy) { if (ValType.isConstQualified()) { Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer) << Ptr->getType() << Ptr->getSourceRange(); @@ -1764,10 +2487,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, // atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the // volatile-ness of the pointee-type inject itself into the result or the - // other operands. + // other operands. Similarly atomic_load can take a pointer to a const 'A'. ValType.removeLocalVolatile(); + ValType.removeLocalConst(); QualType ResultType = ValType; - if (Form == Copy || Form == GNUXchg || Form == Init) + if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init) ResultType = Context.VoidTy; else if (Form == C11CmpXchg || Form == GNUCmpXchg) ResultType = Context.BoolTy; @@ -1778,10 +2502,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, if (!IsC11 && !IsN) ByValType = Ptr->getType(); - // FIXME: __atomic_load allows the first argument to be a a pointer to const - // but not the second argument. We need to manually remove possible const - // qualifiers. - // The first argument --- the pointer --- has a fixed type; we // deduce the types of the rest of the arguments accordingly. Walk // the remaining arguments, converting them to the deduced value type. @@ -1848,6 +2568,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, case Load: SubExprs.push_back(TheCall->getArg(1)); // Order break; + case LoadCopy: case Copy: case Arithmetic: case Xchg: @@ -1897,7 +2618,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult, return AE; } - /// checkBuiltinArgument - Given a call to a builtin function, perform /// normal type-checking on the given argument, updating the call in /// place. This is useful when a builtin function requires custom @@ -2443,6 +3163,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { // block. QualType Type; SourceLocation ParamLoc; + bool IsCRegister = false; if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) { if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) { @@ -2450,24 +3171,30 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) { // Get the last formal in the current function. const ParmVarDecl *LastArg; if (CurBlock) - LastArg = *(CurBlock->TheDecl->param_end()-1); + LastArg = CurBlock->TheDecl->parameters().back(); else if (FunctionDecl *FD = getCurFunctionDecl()) - LastArg = *(FD->param_end()-1); + LastArg = FD->parameters().back(); else - LastArg = *(getCurMethodDecl()->param_end()-1); + LastArg = getCurMethodDecl()->parameters().back(); SecondArgIsLastNamedArgument = PV == LastArg; Type = PV->getType(); ParamLoc = PV->getLocation(); + IsCRegister = + PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus; } } if (!SecondArgIsLastNamedArgument) Diag(TheCall->getArg(1)->getLocStart(), - diag::warn_second_parameter_of_va_start_not_last_named_argument); - else if (Type->isReferenceType()) { - Diag(Arg->getLocStart(), - diag::warn_va_start_of_reference_type_is_undefined); + diag::warn_second_arg_of_va_start_not_last_named_param); + else if (IsCRegister || Type->isReferenceType() || + Type->isPromotableIntegerType() || + Type->isSpecificBuiltinType(BuiltinType::Float)) { + unsigned Reason = 0; + if (Type->isReferenceType()) Reason = 1; + else if (IsCRegister) Reason = 2; + Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason; Diag(ParamLoc, diag::note_parameter_type) << Type; } @@ -2662,8 +3389,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) { // Determine which of the following types of shufflevector we're checking: // 1) unary, vector mask: (lhs, mask) - // 2) binary, vector mask: (lhs, rhs, mask) - // 3) binary, scalar mask: (lhs, rhs, index, ..., index) + // 2) binary, scalar mask: (lhs, rhs, index, ..., index) QualType resType = TheCall->getArg(0)->getType(); unsigned numElements = 0; @@ -3002,7 +3728,6 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) { return false; } - /// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]). /// This checks that the target supports __builtin_setjmp. bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { @@ -3013,12 +3738,68 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) { } namespace { +class UncoveredArgHandler { + enum { Unknown = -1, AllCovered = -2 }; + signed FirstUncoveredArg; + SmallVector<const Expr *, 4> DiagnosticExprs; + +public: + UncoveredArgHandler() : FirstUncoveredArg(Unknown) { } + + bool hasUncoveredArg() const { + return (FirstUncoveredArg >= 0); + } + + unsigned getUncoveredArg() const { + assert(hasUncoveredArg() && "no uncovered argument"); + return FirstUncoveredArg; + } + + void setAllCovered() { + // A string has been found with all arguments covered, so clear out + // the diagnostics. + DiagnosticExprs.clear(); + FirstUncoveredArg = AllCovered; + } + + void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) { + assert(NewFirstUncoveredArg >= 0 && "Outside range"); + + // Don't update if a previous string covers all arguments. + if (FirstUncoveredArg == AllCovered) + return; + + // UncoveredArgHandler tracks the highest uncovered argument index + // and with it all the strings that match this index. + if (NewFirstUncoveredArg == FirstUncoveredArg) + DiagnosticExprs.push_back(StrExpr); + else if (NewFirstUncoveredArg > FirstUncoveredArg) { + DiagnosticExprs.clear(); + DiagnosticExprs.push_back(StrExpr); + FirstUncoveredArg = NewFirstUncoveredArg; + } + } + + void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr); +}; + enum StringLiteralCheckType { SLCT_NotALiteral, SLCT_UncheckedLiteral, SLCT_CheckedLiteral }; -} +} // end anonymous namespace + +static void CheckFormatString(Sema &S, const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, + Sema::FormatStringType Type, + bool inFunctionCall, + Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg); // Determine if an expression is a string literal or constant string. // If this function returns false on the arguments to a function expecting a @@ -3029,7 +3810,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, bool HasVAListArg, unsigned format_idx, unsigned firstDataArg, Sema::FormatStringType Type, Sema::VariadicCallType CallType, bool InFunctionCall, - llvm::SmallBitVector &CheckedVarArgs) { + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) { tryAgain: if (E->isTypeDependent() || E->isValueDependent()) return SLCT_NotALiteral; @@ -3050,17 +3832,39 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, // completely checked only if both sub-expressions were checked. const AbstractConditionalOperator *C = cast<AbstractConditionalOperator>(E); - StringLiteralCheckType Left = - checkFormatStringExpr(S, C->getTrueExpr(), Args, - HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs); - if (Left == SLCT_NotALiteral) - return SLCT_NotALiteral; + + // Determine whether it is necessary to check both sub-expressions, for + // example, because the condition expression is a constant that can be + // evaluated at compile time. + bool CheckLeft = true, CheckRight = true; + + bool Cond; + if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) { + if (Cond) + CheckRight = false; + else + CheckLeft = false; + } + + StringLiteralCheckType Left; + if (!CheckLeft) + Left = SLCT_UncheckedLiteral; + else { + Left = checkFormatStringExpr(S, C->getTrueExpr(), Args, + HasVAListArg, format_idx, firstDataArg, + Type, CallType, InFunctionCall, + CheckedVarArgs, UncoveredArg); + if (Left == SLCT_NotALiteral || !CheckRight) + return Left; + } + StringLiteralCheckType Right = checkFormatStringExpr(S, C->getFalseExpr(), Args, HasVAListArg, format_idx, firstDataArg, - Type, CallType, InFunctionCall, CheckedVarArgs); - return Left < Right ? Left : Right; + Type, CallType, InFunctionCall, CheckedVarArgs, + UncoveredArg); + + return (CheckLeft && Left < Right) ? Left : Right; } case Stmt::ImplicitCastExprClass: { @@ -3111,7 +3915,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); + /*InFunctionCall*/false, CheckedVarArgs, + UncoveredArg); } } @@ -3166,7 +3971,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, InFunctionCall, - CheckedVarArgs); + CheckedVarArgs, UncoveredArg); } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) { unsigned BuiltinID = FD->getBuiltinID(); if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString || @@ -3175,7 +3980,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, return checkFormatStringExpr(S, Arg, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - InFunctionCall, CheckedVarArgs); + InFunctionCall, CheckedVarArgs, + UncoveredArg); } } } @@ -3192,8 +3998,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args, StrE = cast<StringLiteral>(E); if (StrE) { - S.CheckFormatString(StrE, E, Args, HasVAListArg, format_idx, firstDataArg, - Type, InFunctionCall, CallType, CheckedVarArgs); + CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx, + firstDataArg, Type, InFunctionCall, CallType, + CheckedVarArgs, UncoveredArg); return SLCT_CheckedLiteral; } @@ -3261,10 +4068,20 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, // C string (e.g. "%d") // ObjC string uses the same format specifiers as C string, so we can use // the same format string checking logic for both ObjC and C strings. + UncoveredArgHandler UncoveredArg; StringLiteralCheckType CT = checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg, format_idx, firstDataArg, Type, CallType, - /*IsFunctionCall*/true, CheckedVarArgs); + /*IsFunctionCall*/true, CheckedVarArgs, + UncoveredArg); + + // Generate a diagnostic where an uncovered argument is detected. + if (UncoveredArg.hasUncoveredArg()) { + unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg; + assert(ArgIdx < Args.size() && "ArgIdx outside bounds"); + UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]); + } + if (CT != SLCT_NotALiteral) // Literal format string found, check done! return CT == SLCT_CheckedLiteral; @@ -3278,20 +4095,33 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args, // format is either NSString or CFString. This is a hack to prevent // diag when using the NSLocalizedString and CFCopyLocalizedString macros // which are usually used in place of NS and CF string literals. - if (Type == FST_NSString && - SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart())) + SourceLocation FormatLoc = Args[format_idx]->getLocStart(); + if (Type == FST_NSString && SourceMgr.isInSystemMacro(FormatLoc)) return false; // If there are no arguments specified, warn with -Wformat-security, otherwise // warn only with -Wformat-nonliteral. - if (Args.size() == firstDataArg) - Diag(Args[format_idx]->getLocStart(), - diag::warn_format_nonliteral_noargs) + if (Args.size() == firstDataArg) { + Diag(FormatLoc, diag::warn_format_nonliteral_noargs) << OrigFormatExpr->getSourceRange(); - else - Diag(Args[format_idx]->getLocStart(), - diag::warn_format_nonliteral) - << OrigFormatExpr->getSourceRange(); + switch (Type) { + default: + break; + case FST_Kprintf: + case FST_FreeBSDKPrintf: + case FST_Printf: + Diag(FormatLoc, diag::note_format_security_fixit) + << FixItHint::CreateInsertion(FormatLoc, "\"%s\", "); + break; + case FST_NSString: + Diag(FormatLoc, diag::note_format_security_fixit) + << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", "); + break; + } + } else { + Diag(FormatLoc, diag::warn_format_nonliteral) + << OrigFormatExpr->getSourceRange(); + } return false; } @@ -3313,6 +4143,8 @@ protected: bool inFunctionCall; Sema::VariadicCallType CallType; llvm::SmallBitVector &CheckedVarArgs; + UncoveredArgHandler &UncoveredArg; + public: CheckFormatHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, @@ -3320,14 +4152,15 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType callType, - llvm::SmallBitVector &CheckedVarArgs) + 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) { + CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) { CoveredArgs.resize(numDataArgs); CoveredArgs.reset(); } @@ -3362,12 +4195,11 @@ public: void HandleNullChar(const char *nullCharacter) override; template <typename Range> - static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall, - const Expr *ArgumentExpr, - PartialDiagnostic PDiag, - SourceLocation StringLoc, - bool IsStringLocation, Range StringRange, - ArrayRef<FixItHint> Fixit = None); + static void + EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr, + const PartialDiagnostic &PDiag, SourceLocation StringLoc, + bool IsStringLocation, Range StringRange, + ArrayRef<FixItHint> Fixit = None); protected: bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -3396,7 +4228,7 @@ protected: bool IsStringLocation, Range StringRange, ArrayRef<FixItHint> Fixit = None); }; -} +} // end anonymous namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); @@ -3558,26 +4390,44 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const { } void CheckFormatHandler::DoneProcessing() { - // Does the number of data arguments exceed the number of - // format conversions in the format string? + // Does the number of data arguments exceed the number of + // format conversions in the format string? if (!HasVAListArg) { // Find any arguments that weren't covered. CoveredArgs.flip(); signed notCoveredArg = CoveredArgs.find_first(); if (notCoveredArg >= 0) { assert((unsigned)notCoveredArg < NumDataArgs); - if (const Expr *E = getDataArg((unsigned) notCoveredArg)) { - SourceLocation Loc = E->getLocStart(); - if (!S.getSourceManager().isInSystemMacro(Loc)) { - EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used), - Loc, /*IsStringLocation*/false, - getFormatStringRange()); - } - } + UncoveredArg.Update(notCoveredArg, OrigFormatExpr); + } else { + UncoveredArg.setAllCovered(); } } } +void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall, + const Expr *ArgExpr) { + assert(hasUncoveredArg() && DiagnosticExprs.size() > 0 && + "Invalid state"); + + if (!ArgExpr) + return; + + SourceLocation Loc = ArgExpr->getLocStart(); + + if (S.getSourceManager().isInSystemMacro(Loc)) + return; + + PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used); + for (auto E : DiagnosticExprs) + PDiag << E->getSourceRange(); + + CheckFormatHandler::EmitFormatDiagnostic( + S, IsFunctionCall, DiagnosticExprs[0], + PDiag, Loc, /*IsStringLocation*/false, + DiagnosticExprs[0]->getSourceRange()); +} + bool CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc, @@ -3585,7 +4435,6 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, unsigned specifierLen, const char *csStart, unsigned csLen) { - bool keepGoing = true; if (argIndex < NumDataArgs) { // Consider the argument coverered, even though the specifier doesn't @@ -3600,12 +4449,41 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex, // gibberish when trying to match arguments. keepGoing = false; } - - EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_conversion) - << StringRef(csStart, csLen), - Loc, /*IsStringLocation*/true, - getSpecifierRange(startSpec, specifierLen)); - + + StringRef Specifier(csStart, csLen); + + // If the specifier in non-printable, it could be the first byte of a UTF-8 + // sequence. In that case, print the UTF-8 code point. If not, print the byte + // 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) { + unsigned char FirstChar = *csStart; + CodePoint = (UTF32)FirstChar; + } + + llvm::raw_string_ostream OS(CodePointStr); + if (CodePoint < 256) + OS << "\\x" << llvm::format("%02x", CodePoint); + else if (CodePoint <= 0xFFFF) + OS << "\\u" << llvm::format("%04x", CodePoint); + else + OS << "\\U" << llvm::format("%08x", CodePoint); + OS.flush(); + Specifier = CodePointStr; + } + + EmitFormatDiagnostic( + S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc, + /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen)); + return keepGoing; } @@ -3632,6 +4510,10 @@ CheckFormatHandler::CheckNumArgs( EmitFormatDiagnostic( PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true, getSpecifierRange(startSpecifier, specifierLen)); + + // Since more arguments than conversion tokens are given, by extension + // all arguments are covered, so mark this as so. + UncoveredArg.setAllCovered(); return false; } return true; @@ -3674,14 +4556,11 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag, /// templated so it can accept either a CharSourceRange or a SourceRange. /// /// \param FixIt optional fix it hint for the format string. -template<typename Range> -void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, - const Expr *ArgumentExpr, - PartialDiagnostic PDiag, - SourceLocation Loc, - bool IsStringLocation, - Range StringRange, - ArrayRef<FixItHint> FixIt) { +template <typename Range> +void CheckFormatHandler::EmitFormatDiagnostic( + Sema &S, bool InFunctionCall, const Expr *ArgumentExpr, + const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation, + Range StringRange, ArrayRef<FixItHint> FixIt) { if (InFunctionCall) { const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag); D << StringRange; @@ -3704,6 +4583,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall, namespace { class CheckPrintfHandler : public CheckFormatHandler { bool ObjCContext; + public: CheckPrintfHandler(Sema &s, const StringLiteral *fexpr, const Expr *origFormatExpr, unsigned firstDataArg, @@ -3712,14 +4592,15 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, - formatIdx, inFunctionCall, CallType, CheckedVarArgs), + formatIdx, inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg), ObjCContext(isObjC) {} - bool HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, @@ -3760,7 +4641,7 @@ public: const char *conversionPosition) override; }; -} +} // end anonymous namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -3779,7 +4660,6 @@ bool CheckPrintfHandler::HandleAmount( const analyze_format_string::OptionalAmount &Amt, unsigned k, const char *startSpecifier, unsigned specifierLen) { - if (Amt.hasDataArgument()) { if (!HasVAListArg) { unsigned argIndex = Amt.getArgIndex(); @@ -3991,7 +4871,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - using namespace analyze_format_string; using namespace analyze_printf; const PrintfConversionSpecifier &CS = FS.getConversionSpecifier(); @@ -4361,7 +5240,6 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS, E->getLocStart(), /*IsStringLocation*/ false, SpecRange, FixItHint::CreateReplacement(SpecRange, os.str())); - } else { // The canonical type for formatting this value is different from the // actual type of the expression. (This occurs, for example, with Darwin's @@ -4500,11 +5378,12 @@ public: ArrayRef<const Expr *> Args, unsigned formatIdx, bool inFunctionCall, Sema::VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) : CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg, numDataArgs, beg, hasVAListArg, Args, formatIdx, inFunctionCall, CallType, - CheckedVarArgs) + CheckedVarArgs, UncoveredArg) {} bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS, @@ -4518,7 +5397,7 @@ public: void HandleIncompleteScanList(const char *start, const char *end) override; }; -} +} // end anonymous namespace void CheckScanfHandler::HandleIncompleteScanList(const char *start, const char *end) { @@ -4545,7 +5424,6 @@ bool CheckScanfHandler::HandleScanfSpecifier( const analyze_scanf::ScanfSpecifier &FS, const char *startSpecifier, unsigned specifierLen) { - using namespace analyze_scanf; using namespace analyze_format_string; @@ -4665,28 +5543,31 @@ bool CheckScanfHandler::HandleScanfSpecifier( return true; } -void Sema::CheckFormatString(const StringLiteral *FExpr, - const Expr *OrigFormatExpr, - ArrayRef<const Expr *> Args, - bool HasVAListArg, unsigned format_idx, - unsigned firstDataArg, FormatStringType Type, - bool inFunctionCall, VariadicCallType CallType, - llvm::SmallBitVector &CheckedVarArgs) { - +static void CheckFormatString(Sema &S, const StringLiteral *FExpr, + const Expr *OrigFormatExpr, + ArrayRef<const Expr *> Args, + bool HasVAListArg, unsigned format_idx, + unsigned firstDataArg, + Sema::FormatStringType Type, + bool inFunctionCall, + Sema::VariadicCallType CallType, + llvm::SmallBitVector &CheckedVarArgs, + UncoveredArgHandler &UncoveredArg) { // CHECK: is the format string a wide literal? if (!FExpr->isAscii() && !FExpr->isUTF8()) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } - + // Str - The format string. NOTE: this is NOT null-terminated! StringRef StrRef = FExpr->getString(); const char *Str = StrRef.data(); // Account for cases where the string literal is truncated in a declaration. - const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType()); + const ConstantArrayType *T = + S.Context.getAsConstantArrayType(FExpr->getType()); assert(T && "String literal not of constant array type!"); size_t TypeSize = T->getSize().getZExtValue(); size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size()); @@ -4697,8 +5578,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, if (TypeSize <= StrRef.size() && StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_printf_format_string_not_null_terminated), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_printf_format_string_not_null_terminated), FExpr->getLocStart(), /*IsStringLocation=*/true, OrigFormatExpr->getSourceRange()); return; @@ -4707,32 +5588,35 @@ void Sema::CheckFormatString(const StringLiteral *FExpr, // CHECK: empty format string? if (StrLen == 0 && numDataArgs > 0) { CheckFormatHandler::EmitFormatDiagnostic( - *this, inFunctionCall, Args[format_idx], - PDiag(diag::warn_empty_format_string), FExpr->getLocStart(), + S, inFunctionCall, Args[format_idx], + S.PDiag(diag::warn_empty_format_string), FExpr->getLocStart(), /*IsStringLocation*/true, OrigFormatExpr->getSourceRange()); return; } - - if (Type == FST_Printf || Type == FST_NSString || - Type == FST_FreeBSDKPrintf || Type == FST_OSTrace) { - CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, - numDataArgs, (Type == FST_NSString || Type == FST_OSTrace), + + 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); - + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); + if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen, - getLangOpts(), - Context.getTargetInfo(), - Type == FST_FreeBSDKPrintf)) + S.getLangOpts(), + S.Context.getTargetInfo(), + Type == Sema::FST_FreeBSDKPrintf)) H.DoneProcessing(); - } else if (Type == FST_Scanf) { - CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, + } else if (Type == Sema::FST_Scanf) { + CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs, Str, HasVAListArg, Args, format_idx, - inFunctionCall, CallType, CheckedVarArgs); - + inFunctionCall, CallType, CheckedVarArgs, + UncoveredArg); + if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen, - getLangOpts(), - Context.getTargetInfo())) + S.getLangOpts(), + S.Context.getTargetInfo())) H.DoneProcessing(); } // TODO: handle other formats } @@ -5145,7 +6029,6 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, emitReplacement(*this, Call->getExprLoc(), Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); - return; } //===--- CHECK: Standard memory functions ---------------------------------===// @@ -5191,7 +6074,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T, const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl(); RD = RD ? RD->getDefinition() : nullptr; - if (!RD) + if (!RD || RD->isInvalidDecl()) return nullptr; if (RD->isDynamicClass()) @@ -5398,7 +6281,6 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call, << FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)")); break; } - } // A little helper routine: ignore addition and subtraction of integer literals. @@ -5613,10 +6495,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE, //===--- CHECK: Return Address of Stack Variable --------------------------===// -static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl); -static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl); +static const Expr *EvalVal(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl); +static const Expr *EvalAddr(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl); /// CheckReturnStackAddr - Check if a return statement returns the address /// of a stack variable. @@ -5624,8 +6508,8 @@ static void CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, SourceLocation ReturnLoc) { - Expr *stackE = nullptr; - SmallVector<DeclRefExpr *, 8> refVars; + const Expr *stackE = nullptr; + SmallVector<const DeclRefExpr *, 8> refVars; // Perform checking for returned stack addresses, local blocks, // label addresses or references to temporaries. @@ -5653,7 +6537,8 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, diagRange = refVars[0]->getSourceRange(); } - if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var. + if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { + // address of local var S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType() << DR->getDecl()->getDeclName() << diagRange; } else if (isa<BlockExpr>(stackE)) { // local block. @@ -5668,12 +6553,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, // Display the "trail" of reference variables that we followed until we // found the problematic expression using notes. for (unsigned i = 0, e = refVars.size(); i != e; ++i) { - VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); + const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl()); // If this var binds to another reference var, show the range of the next // var, otherwise the var binds to the problematic expression, in which case // show the range of the expression. - SourceRange range = (i < e-1) ? refVars[i+1]->getSourceRange() - : stackE->getSourceRange(); + SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange() + : stackE->getSourceRange(); S.Diag(VD->getLocation(), diag::note_ref_var_local_bind) << VD->getDeclName() << range; } @@ -5705,8 +6590,9 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, /// * arbitrary interplay between "&" and "*" operators /// * pointer arithmetic from an address of a stack variable /// * taking the address of an array element where the array is on the stack -static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl) { +static const Expr *EvalAddr(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl) { if (E->isTypeDependent()) return nullptr; @@ -5723,13 +6609,13 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, // EvalAddr and EvalVal appropriately. switch (E->getStmtClass()) { case Stmt::DeclRefExprClass: { - DeclRefExpr *DR = cast<DeclRefExpr>(E); + const DeclRefExpr *DR = cast<DeclRefExpr>(E); // If we leave the immediate function, the lifetime isn't about to end. if (DR->refersToEnclosingVariableOrCapture()) return nullptr; - if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) + if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) // If this is a reference variable, follow through to the expression that // it points to. if (V->hasLocalStorage() && @@ -5745,44 +6631,44 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, case Stmt::UnaryOperatorClass: { // The only unary operator that make sense to handle here // is AddrOf. All others don't make sense as pointers. - UnaryOperator *U = cast<UnaryOperator>(E); + const UnaryOperator *U = cast<UnaryOperator>(E); if (U->getOpcode() == UO_AddrOf) return EvalVal(U->getSubExpr(), refVars, ParentDecl); - else - return nullptr; + return nullptr; } case Stmt::BinaryOperatorClass: { // Handle pointer arithmetic. All other binary operators are not valid // in this context. - BinaryOperator *B = cast<BinaryOperator>(E); + const BinaryOperator *B = cast<BinaryOperator>(E); BinaryOperatorKind op = B->getOpcode(); if (op != BO_Add && op != BO_Sub) return nullptr; - Expr *Base = B->getLHS(); + const Expr *Base = B->getLHS(); // Determine which argument is the real pointer base. It could be // the RHS argument instead of the LHS. - if (!Base->getType()->isPointerType()) Base = B->getRHS(); + if (!Base->getType()->isPointerType()) + Base = B->getRHS(); - assert (Base->getType()->isPointerType()); + assert(Base->getType()->isPointerType()); return EvalAddr(Base, refVars, ParentDecl); } // For conditional operators we need to see if either the LHS or RHS are // valid DeclRefExpr*s. If one of them is valid, we return it. case Stmt::ConditionalOperatorClass: { - ConditionalOperator *C = cast<ConditionalOperator>(E); + const ConditionalOperator *C = cast<ConditionalOperator>(E); // Handle the GNU extension for missing LHS. // FIXME: That isn't a ConditionalOperator, so doesn't get here. - if (Expr *LHSExpr = C->getLHS()) { + if (const Expr *LHSExpr = C->getLHS()) { // In C++, we can have a throw-expression, which has 'void' type. if (!LHSExpr->getType()->isVoidType()) - if (Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) + if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl)) return LHS; } @@ -5815,7 +6701,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, case Stmt::CXXDynamicCastExprClass: case Stmt::CXXConstCastExprClass: case Stmt::CXXReinterpretCastExprClass: { - Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); + const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr(); switch (cast<CastExpr>(E)->getCastKind()) { case CK_LValueToRValue: case CK_NoOp: @@ -5845,157 +6731,161 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, } case Stmt::MaterializeTemporaryExprClass: - if (Expr *Result = EvalAddr( - cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) + if (const Expr *Result = + EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars, ParentDecl)) return Result; - return E; - + // Everything else: we simply don't reason about them. default: return nullptr; } } - /// EvalVal - This function is complements EvalAddr in the mutual recursion. /// See the comments for EvalAddr for more details. -static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars, - Decl *ParentDecl) { -do { - // We should only be called for evaluating non-pointer expressions, or - // expressions with a pointer type that are not used as references but instead - // are l-values (e.g., DeclRefExpr with a pointer type). - - // Our "symbolic interpreter" is just a dispatch off the currently - // viewed AST node. We then recursively traverse the AST by calling - // EvalAddr and EvalVal appropriately. - - E = E->IgnoreParens(); - switch (E->getStmtClass()) { - case Stmt::ImplicitCastExprClass: { - ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); - if (IE->getValueKind() == VK_LValue) { - E = IE->getSubExpr(); - continue; +static const Expr *EvalVal(const Expr *E, + SmallVectorImpl<const DeclRefExpr *> &refVars, + const Decl *ParentDecl) { + do { + // We should only be called for evaluating non-pointer expressions, or + // expressions with a pointer type that are not used as references but + // instead + // are l-values (e.g., DeclRefExpr with a pointer type). + + // Our "symbolic interpreter" is just a dispatch off the currently + // viewed AST node. We then recursively traverse the AST by calling + // EvalAddr and EvalVal appropriately. + + E = E->IgnoreParens(); + switch (E->getStmtClass()) { + case Stmt::ImplicitCastExprClass: { + const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E); + if (IE->getValueKind() == VK_LValue) { + E = IE->getSubExpr(); + continue; + } + return nullptr; } - return nullptr; - } - - case Stmt::ExprWithCleanupsClass: - return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl); - case Stmt::DeclRefExprClass: { - // When we hit a DeclRefExpr we are looking at code that refers to a - // variable's name. If it's not a reference variable we check if it has - // local storage within the function, and if so, return the expression. - DeclRefExpr *DR = cast<DeclRefExpr>(E); + case Stmt::ExprWithCleanupsClass: + return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars, + ParentDecl); - // If we leave the immediate function, the lifetime isn't about to end. - if (DR->refersToEnclosingVariableOrCapture()) - return nullptr; + case Stmt::DeclRefExprClass: { + // When we hit a DeclRefExpr we are looking at code that refers to a + // variable's name. If it's not a reference variable we check if it has + // local storage within the function, and if so, return the expression. + const DeclRefExpr *DR = cast<DeclRefExpr>(E); - if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { - // Check if it refers to itself, e.g. "int& i = i;". - if (V == ParentDecl) - return DR; + // If we leave the immediate function, the lifetime isn't about to end. + if (DR->refersToEnclosingVariableOrCapture()) + return nullptr; - if (V->hasLocalStorage()) { - if (!V->getType()->isReferenceType()) + if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) { + // Check if it refers to itself, e.g. "int& i = i;". + if (V == ParentDecl) return DR; - // Reference variable, follow through to the expression that - // it points to. - if (V->hasInit()) { - // Add the reference variable to the "trail". - refVars.push_back(DR); - return EvalVal(V->getInit(), refVars, V); + if (V->hasLocalStorage()) { + if (!V->getType()->isReferenceType()) + return DR; + + // Reference variable, follow through to the expression that + // it points to. + if (V->hasInit()) { + // Add the reference variable to the "trail". + refVars.push_back(DR); + return EvalVal(V->getInit(), refVars, V); + } } } - } - - return nullptr; - } - - case Stmt::UnaryOperatorClass: { - // The only unary operator that make sense to handle here - // is Deref. All others don't resolve to a "name." This includes - // handling all sorts of rvalues passed to a unary operator. - UnaryOperator *U = cast<UnaryOperator>(E); - if (U->getOpcode() == UO_Deref) - return EvalAddr(U->getSubExpr(), refVars, ParentDecl); + return nullptr; + } - return nullptr; - } + case Stmt::UnaryOperatorClass: { + // The only unary operator that make sense to handle here + // is Deref. All others don't resolve to a "name." This includes + // handling all sorts of rvalues passed to a unary operator. + const UnaryOperator *U = cast<UnaryOperator>(E); - case Stmt::ArraySubscriptExprClass: { - // Array subscripts are potential references to data on the stack. We - // retrieve the DeclRefExpr* for the array variable if it indeed - // has local storage. - return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl); - } + if (U->getOpcode() == UO_Deref) + return EvalAddr(U->getSubExpr(), refVars, ParentDecl); - case Stmt::OMPArraySectionExprClass: { - return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, - ParentDecl); - } + return nullptr; + } - case Stmt::ConditionalOperatorClass: { - // For conditional operators we need to see if either the LHS or RHS are - // non-NULL Expr's. If one is non-NULL, we return it. - ConditionalOperator *C = cast<ConditionalOperator>(E); + case Stmt::ArraySubscriptExprClass: { + // Array subscripts are potential references to data on the stack. We + // retrieve the DeclRefExpr* for the array variable if it indeed + // has local storage. + const auto *ASE = cast<ArraySubscriptExpr>(E); + if (ASE->isTypeDependent()) + return nullptr; + return EvalAddr(ASE->getBase(), refVars, ParentDecl); + } - // Handle the GNU extension for missing LHS. - if (Expr *LHSExpr = C->getLHS()) { - // In C++, we can have a throw-expression, which has 'void' type. - if (!LHSExpr->getType()->isVoidType()) - if (Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) - return LHS; + case Stmt::OMPArraySectionExprClass: { + return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars, + ParentDecl); } - // In C++, we can have a throw-expression, which has 'void' type. - if (C->getRHS()->getType()->isVoidType()) - return nullptr; + case Stmt::ConditionalOperatorClass: { + // For conditional operators we need to see if either the LHS or RHS are + // non-NULL Expr's. If one is non-NULL, we return it. + const ConditionalOperator *C = cast<ConditionalOperator>(E); + + // Handle the GNU extension for missing LHS. + if (const Expr *LHSExpr = C->getLHS()) { + // In C++, we can have a throw-expression, which has 'void' type. + if (!LHSExpr->getType()->isVoidType()) + if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl)) + return LHS; + } - return EvalVal(C->getRHS(), refVars, ParentDecl); - } + // In C++, we can have a throw-expression, which has 'void' type. + if (C->getRHS()->getType()->isVoidType()) + return nullptr; - // Accesses to members are potential references to data on the stack. - case Stmt::MemberExprClass: { - MemberExpr *M = cast<MemberExpr>(E); + return EvalVal(C->getRHS(), refVars, ParentDecl); + } - // Check for indirect access. We only want direct field accesses. - if (M->isArrow()) - return nullptr; + // Accesses to members are potential references to data on the stack. + case Stmt::MemberExprClass: { + const MemberExpr *M = cast<MemberExpr>(E); - // Check whether the member type is itself a reference, in which case - // we're not going to refer to the member, but to what the member refers to. - if (M->getMemberDecl()->getType()->isReferenceType()) - return nullptr; + // Check for indirect access. We only want direct field accesses. + if (M->isArrow()) + return nullptr; - return EvalVal(M->getBase(), refVars, ParentDecl); - } + // Check whether the member type is itself a reference, in which case + // we're not going to refer to the member, but to what the member refers + // to. + if (M->getMemberDecl()->getType()->isReferenceType()) + return nullptr; - case Stmt::MaterializeTemporaryExprClass: - if (Expr *Result = EvalVal( - cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), - refVars, ParentDecl)) - return Result; - - return E; + return EvalVal(M->getBase(), refVars, ParentDecl); + } - default: - // Check that we don't return or take the address of a reference to a - // temporary. This is only useful in C++. - if (!E->isTypeDependent() && E->isRValue()) + case Stmt::MaterializeTemporaryExprClass: + if (const Expr *Result = + EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(), + refVars, ParentDecl)) + return Result; return E; - // Everything else: we simply don't reason about them. - return nullptr; - } -} while (true); + default: + // Check that we don't return or take the address of a reference to a + // temporary. This is only useful in C++. + if (!E->isTypeDependent() && E->isRValue()) + return E; + + // Everything else: we simply don't reason about them. + return nullptr; + } + } while (true); } void @@ -6047,7 +6937,6 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) { if (DRL->getDecl() == DRR->getDecl()) return; - // Special case: check for comparisons against literals that can be exactly // represented by APFloat. In such cases, do not emit a warning. This // is a heuristic: often comparison against such literals are used to @@ -6173,8 +7062,7 @@ struct IntRange { } }; -static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, - unsigned MaxWidth) { +IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) { if (value.isSigned() && value.isNegative()) return IntRange(value.getMinSignedBits(), false); @@ -6186,8 +7074,8 @@ static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, return IntRange(value.getActiveBits(), true); } -static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, - unsigned MaxWidth) { +IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, + unsigned MaxWidth) { if (result.isInt()) return GetValueRange(C, result.getInt(), MaxWidth); @@ -6215,7 +7103,7 @@ static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty, return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType()); } -static QualType GetExprType(Expr *E) { +QualType GetExprType(const Expr *E) { QualType Ty = E->getType(); if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>()) Ty = AtomicRHS->getValueType(); @@ -6226,7 +7114,7 @@ static QualType GetExprType(Expr *E) { /// range of values it might take. /// /// \param MaxWidth - the width to which the value will be truncated -static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { +IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) { E = E->IgnoreParens(); // Try a full evaluation first. @@ -6237,7 +7125,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { // I think we only want to look through implicit casts here; if the // user has an explicit widening cast, we should treat the value as // being of the new, wider type. - if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) { + if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) { if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue) return GetExprRange(C, CE->getSubExpr(), MaxWidth); @@ -6264,7 +7152,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { SubRange.NonNegative || OutputTypeRange.NonNegative); } - if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) { + if (const auto *CO = dyn_cast<ConditionalOperator>(E)) { // If we can fold the condition, just take that operand. bool CondResult; if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C)) @@ -6278,7 +7166,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::join(L, R); } - if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) { + if (const auto *BO = dyn_cast<BinaryOperator>(E)) { switch (BO->getOpcode()) { // Boolean-valued operations are single-bit and positive. @@ -6418,7 +7306,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { return IntRange::join(L, R); } - if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) { + if (const auto *UO = dyn_cast<UnaryOperator>(E)) { switch (UO->getOpcode()) { // Boolean-valued operations are white-listed. case UO_LNot: @@ -6434,26 +7322,26 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) { } } - if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E)) + if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E)) return GetExprRange(C, OVE->getSourceExpr(), MaxWidth); - if (FieldDecl *BitField = E->getSourceBitField()) + if (const auto *BitField = E->getSourceBitField()) return IntRange(BitField->getBitWidthValue(C), BitField->getType()->isUnsignedIntegerOrEnumerationType()); return IntRange::forValueOfType(C, GetExprType(E)); } -static IntRange GetExprRange(ASTContext &C, Expr *E) { +IntRange GetExprRange(ASTContext &C, const Expr *E) { return GetExprRange(C, E, C.getIntWidth(GetExprType(E))); } /// Checks whether the given value, which currently has the given /// source semantics, has the same value when coerced through the /// target semantics. -static bool IsSameFloatAfterCast(const llvm::APFloat &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +bool IsSameFloatAfterCast(const llvm::APFloat &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { llvm::APFloat truncated = value; bool ignored; @@ -6468,9 +7356,9 @@ static bool IsSameFloatAfterCast(const llvm::APFloat &value, /// target semantics. /// /// The value might be a vector of floats (or a complex number). -static bool IsSameFloatAfterCast(const APValue &value, - const llvm::fltSemantics &Src, - const llvm::fltSemantics &Tgt) { +bool IsSameFloatAfterCast(const APValue &value, + const llvm::fltSemantics &Src, + const llvm::fltSemantics &Tgt) { if (value.isFloat()) return IsSameFloatAfterCast(value.getFloat(), Src, Tgt); @@ -6486,9 +7374,9 @@ static bool IsSameFloatAfterCast(const APValue &value, IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt)); } -static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); +void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC); -static bool IsZero(Sema &S, Expr *E) { +bool IsZero(Sema &S, Expr *E) { // Suppress cases where we are comparing against an enum constant. if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) @@ -6503,7 +7391,7 @@ static bool IsZero(Sema &S, Expr *E) { return E->isIntegerConstantExpr(Value, S.Context) && Value == 0; } -static bool HasEnumType(Expr *E) { +bool HasEnumType(Expr *E) { // Strip off implicit integral promotions. while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) { if (ICE->getCastKind() != CK_IntegralCast && @@ -6515,7 +7403,7 @@ static bool HasEnumType(Expr *E) { return E->getType()->isEnumeralType(); } -static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { +void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; @@ -6543,10 +7431,9 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) { } } -static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, - Expr *Constant, Expr *Other, - llvm::APSInt Value, - bool RhsConstant) { +void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant, + Expr *Other, const llvm::APSInt &Value, + bool RhsConstant) { // Disable warning in template instantiations. if (!S.ActiveTemplateInstantiations.empty()) return; @@ -6754,7 +7641,7 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, /// Analyze the operands of the given comparison. Implements the /// fallback case from AnalyzeComparison. -static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { +void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc()); } @@ -6762,7 +7649,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) { /// \brief Implements -Wsign-compare. /// /// \param E the binary operator to check for warnings -static void AnalyzeComparison(Sema &S, BinaryOperator *E) { +void AnalyzeComparison(Sema &S, BinaryOperator *E) { // The type the comparison is being performed in. QualType T = E->getLHS()->getType(); @@ -6863,8 +7750,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) { /// Analyzes an attempt to assign the given value to a bitfield. /// /// Returns true if there was something fishy about the attempt. -static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, - SourceLocation InitLoc) { +bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, + SourceLocation InitLoc) { assert(Bitfield->isBitField()); if (Bitfield->isInvalidDecl()) return false; @@ -6918,7 +7805,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, /// Analyze the given simple or compound assignment for warning-worthy /// operations. -static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { +void AnalyzeAssignment(Sema &S, BinaryOperator *E) { // Just recurse on the LHS. AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc()); @@ -6937,9 +7824,9 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) { } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, + SourceLocation CContext, unsigned diag, + bool pruneControlFlow = false) { if (pruneControlFlow) { S.DiagRuntimeBehavior(E->getExprLoc(), E, S.PDiag(diag) @@ -6952,25 +7839,75 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T, } /// Diagnose an implicit cast; purely a helper for CheckImplicitConversion. -static void DiagnoseImpCast(Sema &S, Expr *E, QualType T, - SourceLocation CContext, unsigned diag, - bool pruneControlFlow = false) { +void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext, + unsigned diag, bool pruneControlFlow = false) { DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow); } -/// Diagnose an implicit cast from a literal expression. Does not warn when the -/// cast wouldn't lose information. -void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, - SourceLocation CContext) { - // Try to convert the literal exactly to an integer. If we can, don't warn. + +/// Diagnose an implicit cast from a floating point value to an integer value. +void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T, + + SourceLocation CContext) { + const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool); + const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty(); + + Expr *InnerE = E->IgnoreParenImpCasts(); + // We also want to warn on, e.g., "int i = -1.234" + if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) + if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) + InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); + + const bool IsLiteral = + isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE); + + llvm::APFloat Value(0.0); + bool IsConstant = + E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects); + if (!IsConstant) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + bool isExact = false; - const llvm::APFloat &Value = FL->getValue(); + llvm::APSInt IntegerValue(S.Context.getIntWidth(T), T->hasUnsignedIntegerRepresentation()); - if (Value.convertToInteger(IntegerValue, - llvm::APFloat::rmTowardZero, &isExact) - == llvm::APFloat::opOK && isExact) - return; + if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero, + &isExact) == llvm::APFloat::opOK && + isExact) { + if (IsLiteral) return; + return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer, + PruneWarnings); + } + + unsigned DiagID = 0; + if (IsLiteral) { + // Warn on floating point literal to integer. + DiagID = diag::warn_impcast_literal_float_to_integer; + } else if (IntegerValue == 0) { + if (Value.isZero()) { // Skip -0.0 to 0 conversion. + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + // Warn on non-zero to zero conversion. + DiagID = diag::warn_impcast_float_to_integer_zero; + } else { + if (IntegerValue.isUnsigned()) { + if (!IntegerValue.isMaxValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } else { // IntegerValue.isSigned() + if (!IntegerValue.isMaxSignedValue() && + !IntegerValue.isMinSignedValue()) { + return DiagnoseImpCast(S, E, T, CContext, + diag::warn_impcast_float_integer, PruneWarnings); + } + } + // Warn on evaluatable floating point expression to integer conversion. + DiagID = diag::warn_impcast_float_to_integer; + } // FIXME: Force the precision of the source value down so we don't print // digits which are usually useless (we don't really care here if we @@ -6983,14 +7920,22 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T, Value.toString(PrettySourceValue, precision); SmallString<16> PrettyTargetValue; - if (T->isSpecificBuiltinType(BuiltinType::Bool)) + if (IsBool) PrettyTargetValue = Value.isZero() ? "false" : "true"; else IntegerValue.toString(PrettyTargetValue); - S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer) - << FL->getType() << T.getUnqualifiedType() << PrettySourceValue - << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext); + if (PruneWarnings) { + S.DiagRuntimeBehavior(E->getExprLoc(), E, + S.PDiag(DiagID) + << E->getType() << T.getUnqualifiedType() + << PrettySourceValue << PrettyTargetValue + << E->getSourceRange() << SourceRange(CContext)); + } else { + S.Diag(E->getExprLoc(), DiagID) + << E->getType() << T.getUnqualifiedType() << PrettySourceValue + << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext); + } } std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { @@ -7002,7 +7947,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) { return ValueInRange.toString(10); } -static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { +bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) { if (!isa<ImplicitCastExpr>(Ex)) return false; @@ -7042,8 +7987,7 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall, } } -static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, - SourceLocation CC) { +void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) { if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer, E->getExprLoc())) return; @@ -7065,14 +8009,21 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation Loc = E->getSourceRange().getBegin(); + // Venture through the macro stacks to get to the source of macro arguments. + // The new location is a better location than the complete location that was + // passed in. + while (S.SourceMgr.isMacroArgExpansion(Loc)) + Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc); + + while (S.SourceMgr.isMacroArgExpansion(CC)) + CC = S.SourceMgr.getImmediateMacroCallerLoc(CC); + // __null is usually wrapped in a macro. Go up a macro if that is the case. - if (NullKind == Expr::NPCK_GNUNull) { - if (Loc.isMacroID()) { - StringRef MacroName = - Lexer::getImmediateMacroName(Loc, S.SourceMgr, S.getLangOpts()); - if (MacroName == "NULL") - Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; - } + if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) { + StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( + Loc, S.SourceMgr, S.getLangOpts()); + if (MacroName == "NULL") + Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first; } // Only warn if the null and context location are in the same macro expansion. @@ -7085,17 +8036,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, S.getFixItZeroLiteralForType(T, Loc)); } -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral); -static void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral); +void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral); +void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral); /// Check a single element within a collection literal against the /// target element type. -static void checkObjCCollectionLiteralElement(Sema &S, - QualType TargetElementType, - Expr *Element, - unsigned ElementKind) { +void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType, + Expr *Element, unsigned ElementKind) { // Skip a bitcast to 'id' or qualified 'id'. if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) { if (ICE->getCastKind() == CK_BitCast && @@ -7124,8 +8073,8 @@ static void checkObjCCollectionLiteralElement(Sema &S, /// Check an Objective-C array literal being converted to the given /// target type. -static void checkObjCArrayLiteral(Sema &S, QualType TargetType, - ObjCArrayLiteral *ArrayLiteral) { +void checkObjCArrayLiteral(Sema &S, QualType TargetType, + ObjCArrayLiteral *ArrayLiteral) { if (!S.NSArrayDecl) return; @@ -7152,9 +8101,8 @@ static void checkObjCArrayLiteral(Sema &S, QualType TargetType, /// Check an Objective-C dictionary literal being converted to the given /// target type. -static void checkObjCDictionaryLiteral( - Sema &S, QualType TargetType, - ObjCDictionaryLiteral *DictionaryLiteral) { +void checkObjCDictionaryLiteral(Sema &S, QualType TargetType, + ObjCDictionaryLiteral *DictionaryLiteral) { if (!S.NSDictionaryDecl) return; @@ -7180,6 +8128,32 @@ static void checkObjCDictionaryLiteral( } } +// Helper function to filter out cases for constant width constant conversion. +// Don't warn on char array initialization or for non-decimal values. +bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T, + SourceLocation CC) { + // If initializing from a constant, and the constant starts with '0', + // then it is a binary, octal, or hexadecimal. Allow these constants + // to fill all the bits, even if there is a sign change. + if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) { + const char FirstLiteralCharacter = + S.getSourceManager().getCharacterData(IntLit->getLocStart())[0]; + if (FirstLiteralCharacter == '0') + return false; + } + + // If the CC location points to a '{', and the type is char, then assume + // assume it is an array initialization. + if (CC.isValid() && T->isCharType()) { + const char FirstContextCharacter = + S.getSourceManager().getCharacterData(CC)[0]; + if (FirstContextCharacter == '{') + return false; + } + + return true; +} + void CheckImplicitConversion(Sema &S, Expr *E, QualType T, SourceLocation CC, bool *ICContext = nullptr) { if (E->isTypeDependent() || E->isValueDependent()) return; @@ -7284,7 +8258,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision); - } // ... or possibly if we're increasing rank, too else if (TargetBT->getKind() > SourceBT->getKind()) { @@ -7296,22 +8269,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return; } - // If the target is integral, always warn. + // If the target is integral, always warn. if (TargetBT && TargetBT->isInteger()) { if (S.SourceMgr.isInSystemMacro(CC)) return; - - Expr *InnerE = E->IgnoreParenImpCasts(); - // We also want to warn on, e.g., "int i = -1.234" - if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE)) - if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus) - InnerE = UOp->getSubExpr()->IgnoreParenImpCasts(); - - if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) { - DiagnoseFloatingLiteralImpCast(S, FL, T, CC); - } else { - DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer); - } + + DiagnoseFloatingImpCast(S, E, T, CC); } // Detect the case where a call result is converted from floating-point to @@ -7358,7 +8321,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, // If the source is a constant, use a default-on diagnostic. // TODO: this should happen for bitfield stores, too. llvm::APSInt Value(32); - if (E->isIntegerConstantExpr(Value, S.Context)) { + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) { if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -7383,10 +8346,34 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision); } + if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative && + SourceRange.NonNegative && Source->isSignedIntegerType()) { + // Warn when doing a signed to signed conversion, warn if the positive + // source value is exactly the width of the target type, which will + // cause a negative value to be stored. + + llvm::APSInt Value; + if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects) && + !S.SourceMgr.isInSystemMacro(CC)) { + if (isSameWidthConstantConversion(S, E, T, CC)) { + std::string PrettySourceValue = Value.toString(10); + std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange); + + S.DiagRuntimeBehavior( + E->getExprLoc(), E, + S.PDiag(diag::warn_impcast_integer_precision_constant) + << PrettySourceValue << PrettyTargetValue << E->getType() << T + << E->getSourceRange() << clang::SourceRange(CC)); + return; + } + } + + // Fall through for non-constants to give a sign conversion warning. + } + if ((TargetRange.NonNegative && !SourceRange.NonNegative) || (!TargetRange.NonNegative && SourceRange.NonNegative && SourceRange.Width == TargetRange.Width)) { - if (S.SourceMgr.isInSystemMacro(CC)) return; @@ -7429,8 +8416,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T, return DiagnoseImpCast(S, E, SourceType, T, CC, diag::warn_impcast_different_enum_types); } - - return; } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, @@ -7446,7 +8431,6 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T, AnalyzeImplicitConversions(S, E, CC); if (E->getType() != T) return CheckImplicitConversion(S, E, T, CC, &ICContext); - return; } void CheckConditionalOperator(Sema &S, ConditionalOperator *E, @@ -7479,7 +8463,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E, /// CheckBoolLikeConversion - Check conversion of given expression to boolean. /// Input argument E is a logical expression. -static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { +void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) { if (S.getLangOpts().Bool) return; CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC); @@ -7583,10 +8567,31 @@ 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()); + } + return IllegalParams; +} + // Helper function for Sema::DiagnoseAlwaysNonNullPointer. // Returns true when emitting a warning about taking the address of a reference. static bool CheckForReference(Sema &SemaRef, const Expr *E, - PartialDiagnostic PD) { + const PartialDiagnostic &PD) { E = E->IgnoreParenImpCasts(); const FunctionDecl *FD = nullptr; @@ -7681,7 +8686,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, } } - auto ComplainAboutNonnullParamOrCall = [&](bool IsParam) { + auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) { + bool IsParam = isa<NonNullAttr>(NonnullAttr); std::string Str; llvm::raw_string_ostream S(Str); E->printPretty(S, nullptr, getPrintingPolicy()); @@ -7689,13 +8695,14 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, : diag::warn_cast_nonnull_to_bool; Diag(E->getExprLoc(), DiagID) << IsParam << S.str() << E->getSourceRange() << Range << IsEqual; + Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam; }; // If we have a CallExpr that is tagged with returns_nonnull, we can complain. if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) { if (auto *Callee = Call->getDirectCallee()) { - if (Callee->hasAttr<ReturnsNonNullAttr>()) { - ComplainAboutNonnullParamOrCall(false); + if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) { + ComplainAboutNonnullParamOrCall(A); return; } } @@ -7717,25 +8724,25 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, if (const auto* PV = dyn_cast<ParmVarDecl>(D)) { if (getCurFunction() && !getCurFunction()->ModifiedNonNullParams.count(PV)) { - if (PV->hasAttr<NonNullAttr>()) { - ComplainAboutNonnullParamOrCall(true); + if (const Attr *A = PV->getAttr<NonNullAttr>()) { + ComplainAboutNonnullParamOrCall(A); return; } if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) { - auto ParamIter = std::find(FD->param_begin(), FD->param_end(), PV); + auto ParamIter = llvm::find(FD->parameters(), PV); assert(ParamIter != FD->param_end()); unsigned ParamNo = std::distance(FD->param_begin(), ParamIter); for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) { if (!NonNull->args_size()) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } for (unsigned ArgNo : NonNull->args()) { if (ArgNo == ParamNo) { - ComplainAboutNonnullParamOrCall(true); + ComplainAboutNonnullParamOrCall(NonNull); return; } } @@ -7817,7 +8824,6 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E, << FixItHint::CreateInsertion(getLocForEndOfToken(E->getLocEnd()), "()"); } - /// Diagnoses "dangerous" implicit conversions within the given /// expression (which is a full expression). Implements -Wconversion /// and -Wsign-compare. @@ -7852,12 +8858,20 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) { /// Diagnose when expression is an integer constant expression and its evaluation /// results in integer overflow void Sema::CheckForIntOverflow (Expr *E) { - if (isa<BinaryOperator>(E->IgnoreParenCasts())) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); - else if (auto InitList = dyn_cast<InitListExpr>(E)) - for (Expr *E : InitList->inits()) - if (isa<BinaryOperator>(E->IgnoreParenCasts())) - E->IgnoreParenCasts()->EvaluateForOverflow(Context); + // Use a work list to deal with nested struct initializers. + SmallVector<Expr *, 2> Exprs(1, E); + + do { + Expr *E = Exprs.pop_back_val(); + + if (isa<BinaryOperator>(E->IgnoreParenCasts())) { + E->IgnoreParenCasts()->EvaluateForOverflow(Context); + continue; + } + + if (auto InitList = dyn_cast<InitListExpr>(E)) + Exprs.append(InitList->inits().begin(), InitList->inits().end()); + } while (!Exprs.empty()); } namespace { @@ -7875,7 +8889,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { struct Value { explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {} unsigned Parent : 31; - bool Merged : 1; + unsigned Merged : 1; }; SmallVector<Value, 8> Values; @@ -7987,12 +9001,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> { Self.ModAsSideEffect = &ModAsSideEffect; } ~SequencedSubexpression() { - for (auto MI = ModAsSideEffect.rbegin(), ME = ModAsSideEffect.rend(); - MI != ME; ++MI) { - UsageInfo &U = Self.UsageMap[MI->first]; + for (auto &M : llvm::reverse(ModAsSideEffect)) { + UsageInfo &U = Self.UsageMap[M.first]; auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect]; - Self.addUsage(U, MI->first, SideEffectUsage.Use, UK_ModAsValue); - SideEffectUsage = MI->second; + Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue); + SideEffectUsage = M.second; } Self.ModAsSideEffect = OldModAsSideEffect; } @@ -8195,6 +9208,7 @@ public: notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue : UK_ModAsSideEffect); } + void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } @@ -8344,7 +9358,7 @@ public: Tree.merge(Elts[I]); } }; -} +} // end anonymous namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector<Expr *, 8> WorkList; @@ -8403,13 +9417,10 @@ static void diagnoseArrayStarInParamType(Sema &S, QualType PType, /// takes care of any checks that cannot be performed on the /// declaration itself, e.g., that the types of each of the function /// parameters are complete. -bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P, - ParmVarDecl *const *PEnd, +bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters, bool CheckParameterNames) { bool HasInvalidParm = false; - for (; P != PEnd; ++P) { - ParmVarDecl *Param = *P; - + for (ParmVarDecl *Param : Parameters) { // C99 6.7.5.3p4: the parameters in a parameter type list in a // function declarator that is part of a function definition of // that function shall not have incomplete type. @@ -8517,21 +9528,12 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) { << TRange << Op->getSourceRange(); } -static const Type* getElementType(const Expr *BaseExpr) { - const Type* EltType = BaseExpr->getType().getTypePtr(); - if (EltType->isAnyPointerType()) - return EltType->getPointeeType().getTypePtr(); - else if (EltType->isArrayType()) - return EltType->getBaseElementTypeUnsafe(); - return EltType; -} - /// \brief Check whether this array fits the idiom of a size-one tail padded /// array member of a struct. /// /// We avoid emitting out-of-bounds access warnings for such arrays as they are /// commonly used to emulate flexible arrays in C89 code. -static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size, +static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size, const NamedDecl *ND) { if (Size != 1 || !ND) return false; @@ -8580,7 +9582,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (IndexExpr->isValueDependent()) return; - const Type *EffectiveType = getElementType(BaseExpr); + const Type *EffectiveType = + BaseExpr->getType()->getPointeeOrArrayElementType(); BaseExpr = BaseExpr->IgnoreParenCasts(); const ConstantArrayType *ArrayTy = Context.getAsConstantArrayType(BaseExpr->getType()); @@ -8604,7 +9607,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr, if (!size.isStrictlyPositive()) return; - const Type* BaseType = getElementType(BaseExpr); + const Type *BaseType = BaseExpr->getType()->getPointeeOrArrayElementType(); if (BaseType != EffectiveType) { // Make sure we're comparing apples to apples when comparing index to size uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType); @@ -8754,7 +9757,7 @@ namespace { Range = e->getSourceRange(); } }; -} +} // end anonymous namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. @@ -8900,7 +9903,7 @@ namespace { } } }; -} +} // end anonymous namespace /// Check whether the given argument is a block which captures a /// variable. @@ -9136,7 +10139,6 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { } } } - } /// Check a message send to see if it's likely to cause a retain cycle. @@ -9340,7 +10342,7 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, return true; } -} // Unnamed namespace +} // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, @@ -9436,7 +10438,6 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S, /// DiagnoseSelfMove - Emits a warning if a value is moved to itself. void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr, SourceLocation OpLoc) { - if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc)) return; @@ -9675,7 +10676,7 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) { return false; } -} +} // end anonymous namespace //===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----// @@ -9806,7 +10807,7 @@ bool GetMatchingCType( TypeInfo = I->second; return true; } -} // unnamed namespace +} // end anonymous namespace void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind, uint64_t MagicValue, QualType Type, @@ -9839,7 +10840,7 @@ bool IsSameCharType(QualType T1, QualType T2) { (T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) || (T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar); } -} // unnamed namespace +} // end anonymous namespace void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr, const Expr * const *ExprArgs) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp index 21cf62585142..36babc4bc0cd 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp @@ -19,7 +19,6 @@ #include "clang/Lex/MacroInfo.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/CodeCompleteConsumer.h" -#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" @@ -482,12 +481,37 @@ getRequiredQualification(ASTContext &Context, /// Determine whether \p Id is a name reserved for the implementation (C99 /// 7.1.3, C++ [lib.global.names]). -static bool isReservedName(const IdentifierInfo *Id) { +static bool isReservedName(const IdentifierInfo *Id, + bool doubleUnderscoreOnly = false) { if (Id->getLength() < 2) return false; const char *Name = Id->getNameStart(); return Name[0] == '_' && - (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z')); + (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z' && + !doubleUnderscoreOnly)); +} + +// Some declarations have reserved names that we don't want to ever show. +// Filter out names reserved for the implementation if they come from a +// system header. +static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) { + const IdentifierInfo *Id = ND->getIdentifier(); + if (!Id) + return false; + + // Ignore reserved names for compiler provided decls. + if (isReservedName(Id) && ND->getLocation().isInvalid()) + return true; + + // For system headers ignore only double-underscore names. + // This allows for system headers providing private symbols with a single + // underscore. + if (isReservedName(Id, /*doubleUnderscoreOnly=*/true) && + SemaRef.SourceMgr.isInSystemHeader( + SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))) + return true; + + return false; } bool ResultBuilder::isInterestingDecl(const NamedDecl *ND, @@ -514,17 +538,9 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND, // Using declarations themselves are never added as results. if (isa<UsingDecl>(ND)) return false; - - // Some declarations have reserved names that we don't want to ever show. - // Filter out names reserved for the implementation if they come from a - // system header. - // TODO: Add a predicate for this. - if (const IdentifierInfo *Id = ND->getIdentifier()) - if (isReservedName(Id) && - (ND->getLocation().isInvalid() || - SemaRef.SourceMgr.isInSystemHeader( - SemaRef.SourceMgr.getSpellingLoc(ND->getLocation())))) - return false; + + if (shouldIgnoreDueToReservedName(ND, SemaRef)) + return false; if (Filter == &ResultBuilder::IsNestedNameSpecifier || (isa<NamespaceDecl>(ND) && @@ -1518,7 +1534,6 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC, ResultBuilder &Results) { CodeCompletionAllocator &Allocator = Results.getAllocator(); CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo()); - PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef); typedef CodeCompletionResult Result; switch (CCC) { @@ -3046,6 +3061,7 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) { case Decl::ClassTemplatePartialSpecialization: return CXCursor_ClassTemplatePartialSpecialization; case Decl::UsingDirective: return CXCursor_UsingDirective; + case Decl::StaticAssert: return CXCursor_StaticAssert; case Decl::TranslationUnit: return CXCursor_TranslationUnit; case Decl::Using: @@ -3209,7 +3225,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, // We need to have names for all of the parameters, if we're going to // generate a forwarding call. - for (auto P : Method->params()) + for (auto P : Method->parameters()) if (!P->getDeclName()) return; @@ -3241,7 +3257,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext, Overridden->getNameAsString())); Builder.AddChunk(CodeCompletionString::CK_LeftParen); bool FirstParam = true; - for (auto P : Method->params()) { + for (auto P : Method->parameters()) { if (FirstParam) FirstParam = false; else @@ -3570,7 +3586,7 @@ static void AddObjCProperties(const CodeCompletionContext &CCContext, Container = getContainerDef(Container); // Add properties in this container. - for (const auto *P : Container->properties()) + for (const auto *P : Container->instance_properties()) if (AddedProperties.insert(P->getIdentifier()).second) Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr), CurContext); @@ -3812,12 +3828,19 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) { if (getLangOpts().C11 && !(DS.getTypeQualifiers() & DeclSpec::TQ_atomic)) Results.AddResult("_Atomic"); + if (getLangOpts().MSVCCompat && + !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned)) + Results.AddResult("__unaligned"); Results.ExitScope(); HandleCodeCompleteResults(this, CodeCompleter, Results.getCompletionContext(), Results.data(), Results.size()); } +void Sema::CodeCompleteBracketDeclarator(Scope *S) { + CodeCompleteExpression(S, QualType(getASTContext().getSizeType())); +} + void Sema::CodeCompleteCase(Scope *S) { if (getCurFunction()->SwitchStack.empty() || !CodeCompleter) return; @@ -6189,7 +6212,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, // Figure out which interface we're looking into. ObjCInterfaceDecl *Class = nullptr; if (ObjCImplementationDecl *ClassImpl - = dyn_cast<ObjCImplementationDecl>(Container)) + = dyn_cast<ObjCImplementationDecl>(Container)) Class = ClassImpl->getClassInterface(); else Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl() @@ -6198,8 +6221,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S, // Determine the type of the property we're synthesizing. QualType PropertyType = Context.getObjCIdType(); if (Class) { - if (ObjCPropertyDecl *Property - = Class->FindPropertyDeclaration(PropertyName)) { + if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration( + PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { PropertyType = Property->getType().getNonReferenceType().getUnqualifiedType(); @@ -7178,7 +7201,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S, Containers.push_back(Cat); for (unsigned I = 0, N = Containers.size(); I != N; ++I) - for (auto *P : Containers[I]->properties()) + for (auto *P : Containers[I]->instance_properties()) AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context, KnownSelectors, Results); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp index 4b4fd6b16a06..c8715fff4159 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp @@ -244,7 +244,7 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) { // If the expression is a temporary, materialize it as an lvalue so that we // can use it multiple times. if (E->getValueKind() == VK_RValue) - E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true); + E = CreateMaterializeTemporaryExpr(E->getType(), E, true); // Build the await_ready, await_suspend, await_resume calls. ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E); @@ -311,7 +311,7 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) { // If the expression is a temporary, materialize it as an lvalue so that we // can use it multiple times. if (E->getValueKind() == VK_RValue) - E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true); + E = CreateMaterializeTemporaryExpr(E->getType(), E, true); // Build the await_ready, await_suspend, await_resume calls. ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp index f95d1068cc59..ea276a995d81 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp @@ -47,6 +47,7 @@ #include <algorithm> #include <cstring> #include <functional> + using namespace clang; using namespace sema; @@ -88,7 +89,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback { bool AllowClassTemplates; }; -} +} // end anonymous namespace /// \brief Determine whether the token kind starts a simple-type-specifier. bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { @@ -107,6 +108,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const { case tok::kw_half: case tok::kw_float: case tok::kw_double: + case tok::kw___float128: case tok::kw_wchar_t: case tok::kw_bool: case tok::kw___underlying_type: @@ -134,7 +136,7 @@ enum class UnqualifiedTypeNameLookupResult { FoundNonType, FoundType }; -} // namespace +} // end anonymous namespace /// \brief Tries to perform unqualified lookup of the type decls in bases for /// dependent class. @@ -161,11 +163,17 @@ lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II, auto *TD = TST->getTemplateName().getAsTemplateDecl(); if (!TD) continue; - auto *BasePrimaryTemplate = - dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl()); - if (!BasePrimaryTemplate) - continue; - BaseRD = BasePrimaryTemplate; + if (auto *BasePrimaryTemplate = + dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl())) { + if (BasePrimaryTemplate->getCanonicalDecl() != RD->getCanonicalDecl()) + BaseRD = BasePrimaryTemplate; + else if (auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) { + if (const ClassTemplatePartialSpecializationDecl *PS = + CTD->findPartialSpecialization(Base.getType())) + if (PS->getCanonicalDecl() != RD->getCanonicalDecl()) + BaseRD = PS; + } + } } if (BaseRD) { for (NamedDecl *ND : BaseRD->lookup(&II)) { @@ -207,7 +215,7 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S, FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD); } if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType) - return ParsedType(); + return nullptr; // We found some types in dependent base classes. Recover as if the user // wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the @@ -266,25 +274,25 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // We therefore do not perform any name lookup if the result would // refer to a member of an unknown specialization. if (!isClassName && !IsCtorOrDtorName) - return ParsedType(); - + return nullptr; + // We know from the grammar that this name refers to a type, // so build a dependent node to describe the type. if (WantNontrivialTypeSourceInfo) return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get(); - + NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context); QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc, II, NameLoc); return ParsedType::make(T); } - - return ParsedType(); + + return nullptr; } - + if (!LookupCtx->isDependentContext() && RequireCompleteDeclContext(*SS, LookupCtx)) - return ParsedType(); + return nullptr; } // FIXME: LookupNestedNameSpecifierName isn't the right kind of @@ -302,7 +310,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, if (ObjectTypePtr && Result.empty()) { // C++ [basic.lookup.classref]p3: // If the unqualified-id is ~type-name, the type-name is looked up - // in the context of the entire postfix-expression. If the type T of + // in the context of the entire postfix-expression. If the type T of // the object expression is of a class type C, the type-name is also // looked up in the scope of class C. At least one of the lookups shall // find a name that refers to (possibly cv-qualified) T. @@ -346,8 +354,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // identifier is not a template (typo correction for template names // is handled elsewhere). !(getLangOpts().CPlusPlus && NewSSPtr && - isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(), - false, Template, MemberOfUnknownSpecialization))) { + isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false, + Template, MemberOfUnknownSpecialization))) { ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr, isClassName, HasTrailingDot, ObjectTypePtr, IsCtorOrDtorName, @@ -367,7 +375,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: Result.suppressDiagnostics(); - return ParsedType(); + return nullptr; case LookupResult::Ambiguous: // Recover from type-hiding ambiguities by hiding the type. We'll @@ -377,7 +385,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // that only makes sense if the identifier was treated like a type. if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) { Result.suppressDiagnostics(); - return ParsedType(); + return nullptr; } // Look to see if we have a type anywhere in the list of results. @@ -399,7 +407,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // will produce the ambiguity, or will complain that it expected // a type name. Result.suppressDiagnostics(); - return ParsedType(); + return nullptr; } // We found a type within the ambiguous lookup; diagnose the @@ -430,7 +438,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, // Construct a type with type-source information. TypeLocBuilder Builder; Builder.pushTypeSpec(T).setNameLoc(NameLoc); - + T = getElaboratedType(ETK_None, *SS, T); ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T); ElabTL.setElaboratedKeywordLoc(SourceLocation()); @@ -449,7 +457,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc, if (T.isNull()) { // If it's not plausibly a type, suppress diagnostics. Result.suppressDiagnostics(); - return ParsedType(); + return nullptr; } return ParsedType::make(T); } @@ -471,17 +479,53 @@ synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) { llvm_unreachable("something isn't in TU scope?"); } -ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II, - SourceLocation NameLoc) { - // Accepting an undeclared identifier as a default argument for a template - // type parameter is a Microsoft extension. - Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; +/// Find the parent class with dependent bases of the innermost enclosing method +/// context. Do not look for enclosing CXXRecordDecls directly, or we will end +/// up allowing unqualified dependent type names at class-level, which MSVC +/// correctly rejects. +static const CXXRecordDecl * +findRecordWithDependentBasesOfEnclosingMethod(const DeclContext *DC) { + for (; DC && DC->isDependentContext(); DC = DC->getLookupParent()) { + DC = DC->getPrimaryContext(); + if (const auto *MD = dyn_cast<CXXMethodDecl>(DC)) + if (MD->getParent()->hasAnyDependentBases()) + return MD->getParent(); + } + return nullptr; +} + +ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II, + SourceLocation NameLoc, + bool IsTemplateTypeArg) { + assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode"); + + NestedNameSpecifier *NNS = nullptr; + if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) { + // If we weren't able to parse a default template argument, delay lookup + // until instantiation time by making a non-dependent DependentTypeName. We + // pretend we saw a NestedNameSpecifier referring to the current scope, and + // lookup is retried. + // FIXME: This hurts our diagnostic quality, since we get errors like "no + // type named 'Foo' in 'current_namespace'" when the user didn't write any + // name specifiers. + NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext); + Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II; + } else if (const CXXRecordDecl *RD = + findRecordWithDependentBasesOfEnclosingMethod(CurContext)) { + // Build a DependentNameType that will perform lookup into RD at + // instantiation time. + NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(), + RD->getTypeForDecl()); + + // Diagnose that this identifier was undeclared, and retry the lookup during + // template instantiation. + Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II + << RD; + } else { + // This is not a situation that we should recover from. + return ParsedType(); + } - // Build a fake DependentNameType that will perform lookup into CurContext at - // instantiation time. The name specifier isn't dependent, so template - // instantiation won't transform it. It will retry the lookup, however. - NestedNameSpecifier *NNS = - synthesizeCurrentNestedNameSpecifier(Context, CurContext); QualType T = Context.getDependentNameType(ETK_None, NNS, &II); // Build type location information. We synthesized the qualifier, so we have @@ -548,7 +592,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) { if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType())) return true; return S->isFunctionPrototypeScope(); - } + } return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope(); } @@ -559,8 +603,8 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, ParsedType &SuggestedType, bool AllowClassTemplates) { // We don't have anything to suggest (yet). - SuggestedType = ParsedType(); - + SuggestedType = nullptr; + // There may have been a typo in the name of the type. Look up typo // results, in case we have something that we can suggest. if (TypoCorrection Corrected = @@ -592,11 +636,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, if (Corrected.getCorrectionSpecifier()) tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(), SourceRange(IILoc)); - SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), - IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false, - false, ParsedType(), - /*IsCtorOrDtorName=*/false, - /*NonTrivialTypeSourceInfo=*/true); + SuggestedType = + getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S, + tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr, + /*IsCtorOrDtorName=*/false, + /*NonTrivialTypeSourceInfo=*/true); } return; } @@ -609,7 +653,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, TemplateTy TemplateResult; bool MemberOfUnknownSpecialization; if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false, - Name, ParsedType(), true, TemplateResult, + Name, nullptr, true, TemplateResult, MemberOfUnknownSpecialization) == TNK_Type_template) { TemplateName TplName = TemplateResult.get(); Diag(IILoc, diag::err_template_missing_args) << TplName; @@ -623,11 +667,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, // FIXME: Should we move the logic that tries to recover from a missing tag // (struct, union, enum) from Parser::ParseImplicitInt here, instead? - + if (!SS || (!SS->isSet() && !SS->isInvalid())) Diag(IILoc, diag::err_unknown_typename) << II; else if (DeclContext *DC = computeDeclContext(*SS, false)) - Diag(IILoc, diag::err_typename_nested_not_found) + Diag(IILoc, diag::err_typename_nested_not_found) << II << DC << SS->getRange(); else if (isDependentScopeSpecifier(*SS)) { unsigned DiagID = diag::err_typename_missing; @@ -641,25 +685,25 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II, SuggestedType = ActOnTypenameType(S, SourceLocation(), *SS, *II, IILoc).get(); } else { - assert(SS && SS->isInvalid() && + assert(SS && SS->isInvalid() && "Invalid scope specifier has already been diagnosed"); } } /// \brief Determine whether the given result set contains either a type name -/// or +/// or static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) { bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus && NextToken.is(tok::less); - + for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) { if (isa<TypeDecl>(*I) || isa<ObjCInterfaceDecl>(*I)) return true; - + if (CheckTemplate && isa<TemplateDecl>(*I)) return true; } - + return false; } @@ -751,7 +795,7 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, return TypeInBase; } - // Perform lookup for Objective-C instance variables (including automatically + // Perform lookup for Objective-C instance variables (including automatically // synthesized instance variables), if we're in an Objective-C method. // FIXME: This lookup really, really needs to be folded in to the normal // unqualified lookup mechanism. @@ -760,10 +804,10 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name, if (E.get() || E.isInvalid()) return E; } - + bool SecondTry = false; bool IsFilteredTemplateName = false; - + Corrected: switch (Result.getResultKind()) { case LookupResult::NotFound: @@ -774,18 +818,18 @@ Corrected: // FIXME: Reference? if (getLangOpts().CPlusPlus) return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true); - + // C90 6.3.2.2: - // If the expression that precedes the parenthesized argument list in a - // function call consists solely of an identifier, and if no - // declaration is visible for this identifier, the identifier is + // If the expression that precedes the parenthesized argument list in a + // function call consists solely of an identifier, and if no + // declaration is visible for this identifier, the identifier is // implicitly declared exactly as if, in the innermost block containing // the function call, the declaration // - // extern int identifier (); + // extern int identifier (); + // + // appeared. // - // appeared. - // // We also allow this in C99 as an extension. if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) { Result.addDecl(D); @@ -793,9 +837,9 @@ Corrected: return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false); } } - - // In C, we first see whether there is a tag type by the same name, in - // which case it's likely that the user just forgot to write "enum", + + // In C, we first see whether there is a tag type by the same name, in + // which case it's likely that the user just forgot to write "enum", // "struct", or "union". if (!getLangOpts().CPlusPlus && !SecondTry && isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) { @@ -807,7 +851,7 @@ Corrected: if (!SecondTry && CCC) { SecondTry = true; if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(), - Result.getLookupKind(), S, + Result.getLookupKind(), S, &SS, std::move(CCC), CTK_ErrorRecovery)) { unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest; @@ -819,8 +863,8 @@ Corrected: UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) { UnqualifiedDiag = diag::err_no_template_suggest; QualifiedDiag = diag::err_no_member_template_suggest; - } else if (UnderlyingFirstDecl && - (isa<TypeDecl>(UnderlyingFirstDecl) || + } else if (UnderlyingFirstDecl && + (isa<TypeDecl>(UnderlyingFirstDecl) || isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) || isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) { UnqualifiedDiag = diag::err_unknown_typename_suggest; @@ -861,28 +905,28 @@ Corrected: ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier())); return E; } - + goto Corrected; } } - + // We failed to correct; just fall through and let the parser deal with it. Result.suppressDiagnostics(); return NameClassification::Unknown(); - + case LookupResult::NotFoundInCurrentInstantiation: { - // We performed name lookup into the current instantiation, and there were + // We performed name lookup into the current instantiation, and there were // dependent bases, so we treat this result the same way as any other // dependent nested-name-specifier. - + // C++ [temp.res]p2: - // A name used in a template declaration or definition and that is - // dependent on a template-parameter is assumed not to name a type - // unless the applicable name lookup finds a type name or the name is + // A name used in a template declaration or definition and that is + // dependent on a template-parameter is assumed not to name a type + // unless the applicable name lookup finds a type name or the name is // qualified by the keyword typename. // // FIXME: If the next token is '<', we might want to ask the parser to - // perform some heroics to see if we actually have a + // perform some heroics to see if we actually have a // template-argument-list, which would indicate a missing 'template' // keyword here. return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(), @@ -894,7 +938,7 @@ Corrected: case LookupResult::FoundOverloaded: case LookupResult::FoundUnresolvedValue: break; - + case LookupResult::Ambiguous: if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && hasAnyAcceptableTemplateNames(Result)) { @@ -915,29 +959,29 @@ Corrected: break; } } - + // Diagnose the ambiguity and return an error. return NameClassification::Error(); } - + if (getLangOpts().CPlusPlus && NextToken.is(tok::less) && (IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) { // C++ [temp.names]p3: // After name lookup (3.4) finds that a name is a template-name or that // an operator-function-id or a literal- operator-id refers to a set of - // overloaded functions any member of which is a function template if + // overloaded functions any member of which is a function template if // this is followed by a <, the < is always taken as the delimiter of a // template-argument-list and never as the less-than operator. if (!IsFilteredTemplateName) FilterAcceptableTemplateNames(Result); - + if (!Result.empty()) { bool IsFunctionTemplate; bool IsVarTemplate; TemplateName Template; if (Result.end() - Result.begin() > 1) { IsFunctionTemplate = true; - Template = Context.getOverloadedTemplateName(Result.begin(), + Template = Context.getOverloadedTemplateName(Result.begin(), Result.end()); } else { TemplateDecl *TD @@ -946,19 +990,19 @@ Corrected: IsVarTemplate = isa<VarTemplateDecl>(TD); if (SS.isSet() && !SS.isInvalid()) - Template = Context.getQualifiedTemplateName(SS.getScopeRep(), + Template = Context.getQualifiedTemplateName(SS.getScopeRep(), /*TemplateKeyword=*/false, TD); else Template = TemplateName(TD); } - + if (IsFunctionTemplate) { // Function templates always go through overload resolution, at which // point we'll perform the various checks (e.g., accessibility) we need // to based on which function we selected. Result.suppressDiagnostics(); - + return NameClassification::FunctionTemplate(Template); } @@ -984,17 +1028,17 @@ Corrected: dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl)) Class = Alias->getClassInterface(); } - + if (Class) { DiagnoseUseOfDecl(Class, NameLoc); - + if (NextToken.is(tok::period)) { // Interface. <something> is parsed as a property reference expression. // Just return "unknown" as a fall-through for now. Result.suppressDiagnostics(); return NameClassification::Unknown(); } - + QualType T = Context.getObjCInterfaceType(Class); return ParsedType::make(T); } @@ -1018,7 +1062,7 @@ Corrected: return buildNestedType(*this, SS, T, NameLoc); return ParsedType::make(T); } - + if (FirstDecl->isCXXClassMember()) return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result, nullptr, S); @@ -1035,15 +1079,15 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) { // Functions defined inline within classes aren't parsed until we've // finished parsing the top-level class, so the top-level class is // the context we'll need to return to. - // A Lambda call operator whose parent is a class must not be treated + // A Lambda call operator whose parent is a class must not be treated // as an inline member function. A Lambda can be used legally // either as an in-class member initializer or a default argument. These // are parsed once the class has been marked complete and so the containing // context would be the nested class (when the lambda is defined in one); - // If the class is not complete, then the lambda is being used in an + // If the class is not complete, then the lambda is being used in an // ill-formed fashion (such as to specify the width of a bit-field, or - // in an array-bound) - in which case we still want to return the - // lexically containing DC (which could be a nested class). + // in an array-bound) - in which case we still want to return the + // lexically containing DC (which could be a nested class). if (isa<FunctionDecl>(DC) && !isLambdaCallOperator(DC)) { DC = DC->getLexicalParent(); @@ -1143,7 +1187,6 @@ void Sema::ExitDeclaratorContext(Scope *S) { // disappear. } - void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { // We assume that the caller has already called // ActOnReenterTemplateScope so getTemplatedDecl() works. @@ -1168,7 +1211,6 @@ void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) { } } - void Sema::ActOnExitFunctionContext() { // Same implementation as PopDeclContext, but returns to the lexical parent, // rather than the top-level class. @@ -1177,7 +1219,6 @@ void Sema::ActOnExitFunctionContext() { assert(CurContext && "Popped translation unit!"); } - /// \brief Determine whether we allow overloading of the function /// PrevDecl with another declaration. /// @@ -1226,7 +1267,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { cast<FunctionDecl>(D)->isFunctionTemplateSpecialization()) return; - // If this replaces anything in the current scope, + // If this replaces anything in the current scope, IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()), IEnd = IdResolver.end(); for (; I != IEnd; ++I) { @@ -1240,7 +1281,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } S->AddDecl(D); - + if (isa<LabelDecl>(D) && !cast<LabelDecl>(D)->isGnuLocal()) { // Implicitly-generated labels may end up getting generated in an order that // isn't strictly lexical, which breaks name lookup. Be careful to insert @@ -1253,7 +1294,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) { } else if (IDC->Encloses(CurContext)) break; } - + IdResolver.InsertDeclAfter(I, D); } else { IdResolver.AddDecl(D); @@ -1416,6 +1457,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const { if (VD->isStaticDataMember() && VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation) return false; + + if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation())) + return false; } else { return false; } @@ -1469,7 +1513,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { if (isa<TypedefNameDecl>(D)) return true; - + // White-list anything that isn't a local variable. if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D)) return false; @@ -1487,7 +1531,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { } // If we failed to complete the type for some reason, or if the type is - // dependent, don't diagnose the variable. + // dependent, don't diagnose the variable. if (Ty->isIncompleteType() || Ty->isDependentType()) return false; @@ -1517,7 +1561,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) { // TODO: __attribute__((unused)) templates? } - + return true; } @@ -1531,7 +1575,6 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx, Hint = FixItHint::CreateRemoval(CharSourceRange:: getCharRange(D->getLocStart(), AfterColon)); } - return; } void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) { @@ -1558,7 +1601,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) { UnusedLocalTypedefNameCandidates.insert(TD); return; } - + FixItHint Hint; GenerateFixForUnusedDecl(D, Context, Hint); @@ -1608,13 +1651,23 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) { if (const auto *RD = dyn_cast<RecordDecl>(D)) DiagnoseUnusedNestedTypedefs(RD); } - + // If this was a forward reference to a label, verify it was defined. if (LabelDecl *LD = dyn_cast<LabelDecl>(D)) CheckPoppedLabel(LD, *this); - - // Remove this name from our lexical scope. + + // Remove this name from our lexical scope, and warn on it if we haven't + // already. IdResolver.RemoveDecl(D); + auto ShadowI = ShadowingDecls.find(D); + if (ShadowI != ShadowingDecls.end()) { + if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) { + Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field) + << D << FD << FD->getParent(); + Diag(FD->getLocation(), diag::note_previous_declaration); + } + ShadowingDecls.erase(ShadowI); + } } } @@ -1697,7 +1750,7 @@ static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S, if (!II->isStr("objc_msgSendSuper")) return; ASTContext &Context = ThisSema.Context; - + LookupResult Result(ThisSema, &Context.Idents.get("objc_super"), SourceLocation(), Sema::LookupTagName); ThisSema.LookupName(Result, S); @@ -1748,6 +1801,9 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID, << Context.BuiltinInfo.getName(ID); } + if (R.isNull()) + return nullptr; + DeclContext *Parent = Context.getTranslationUnitDecl(); if (getLangOpts().CPlusPlus) { LinkageSpecDecl *CLinkageDecl = @@ -1855,13 +1911,13 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) { if (Old->getLocation().isValid()) Diag(Old->getLocation(), diag::note_previous_definition); New->setInvalidDecl(); - return true; + return true; } - + if (OldType != NewType && !OldType->isDependentType() && !NewType->isDependentType() && - !Context.hasSameType(OldType, NewType)) { + !Context.hasSameType(OldType, NewType)) { int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0; Diag(New->getLocation(), diag::err_redefinition_different_typedef) << Kind << NewType << OldType; @@ -2000,7 +2056,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, return; // C++0x [dcl.typedef]p4: - // In a given class scope, a typedef specifier can be used to redefine + // In a given class scope, a typedef specifier can be used to redefine // any class-name declared in that scope that is not also a typedef-name // to refer to the type to which it already refers. // @@ -2032,7 +2088,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New, // Modules always permit redefinition of typedefs, as does C11. if (getLangOpts().Modules || getLangOpts().C11) return; - + // If we have a redefinition of a typedef in C, emit a warning. This warning // is normally mapped to an error, but can be controlled with // -Wtypedef-redefinition. If either the original or the redefinition is @@ -2194,9 +2250,11 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, unsigned AttrSpellingListIndex = Attr->getSpellingListIndex(); if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr)) NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(), - AA->getIntroduced(), AA->getDeprecated(), + AA->isImplicit(), AA->getIntroduced(), + AA->getDeprecated(), AA->getObsoleted(), AA->getUnavailable(), - AA->getMessage(), AMK, + AA->getMessage(), AA->getStrict(), + AA->getReplacement(), AMK, AttrSpellingListIndex); else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr)) NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(), @@ -2252,6 +2310,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D, if (NewAttr) { NewAttr->setInherited(true); D->addAttr(NewAttr); + if (isa<MSInheritanceAttr>(NewAttr)) + S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); return true; } @@ -2267,11 +2327,8 @@ static const Decl *getDefinition(const Decl *D) { return Def; return VD->getActingDefinition(); } - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { - const FunctionDecl* Def; - if (FD->isDefined(Def)) - return Def; - } + if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getDefinition(); return nullptr; } @@ -2296,7 +2353,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { for (unsigned I = 0, E = NewAttributes.size(); I != E;) { const Attr *NewAttribute = NewAttributes[I]; - if (isa<AliasAttr>(NewAttribute)) { + if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) { if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) { Sema::SkipBodyInfo SkipBody; S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody); @@ -2339,7 +2396,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { ++I; continue; } else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) { - if (AA->isAlignas()) { + if (AA->isAlignas()) { // C++11 [dcl.align]p6: // if any declaration of an entity has an alignment-specifier, // every defining declaration of that entity shall specify an @@ -2396,6 +2453,24 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old, } } + // Re-declaration cannot add abi_tag's. + if (const auto *NewAbiTagAttr = New->getAttr<AbiTagAttr>()) { + if (const auto *OldAbiTagAttr = Old->getAttr<AbiTagAttr>()) { + for (const auto &NewTag : NewAbiTagAttr->tags()) { + if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(), + NewTag) == OldAbiTagAttr->tags_end()) { + Diag(NewAbiTagAttr->getLocation(), + diag::err_new_abi_tag_on_redeclaration) + << NewTag; + Diag(OldAbiTagAttr->getLocation(), diag::note_previous_declaration); + } + } + } else { + Diag(NewAbiTagAttr->getLocation(), diag::err_abi_tag_on_redeclaration); + Diag(Old->getLocation(), diag::note_previous_declaration); + } + } + if (!Old->hasAttrs()) return; @@ -2519,7 +2594,7 @@ struct GNUCompatibleParamWarning { QualType PromotedType; }; -} +} // end anonymous namespace /// getSpecialMember - get the special member enum for a method. Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) { @@ -2799,11 +2874,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, Diag(OldLocation, diag::note_previous_declaration); return true; } - + NewTypeInfo = NewTypeInfo.withProducesResult(true); RequiresAdjustment = true; } - + if (RequiresAdjustment) { const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>(); AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo); @@ -2956,11 +3031,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD, NewMethod->setImplicit(); } else { Diag(NewMethod->getLocation(), - diag::err_definition_of_implicitly_declared_member) + diag::err_definition_of_implicitly_declared_member) << New << getSpecialMember(OldMethod); return true; } - } else if (OldMethod->isExplicitlyDefaulted() && !isFriend) { + } else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) { Diag(NewMethod->getLocation(), diag::err_definition_of_explicitly_defaulted_member) << getSpecialMember(OldMethod); @@ -3221,10 +3296,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old, return false; } - void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, ObjCMethodDecl *oldMethod) { - // Merge the attributes, including deprecated/unavailable AvailabilityMergeKind MergeKind = isa<ObjCProtocolDecl>(oldMethod->getDeclContext()) @@ -3245,6 +3318,22 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod, CheckObjCMethodOverride(newMethod, oldMethod); } +static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) { + assert(!S.Context.hasSameType(New->getType(), Old->getType())); + + S.Diag(New->getLocation(), New->isThisDeclarationADefinition() + ? diag::err_redefinition_different_type + : diag::err_redeclaration_different_type) + << New->getDeclName() << New->getType() << Old->getType(); + + diag::kind PrevDiag; + SourceLocation OldLocation; + std::tie(PrevDiag, OldLocation) + = getNoteDiagForInvalidRedeclaration(Old, New); + S.Diag(OldLocation, PrevDiag); + New->setInvalidDecl(); +} + /// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and /// scope as a previous declaration 'Old'. Figure out how to merge their types, /// emitting diagnostics as appropriate. @@ -3271,21 +3360,40 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, // object or function shall be identical, except that declarations for an // array object can specify array types that differ by the presence or // absence of a major array bound (8.3.4). - else if (Old->getType()->isIncompleteArrayType() && - New->getType()->isArrayType()) { - const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); - const ArrayType *NewArray = Context.getAsArrayType(New->getType()); - if (Context.hasSameType(OldArray->getElementType(), - NewArray->getElementType())) - MergedT = New->getType(); - } else if (Old->getType()->isArrayType() && - New->getType()->isIncompleteArrayType()) { + else if (Old->getType()->isArrayType() && New->getType()->isArrayType()) { const ArrayType *OldArray = Context.getAsArrayType(Old->getType()); const ArrayType *NewArray = Context.getAsArrayType(New->getType()); - if (Context.hasSameType(OldArray->getElementType(), - NewArray->getElementType())) - MergedT = Old->getType(); - } else if (New->getType()->isObjCObjectPointerType() && + + // 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()) { + for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD; + PrevVD = PrevVD->getPreviousDecl()) { + const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType()); + if (PrevVDTy->isIncompleteArrayType()) + continue; + + if (!Context.hasSameType(NewArray, PrevVDTy)) + return diagnoseVarDeclTypeMismatch(*this, New, PrevVD); + } + } + + if (OldArray->isIncompleteArrayType() && NewArray->isArrayType()) { + if (Context.hasSameType(OldArray->getElementType(), + NewArray->getElementType())) + MergedT = New->getType(); + } + // FIXME: Check visibility. New is hidden but has a complete type. If New + // has no array bound, it should not inherit one from Old, if Old is not + // visible. + else if (OldArray->isArrayType() && NewArray->isIncompleteArrayType()) { + if (Context.hasSameType(OldArray->getElementType(), + NewArray->getElementType())) + MergedT = Old->getType(); + } + } + else if (New->getType()->isObjCObjectPointerType() && Old->getType()->isObjCObjectPointerType()) { MergedT = Context.mergeObjCGCQualifiers(New->getType(), Old->getType()); @@ -3311,27 +3419,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old, New->setType(Context.DependentTy); return; } - - // FIXME: Even if this merging succeeds, some other non-visible declaration - // of this variable might have an incompatible type. For instance: - // - // extern int arr[]; - // void f() { extern int arr[2]; } - // void g() { extern int arr[3]; } - // - // Neither C nor C++ requires a diagnostic for this, but we should still try - // to diagnose it. - Diag(New->getLocation(), New->isThisDeclarationADefinition() - ? diag::err_redefinition_different_type - : diag::err_redeclaration_different_type) - << New->getDeclName() << New->getType() << Old->getType(); - - diag::kind PrevDiag; - SourceLocation OldLocation; - std::tie(PrevDiag, OldLocation) = - getNoteDiagForInvalidRedeclaration(Old, New); - Diag(OldLocation, PrevDiag); - return New->setInvalidDecl(); + return diagnoseVarDeclTypeMismatch(*this, New, Old); } // Don't actually update the type on the new declaration if the old @@ -3425,17 +3513,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { // C++ [class.mem]p1: // A member shall not be declared twice in the member-specification [...] - // + // // Here, we need only consider static data members. if (Old->isStaticDataMember() && !New->isOutOfLine()) { - Diag(New->getLocation(), diag::err_duplicate_member) + Diag(New->getLocation(), diag::err_duplicate_member) << New->getIdentifier(); Diag(Old->getLocation(), diag::note_previous_declaration); New->setInvalidDecl(); } - + mergeDeclAttributes(New, Old); - // Warn if an already-declared variable is made a weak_import in a subsequent + // Warn if an already-declared variable is made a weak_import in a subsequent // declaration if (New->hasAttr<WeakImportAttr>() && Old->getStorageClass() == SC_None && @@ -3533,6 +3621,23 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { return New->setInvalidDecl(); } + if (New->isInline() && !Old->getMostRecentDecl()->isInline()) { + if (VarDecl *Def = Old->getDefinition()) { + // C++1z [dcl.fcn.spec]p4: + // If the definition of a variable appears in a translation unit before + // its first declaration as inline, the program is ill-formed. + Diag(New->getLocation(), diag::err_inline_decl_follows_def) << New; + Diag(Def->getLocation(), diag::note_previous_definition); + } + } + + // If this redeclaration makes the function inline, we may need to add it to + // UndefinedButUsed. + if (!Old->isInline() && New->isInline() && Old->isUsed(false) && + !Old->getDefinition() && !New->isThisDeclarationADefinition()) + UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(), + SourceLocation())); + if (New->getTLSKind() != Old->getTLSKind()) { if (!Old->getTLSKind()) { Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName(); @@ -3564,6 +3669,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { 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()) { + // 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); @@ -3592,13 +3703,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) { New->setAccess(Old->getAccess()); if (NewTemplate) NewTemplate->setAccess(New->getAccess()); + + if (Old->isInline()) + New->setImplicitlyInline(); } /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. -Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS) { - return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg()); +Decl * +Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + RecordDecl *&AnonRecord) { + return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false, + AnonRecord); } // The MS ABI changed between VS2013 and VS2015 with regard to numbers used to @@ -3704,10 +3820,11 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) { /// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with /// no declarator (e.g. "struct foo;") is parsed. It also accepts template /// parameters to cope with template friend declarations. -Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, - DeclSpec &DS, - MultiTemplateParamsArg TemplateParams, - bool IsExplicitInstantiation) { +Decl * +Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS, + MultiTemplateParamsArg TemplateParams, + bool IsExplicitInstantiation, + RecordDecl *&AnonRecord) { Decl *TagD = nullptr; TagDecl *Tag = nullptr; if (DS.getTypeSpecType() == DeclSpec::TST_class || @@ -3745,6 +3862,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, << DS.getSourceRange(); } + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; + if (DS.isConstexprSpecified()) { // C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations // and definitions of functions and variables. @@ -3802,9 +3923,19 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, if (!Record->getDeclName() && Record->isCompleteDefinition() && DS.getStorageClassSpec() != DeclSpec::SCS_typedef) { if (getLangOpts().CPlusPlus || - Record->getDeclContext()->isRecord()) + Record->getDeclContext()->isRecord()) { + // If CurContext is a DeclContext that can contain statements, + // RecursiveASTVisitor won't visit the decls that + // BuildAnonymousStructOrUnion() will put into CurContext. + // Also store them here so that they can be part of the + // DeclStmt that gets created in this case. + // FIXME: Also return the IndirectFieldDecls created by + // BuildAnonymousStructOr union, for the same reason? + if (CurContext->isFunctionOrMethod()) + AnonRecord = Record; return BuildAnonymousStructOrUnion(S, DS, AS, Record, Context.getPrintingPolicy()); + } DeclaresAnything = false; } @@ -3926,6 +4057,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, // Restrict is covered above. if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic) Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic"; + if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned) + Diag(DS.getUnalignedSpecLoc(), DiagID) << "__unaligned"; } // Warn about ignored type attributes, for example: @@ -3992,12 +4125,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef, /// /// This routine is recursive, injecting the names of nested anonymous /// structs/unions into the owning context and scope as well. -static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, - DeclContext *Owner, - RecordDecl *AnonRecord, - AccessSpecifier AS, - SmallVectorImpl<NamedDecl *> &Chaining, - bool MSAnonStruct) { +static bool +InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner, + RecordDecl *AnonRecord, AccessSpecifier AS, + SmallVectorImpl<NamedDecl *> &Chaining) { bool Invalid = false; // Look every FieldDecl and IndirectFieldDecl with a name. @@ -4033,7 +4164,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(), - VD->getType(), NamedChain, Chaining.size()); + VD->getType(), {NamedChain, Chaining.size()}); for (const auto *Attr : VD->attrs()) IndirectField->addAttr(Attr->clone(SemaRef.Context)); @@ -4143,7 +4274,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, cast<NamespaceDecl>(Owner)->getDeclName()))) { Diag(Record->getLocation(), diag::err_anonymous_union_not_static) << FixItHint::CreateInsertion(Record->getLocation(), "static "); - + // Recover by adding 'static'. DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(), PrevSpec, DiagID, Policy); @@ -4156,9 +4287,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, Diag(DS.getStorageClassSpecLoc(), diag::err_anonymous_union_with_storage_spec) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); - + // Recover by removing the storage specifier. - DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, + DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified, SourceLocation(), PrevSpec, DiagID, Context.getPrintingPolicy()); } @@ -4185,6 +4316,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, diag::ext_anonymous_struct_union_qualified) << Record->isUnion() << "_Atomic" << FixItHint::CreateRemoval(DS.getAtomicSpecLoc()); + if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned) + Diag(DS.getUnalignedSpecLoc(), + diag::ext_anonymous_struct_union_qualified) + << Record->isUnion() << "__unaligned" + << FixItHint::CreateRemoval(DS.getUnalignedSpecLoc()); DS.ClearTypeQualifiers(); } @@ -4254,7 +4390,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, DK = diag::err_anonymous_record_with_function; else if (isa<VarDecl>(Mem)) DK = diag::err_anonymous_record_with_static; - + // Visual C++ allows type definition in anonymous struct or union. if (getLangOpts().MicrosoftExt && DK == diag::err_anonymous_record_with_type) @@ -4340,8 +4476,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS, SmallVector<NamedDecl*, 2> Chain; Chain.push_back(Anon); - if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, - Chain, false)) + if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain)) Invalid = true; if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) { @@ -4413,7 +4548,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS, if (RequireCompleteType(Anon->getLocation(), RecTy, diag::err_field_incomplete) || InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef, - AS_none, Chain, true)) { + AS_none, Chain)) { Anon->setInvalidDecl(); ParentDecl->setInvalidDecl(); } @@ -4662,7 +4797,7 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) { } /// DiagnoseClassNameShadow - Implement C++ [class.mem]p13: -/// If T is the name of a class, then each of the following shall have a +/// If T is the name of a class, then each of the following shall have a /// name different from T: /// - every static data member of class T; /// - every member function of class T @@ -4683,12 +4818,12 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC, return false; } -/// \brief Diagnose a declaration whose declarator-id has the given +/// \brief Diagnose a declaration whose declarator-id has the given /// nested-name-specifier. /// /// \param SS The nested-name-specifier of the declarator-id. /// -/// \param DC The declaration context to which the nested-name-specifier +/// \param DC The declaration context to which the nested-name-specifier /// resolves. /// /// \param Name The name of the entity being declared. @@ -4734,15 +4869,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, Diag(Loc, diag::err_invalid_declarator_global_scope) << Name << SS.getRange(); else if (isa<FunctionDecl>(Cur)) - Diag(Loc, diag::err_invalid_declarator_in_function) + Diag(Loc, diag::err_invalid_declarator_in_function) << Name << SS.getRange(); else if (isa<BlockDecl>(Cur)) - Diag(Loc, diag::err_invalid_declarator_in_block) + Diag(Loc, diag::err_invalid_declarator_in_block) << Name << SS.getRange(); else Diag(Loc, diag::err_invalid_declarator_scope) << Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange(); - + return true; } @@ -4751,7 +4886,7 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, Diag(Loc, diag::err_member_qualification) << Name << SS.getRange(); SS.clear(); - + // C++ constructors and destructors with incorrect scopes can break // our AST invariants by having the wrong underlying types. If // that's the case, then drop this declaration entirely. @@ -4760,10 +4895,10 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, !Context.hasSameType(Name.getCXXNameType(), Context.getTypeDeclType(cast<CXXRecordDecl>(Cur)))) return true; - + return false; } - + // C++11 [dcl.meaning]p1: // [...] "The nested-name-specifier of the qualified declarator-id shall // not begin with a decltype-specifer" @@ -4805,7 +4940,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (D.getCXXScopeSpec().isInvalid()) D.setInvalidType(); else if (D.getCXXScopeSpec().isSet()) { - if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), + if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(), UPPC_DeclarationQualifier)) return nullptr; @@ -4824,7 +4959,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, } bool IsDependentContext = DC->isDependentContext(); - if (!IsDependentContext && + if (!IsDependentContext && RequireCompleteDeclContext(D.getCXXScopeSpec(), DC)) return nullptr; @@ -4904,11 +5039,11 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, LookupQualifiedName(Previous, DC); // C++ [dcl.meaning]p1: - // When the declarator-id is qualified, the declaration shall refer to a - // previously declared member of the class or namespace to which the + // When the declarator-id is qualified, the declaration shall refer to a + // previously declared member of the class or namespace to which the // qualifier refers (or, in the case of a namespace, of an element of the // inline namespace set of that namespace (7.3.1)) or to a specialization - // thereof; [...] + // thereof; [...] // // Note that we already checked the context above, and that we do not have // enough information to make sure that Previous contains the declaration @@ -4924,10 +5059,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, // In this case, Previous will point to the overload set // containing the two f's declared in X, but neither of them // matches. - + // C++ [dcl.meaning]p1: - // [...] the member shall not merely have been introduced by a - // using-declaration in the scope of the class or namespace nominated by + // [...] the member shall not merely have been introduced by a + // using-declaration in the scope of the class or namespace nominated by // the nested-name-specifier of the declarator-id. RemoveUsingDecls(Previous); } @@ -4995,10 +5130,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, if (!New) return nullptr; - // If this has an identifier and is not an invalid redeclaration or - // function template specialization, add it to the scope stack. - if (New->getDeclName() && AddToScope && - !(D.isRedeclaration() && New->isInvalidDecl())) { + // If this has an identifier and is not a function template specialization, + // add it to the scope stack. + if (New->getDeclName() && AddToScope) { // Only make a locally-scoped extern declaration visible if it is the first // declaration of this entity. Qualified lookup for such an entity should // only find this declaration if there is no visible declaration of it. @@ -5008,6 +5142,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D, CurContext->addHiddenDecl(New); } + if (isInOpenMPDeclareTargetContext()) + checkDeclIsAllowedInOpenMPTarget(nullptr, New); + return New; } @@ -5024,10 +5161,10 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, // constant expression folding, like struct {char x[(int)(char*)2];} SizeIsNegative = false; Oversized = 0; - + if (T->isDependentType()) return QualType(); - + QualifierCollector Qs; const Type *Ty = Qs.strip(T); @@ -5076,7 +5213,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T, Oversized = Res; return QualType(); } - + return Context.getConstantArrayType(VLATy->getElementType(), Res, ArrayType::Normal, 0); } @@ -5154,11 +5291,7 @@ NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) { /// does not identify a function. void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) { // FIXME: We should probably indicate the identifier in question to avoid - // confusion for constructs like "inline int a(), b;" - if (DS.isInlineSpecified()) - Diag(DS.getInlineSpecLoc(), - diag::err_inline_non_function); - + // confusion for constructs like "virtual int a(), b;" if (DS.isVirtualSpecified()) Diag(DS.getVirtualSpecLoc(), diag::err_virtual_non_function); @@ -5187,6 +5320,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC, DiagnoseFunctionSpecifiers(D.getDeclSpec()); + if (D.getDeclSpec().isInlineSpecified()) + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (D.getDeclSpec().isConstexprSpecified()) Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr) << 1; @@ -5241,7 +5377,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { else if (T->isVariableArrayType()) Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope); else if (Oversized.getBoolValue()) - Diag(NewTD->getLocation(), diag::err_array_too_large) + Diag(NewTD->getLocation(), diag::err_array_too_large) << Oversized.toString(10); else Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope); @@ -5251,7 +5387,6 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) { } } - /// ActOnTypedefNameDecl - Perform semantic checking for a declaration which /// declares a typedef-name, either using the 'typedef' type specifier or via /// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'. @@ -5323,12 +5458,12 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC, if (!OuterContext->isFunctionOrMethod()) // This rule only applies to block-scope declarations. return false; - + DeclContext *PrevOuterContext = PrevDecl->getDeclContext(); if (PrevOuterContext->isRecord()) // We found a member function: ignore it. return false; - + // Find the innermost enclosing namespace for the new and // previous declarations. OuterContext = OuterContext->getEnclosingNamespaceContext(); @@ -5379,7 +5514,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { type = Context.getLifetimeQualifiedType(type, lifetime); decl->setType(type); } - + if (VarDecl *var = dyn_cast<VarDecl>(decl)) { // Thread-local variables cannot have lifetime. if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone && @@ -5389,7 +5524,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) { return true; } } - + return false; } @@ -5418,7 +5553,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { if (const auto *Attr = VD->getAttr<AliasAttr>()) { assert(VD->isThisDeclarationADefinition() && !VD->isExternallyVisible() && "Broken AliasAttr handled late!"); - S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD; + S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD << 0; VD->dropAttr<AliasAttr>(); } } @@ -5458,9 +5593,13 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) { static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, NamedDecl *NewDecl, - bool IsSpecialization) { - if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) + bool IsSpecialization, + bool IsDefinition) { + if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) { OldDecl = OldTD->getTemplatedDecl(); + if (!IsSpecialization) + IsDefinition = false; + } if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl)) NewDecl = NewTD->getTemplatedDecl(); @@ -5516,14 +5655,17 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, // A redeclaration is not allowed to drop a dllimport attribute, the only // exceptions being inline function definitions, local extern declarations, - // and qualified friend declarations. - // NB: MSVC converts such a declaration to dllexport. + // qualified friend declarations or special MSVC extension: in the last case, + // the declaration is treated as if it were marked dllexport. bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false; - if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) + bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft(); + if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) { // Ignore static data because out-of-line definitions are diagnosed // separately. IsStaticDataMember = VD->isStaticDataMember(); - else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) { + IsDefinition = VD->isThisDeclarationADefinition(S.Context) != + VarDecl::DeclarationOnly; + } else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) { IsInline = FD->isInlined(); IsQualifiedFriend = FD->getQualifier() && FD->getFriendObjectKind() == Decl::FOK_Declared; @@ -5531,15 +5673,25 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl, if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember && !NewDecl->isLocalExternDecl() && !IsQualifiedFriend) { - S.Diag(NewDecl->getLocation(), - diag::warn_redeclaration_without_attribute_prev_attribute_ignored) - << NewDecl << OldImportAttr; - S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); - S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); - OldDecl->dropAttr<DLLImportAttr>(); - NewDecl->dropAttr<DLLImportAttr>(); - } else if (IsInline && OldImportAttr && - !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) { + if (IsMicrosoft && IsDefinition) { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_import_attribute) + << NewDecl; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + NewDecl->dropAttr<DLLImportAttr>(); + NewDecl->addAttr(::new (S.Context) DLLExportAttr( + NewImportAttr->getRange(), S.Context, + NewImportAttr->getSpellingListIndex())); + } else { + S.Diag(NewDecl->getLocation(), + diag::warn_redeclaration_without_attribute_prev_attribute_ignored) + << NewDecl << OldImportAttr; + S.Diag(OldDecl->getLocation(), diag::note_previous_declaration); + S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute); + OldDecl->dropAttr<DLLImportAttr>(); + NewDecl->dropAttr<DLLImportAttr>(); + } + } else if (IsInline && OldImportAttr && !IsMicrosoft) { // In MinGW, seeing a function declared inline drops the dllimport attribute. OldDecl->dropAttr<DLLImportAttr>(); NewDecl->dropAttr<DLLImportAttr>(); @@ -5605,10 +5757,9 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) { if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>()) return false; - // So do CUDA's host/device attributes if overloading is enabled. - if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads && - (D->template hasAttr<CUDADeviceAttr>() || - D->template hasAttr<CUDAHostAttr>())) + // So do CUDA's host/device attributes. + if (S.getLangOpts().CUDA && (D->template hasAttr<CUDADeviceAttr>() || + D->template hasAttr<CUDAHostAttr>())) return false; } return D->isExternC(); @@ -5616,7 +5767,7 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) { static bool shouldConsiderLinkage(const VarDecl *VD) { const DeclContext *DC = VD->getDeclContext()->getRedeclContext(); - if (DC->isFunctionOrMethod()) + if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC)) return VD->hasExternalStorage(); if (DC->isFileContext()) return true; @@ -5627,7 +5778,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) { static bool shouldConsiderLinkage(const FunctionDecl *FD) { const DeclContext *DC = FD->getDeclContext()->getRedeclContext(); - if (DC->isFileContext() || DC->isFunctionOrMethod()) + if (DC->isFileContext() || DC->isFunctionOrMethod() || + isa<OMPDeclareReductionDecl>(DC)) return true; if (DC->isRecord()) return false; @@ -5701,6 +5853,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, 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(); + return nullptr; + } + DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec(); StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec()); @@ -5847,7 +6010,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, case SC_PrivateExtern: llvm_unreachable("C storage class in c++!"); } - } + } if (SC == SC_Static && CurContext->isRecord()) { if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) { @@ -5964,11 +6127,18 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewVD->setTemplateParameterListsInfo( Context, TemplateParamLists.drop_back(VDTemplateParamLists)); - if (D.getDeclSpec().isConstexprSpecified()) + if (D.getDeclSpec().isConstexprSpecified()) { NewVD->setConstexpr(true); + // C++1z [dcl.spec.constexpr]p1: + // A static data member declared with the constexpr specifier is + // implicitly an inline variable. + if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus1z) + NewVD->setImplicitlyInline(); + } if (D.getDeclSpec().isConceptSpecified()) { - NewVD->setConcept(true); + if (VarTemplateDecl *VTD = NewVD->getDescribedVarTemplate()) + VTD->setConcept(); // C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not // be declared with the thread_local, inline, friend, or constexpr @@ -5986,6 +6156,41 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, << 0 << 3; NewVD->setInvalidDecl(true); } + + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable + // template, declared in namespace scope. + if (IsVariableTemplateSpecialization) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) + << (IsPartialSpecialization ? 2 : 1); + } + + // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the + // following restrictions: + // - The declared type shall have the type bool. + if (!Context.hasSameType(NewVD->getType(), Context.BoolTy) && + !NewVD->isInvalidDecl()) { + Diag(D.getIdentifierLoc(), diag::err_variable_concept_bool_decl); + NewVD->setInvalidDecl(true); + } + } + } + + if (D.getDeclSpec().isInlineSpecified()) { + if (!getLangOpts().CPlusPlus) { + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) + << 0; + } else if (CurContext->isFunctionOrMethod()) { + // 'inline' is not allowed on block scope variable declaration. + Diag(D.getDeclSpec().getInlineSpecLoc(), + diag::err_inline_declaration_block_scope) << Name + << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); + } else { + Diag(D.getDeclSpec().getInlineSpecLoc(), + getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_inline_variable + : diag::ext_inline_variable); + NewVD->setInlineSpecified(); } } @@ -6209,6 +6414,25 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (!IsVariableTemplateSpecialization) D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous)); + // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...] + // an explicit specialization (14.8.3) or a partial specialization of a + // concept definition. + if (IsVariableTemplateSpecialization && + !D.getDeclSpec().isConceptSpecified() && !Previous.empty() && + Previous.isSingleResult()) { + NamedDecl *PreviousDecl = Previous.getFoundDecl(); + if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(PreviousDecl)) { + if (VarTmpl->isConcept()) { + Diag(NewVD->getLocation(), diag::err_concept_specialized) + << 1 /*variable*/ + << (IsPartialSpecialization ? 2 /*partially specialized*/ + : 1 /*explicitly specialized*/); + Diag(VarTmpl->getLocation(), diag::note_previous_declaration); + NewVD->setInvalidDecl(); + } + } + } + if (NewTemplate) { VarTemplateDecl *PrevVarTemplate = NewVD->getPreviousDecl() @@ -6274,7 +6498,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD, - IsExplicitSpecialization); + IsExplicitSpecialization, D.isFunctionDefinition()); } if (NewTemplate) { @@ -6287,6 +6511,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC, return NewVD; } +/// Enum describing the %select options in diag::warn_decl_shadow. +enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field }; + +/// Determine what kind of declaration we're shadowing. +static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl, + const DeclContext *OldDC) { + if (isa<RecordDecl>(OldDC)) + return isa<FieldDecl>(ShadowedDecl) ? SDK_Field : SDK_StaticMember; + return OldDC->isFileContext() ? SDK_Global : SDK_Local; +} + /// \brief Diagnose variable or built-in function shadowing. Implements /// -Wshadow. /// @@ -6315,12 +6550,23 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl)) return; - // Fields are not shadowed by variables in C++ static methods. - if (isa<FieldDecl>(ShadowedDecl)) + if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) { + // Fields are not shadowed by variables in C++ static methods. if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC)) if (MD->isStatic()) return; + // Fields shadowed by constructor parameters are a special case. Usually + // the constructor initializes the field with the parameter. + if (isa<CXXConstructorDecl>(NewDC) && isa<ParmVarDecl>(D)) { + // Remember that this was shadowed so we can either warn about its + // modification or its existence depending on warning settings. + D = D->getCanonicalDecl(); + ShadowingDecls.insert({D, FD}); + return; + } + } + if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl)) if (shadowedVar->isExternC()) { // For shadowing external vars, make sure that we point to the global @@ -6342,29 +6588,19 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) { // TODO: should we warn about static data members shadowing // static data members from base classes? - + // TODO: don't diagnose for inaccessible shadowed members. // This is hard to do perfectly because we might friend the // shadowing context, but that's just a false negative. } - // Determine what kind of declaration we're shadowing. - unsigned Kind; - if (isa<RecordDecl>(OldDC)) { - if (isa<FieldDecl>(ShadowedDecl)) - Kind = 3; // field - else - Kind = 2; // static data member - } else if (OldDC->isFileContext()) - Kind = 1; // global - else - Kind = 0; // local DeclarationName Name = R.getLookupName(); // Emit warning and note. if (getSourceManager().isInSystemMacro(R.getNameLoc())) return; + ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC); Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC; Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); } @@ -6380,6 +6616,30 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) { CheckShadow(S, D, R); } +/// Check if 'E', which is an expression that is about to be modified, refers +/// to a constructor parameter that shadows a field. +void Sema::CheckShadowingDeclModification(Expr *E, SourceLocation Loc) { + // Quickly ignore expressions that can't be shadowing ctor parameters. + if (!getLangOpts().CPlusPlus || ShadowingDecls.empty()) + return; + E = E->IgnoreParenImpCasts(); + auto *DRE = dyn_cast<DeclRefExpr>(E); + if (!DRE) + return; + const NamedDecl *D = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl()); + auto I = ShadowingDecls.find(D); + if (I == ShadowingDecls.end()) + return; + const NamedDecl *ShadowedDecl = I->second; + const DeclContext *OldDC = ShadowedDecl->getDeclContext(); + Diag(Loc, diag::warn_modifying_shadowing_decl) << D << OldDC; + Diag(D->getLocation(), diag::note_var_declared_here) << D; + Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration); + + // Avoid issuing multiple warnings about the same decl. + ShadowingDecls.erase(I); +} + /// Check for conflict between this global or extern "C" declaration and /// previous global or extern "C" declarations. This is only used in C++. template<typename T> @@ -6530,7 +6790,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } - // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program + // OpenCL v1.2 s6.8 - The static qualifier is valid only in program // scope. if (getLangOpts().OpenCLVersion == 120 && !getOpenCLOptions().cl_clang_storage_class_specifiers && @@ -6540,40 +6800,64 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { return; } - // OpenCL v1.2 s6.5 - All program scope variables must be declared in the - // __constant address space. - // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static - // variables inside a function can also be declared in the global - // address space. if (getLangOpts().OpenCL) { - if (NewVD->isFileVarDecl()) { + // OpenCL v2.0 s6.12.5 - The __block storage type is not supported. + if (NewVD->hasAttr<BlocksAttr>()) { + Diag(NewVD->getLocation(), diag::err_opencl_block_storage_type); + return; + } + + if (T->isBlockPointerType()) { + // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and + // can't use 'extern' storage class. + if (!T.isConstQualified()) { + Diag(NewVD->getLocation(), diag::err_opencl_invalid_block_declaration) + << 0 /*const*/; + NewVD->setInvalidDecl(); + return; + } + if (NewVD->hasExternalStorage()) { + Diag(NewVD->getLocation(), diag::err_opencl_extern_block_declaration); + 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. + // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static + // variables inside a function can also be declared in the global + // address space. + if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() || + NewVD->hasExternalStorage()) { if (!T->isSamplerT() && !(T.getAddressSpace() == LangAS::opencl_constant || (T.getAddressSpace() == LangAS::opencl_global && getLangOpts().OpenCLVersion == 200))) { + int Scope = NewVD->isStaticLocal() | NewVD->hasExternalStorage() << 1; if (getLangOpts().OpenCLVersion == 200) Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) - << "global or constant"; + << Scope << "global or constant"; else Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) - << "constant"; + << Scope << "constant"; NewVD->setInvalidDecl(); return; } } else { - // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static - // variables inside a function can also be declared in the global - // address space. - if (NewVD->isStaticLocal() && - !(T.getAddressSpace() == LangAS::opencl_constant || - (T.getAddressSpace() == LangAS::opencl_global && - getLangOpts().OpenCLVersion == 200))) { - if (getLangOpts().OpenCLVersion == 200) - Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) - << "global or constant"; - else - Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space) - << "constant"; + if (T.getAddressSpace() == LangAS::opencl_global) { + Diag(NewVD->getLocation(), diag::err_opencl_function_variable) + << 1 /*is any function*/ << "global"; NewVD->setInvalidDecl(); return; } @@ -6584,11 +6868,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { FunctionDecl *FD = getCurFunctionDecl(); if (FD && !FD->hasAttr<OpenCLKernelAttr>()) { if (T.getAddressSpace() == LangAS::opencl_constant) - Diag(NewVD->getLocation(), diag::err_opencl_non_kernel_variable) - << "constant"; + Diag(NewVD->getLocation(), diag::err_opencl_function_variable) + << 0 /*non-kernel only*/ << "constant"; else - Diag(NewVD->getLocation(), diag::err_opencl_non_kernel_variable) - << "local"; + Diag(NewVD->getLocation(), diag::err_opencl_function_variable) + << 0 /*non-kernel only*/ << "local"; NewVD->setInvalidDecl(); return; } @@ -6605,7 +6889,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) { Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local); } } - + bool isVM = T->isVariablyModifiedType(); if (isVM || NewVD->hasAttr<CleanupAttr>() || NewVD->hasAttr<BlocksAttr>()) @@ -6821,7 +7105,7 @@ namespace { MultiTemplateParamsArg TemplateParamLists; bool AddToScope; }; -} +} // end anonymous namespace namespace { @@ -6865,7 +7149,7 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback { CXXRecordDecl *ExpectedParent; }; -} +} // end anonymous namespace /// \brief Generate diagnostics for an invalid function redeclaration. /// @@ -7072,9 +7356,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D, (D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) || (!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType()); - NewFD = FunctionDecl::Create(SemaRef.Context, DC, - D.getLocStart(), NameInfo, R, - TInfo, SC, isInline, + NewFD = FunctionDecl::Create(SemaRef.Context, DC, + D.getLocStart(), NameInfo, R, + TInfo, SC, isInline, HasPrototype, false); if (D.isInvalidType()) NewFD->setInvalidDecl(); @@ -7483,8 +7767,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(NewFD->getLocation(), diag::err_destructor_template); NewFD->setInvalidDecl(); } - - // If we're adding a template to a dependent context, we may need to + + // 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 (DC->isDependentContext()) { @@ -7492,7 +7776,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams)) Invalid = true; } - FunctionTemplate = FunctionTemplateDecl::Create(Context, DC, NewFD->getLocation(), @@ -7561,7 +7844,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::err_virtual_non_function); } else if (!CurContext->isRecord()) { // 'virtual' was specified outside of the class. - Diag(D.getDeclSpec().getVirtualSpecLoc(), + Diag(D.getDeclSpec().getVirtualSpecLoc(), diag::err_virtual_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc()); } else if (NewFD->getDescribedFunctionTemplate()) { @@ -7599,12 +7882,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } // C++ [dcl.fct.spec]p3: - // The inline specifier shall not appear on a block scope function + // The inline specifier shall not appear on a block scope function // declaration. if (isInline && !NewFD->isInvalidDecl()) { if (CurContext->isFunctionOrMethod()) { // 'inline' is not allowed on block scope function declaration. - Diag(D.getDeclSpec().getInlineSpecLoc(), + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_declaration_block_scope) << Name << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc()); } @@ -7612,22 +7895,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++ [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of a - // constructor or conversion function within its class definition; + // constructor or conversion function within its class definition; // see 12.3.1 and 12.3.2. if (isExplicit && !NewFD->isInvalidDecl()) { if (!CurContext->isRecord()) { // 'explicit' was specified outside of the class. - Diag(D.getDeclSpec().getExplicitSpecLoc(), + Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_out_of_class) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } else if (!isa<CXXConstructorDecl>(NewFD) && + } else if (!isa<CXXConstructorDecl>(NewFD) && !isa<CXXConversionDecl>(NewFD)) { // 'explicit' was specified on a function that wasn't a constructor // or conversion function. Diag(D.getDeclSpec().getExplicitSpecLoc(), diag::err_explicit_non_ctor_or_conv_function) << FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc()); - } + } } if (isConstexpr) { @@ -7643,6 +7926,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } if (isConcept) { + // This is a function concept. + if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate()) + FTD->setConcept(); + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be // applied only to the definition of a function template [...] if (!D.isFunctionDefinition()) { @@ -7668,6 +7955,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the // following restrictions: + // - The declared return type shall have the type bool. + if (!Context.hasSameType(FPT->getReturnType(), Context.BoolTy)) { + Diag(D.getIdentifierLoc(), diag::err_function_concept_bool_ret); + NewFD->setInvalidDecl(); + } + + // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the + // following restrictions: // - The declaration's parameter list shall be equivalent to an empty // parameter list. if (FPT->getNumParams() > 0 || FPT->isVariadic()) @@ -7701,6 +7996,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << 1 << 3; NewFD->setInvalidDecl(true); } + + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable + // template, declared in namespace scope. + if (isFunctionTemplateSpecialization) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) << 1; + NewFD->setInvalidDecl(true); + return NewFD; + } } // If __module_private__ was specified, mark the function accordingly. @@ -7734,11 +8039,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, case FDK_Declaration: case FDK_Definition: break; - + case FDK_Defaulted: NewFD->setDefaulted(); break; - + case FDK_Deleted: NewFD->setDeletedAsWritten(); break; @@ -7747,7 +8052,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (isa<CXXMethodDecl>(NewFD) && DC == CurContext && D.isFunctionDefinition()) { // C++ [class.mfct]p2: - // A member function may be defined (8.4) in its class definition, in + // A member function may be defined (8.4) in its class definition, in // which case it is an inline member function (7.1.2) NewFD->setImplicitlyInline(); } @@ -7825,7 +8130,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setInvalidDecl(); } } - } 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) @@ -7890,6 +8194,9 @@ 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. @@ -7952,7 +8259,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, diag::ext_operator_new_delete_declared_inline) << NewFD->getDeclName(); - // If the declarator is a template-id, translate the parser's template + // If the declarator is a template-id, translate the parser's template // argument list into our AST format. if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) { TemplateIdAnnotation *TemplateId = D.getName().TemplateId; @@ -7962,9 +8269,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, TemplateId->NumArgs); translateTemplateArguments(TemplateArgsPtr, TemplateArgs); - + HasExplicitTemplateArgs = true; - + if (NewFD->isInvalidDecl()) { HasExplicitTemplateArgs = false; } else if (FunctionTemplate) { @@ -8000,7 +8307,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (isFunctionTemplateSpecialization && isFriend && (NewFD->getType()->isDependentType() || DC->isDependentContext() || TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), TemplateArgs.size(), + TemplateArgs, InstantiationDependent))) { assert(HasExplicitTemplateArgs && "friend function specialization without template args"); @@ -8008,10 +8315,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Previous)) NewFD->setInvalidDecl(); } else if (isFunctionTemplateSpecialization) { - if (CurContext->isDependentContext() && CurContext->isRecord() + if (CurContext->isDependentContext() && CurContext->isRecord() && !isFriend) { isDependentClassScopeExplicitSpecialization = true; - Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? + Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ? diag::ext_function_specialization_in_class : diag::err_function_specialization_in_class) << NewFD->getDeclName(); @@ -8020,7 +8327,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, : nullptr), Previous)) NewFD->setInvalidDecl(); - + // C++ [dcl.stc]p1: // A storage-class-specifier shall not be specified in an explicit // specialization (14.7.3) @@ -8033,14 +8340,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, << SC << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); - + else - Diag(NewFD->getLocation(), + Diag(NewFD->getLocation(), diag::ext_explicit_specialization_storage_class) << FixItHint::CreateRemoval( D.getDeclSpec().getStorageClassSpecLoc()); } - } else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) { if (CheckMemberSpecialization(NewFD, Previous)) NewFD->setInvalidDecl(); @@ -8086,7 +8392,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // If we have a function template, check the template parameter // list. This will check and merge default template arguments. if (FunctionTemplate) { - FunctionTemplateDecl *PrevTemplate = + FunctionTemplateDecl *PrevTemplate = FunctionTemplate->getPreviousDecl(); CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(), PrevTemplate ? PrevTemplate->getTemplateParameters() @@ -8095,8 +8401,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, ? (D.isFunctionDefinition() ? TPC_FriendFunctionTemplateDefinition : TPC_FriendFunctionTemplate) - : (D.getCXXScopeSpec().isSet() && - DC && DC->isRecord() && + : (D.getCXXScopeSpec().isSet() && + DC && DC->isRecord() && DC->isDependentContext()) ? TPC_ClassTemplateMember : TPC_FunctionTemplate); @@ -8159,7 +8465,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, return Result; } } - } else if (!D.isFunctionDefinition() && isa<CXXMethodDecl>(NewFD) && NewFD->isOutOfLine() && !isFriend && !isFunctionTemplateSpecialization && @@ -8168,8 +8473,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, // definition (C++ [class.mfct]p2). // Note that this is not the case for explicit specializations of // function templates or member functions of class templates, per - // C++ [temp.expl.spec]p2. We also allow these declarations as an - // extension for compatibility with old SWIG code which likes to + // C++ [temp.expl.spec]p2. We also allow these declarations as an + // extension for compatibility with old SWIG code which likes to // generate them. Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration) << D.getCXXScopeSpec().getRange(); @@ -8181,7 +8486,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, AddKnownFunctionAttributes(NewFD); - if (NewFD->hasAttr<OverloadableAttr>() && + if (NewFD->hasAttr<OverloadableAttr>() && !NewFD->getType()->getAs<FunctionProtoType>()) { Diag(NewFD->getLocation(), diag::err_attribute_overloadable_no_prototype) @@ -8224,7 +8529,30 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, if (D.isRedeclaration() && !Previous.empty()) { checkDLLAttributeRedeclaration( *this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD, - isExplicitSpecialization || isFunctionTemplateSpecialization); + isExplicitSpecialization || isFunctionTemplateSpecialization, + D.isFunctionDefinition()); + } + + if (getLangOpts().CUDA) { + IdentifierInfo *II = NewFD->getIdentifier(); + if (II && II->isStr("cudaConfigureCall") && !NewFD->isInvalidDecl() && + NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { + if (!R->getAs<FunctionType>()->getReturnType()->isScalarType()) + Diag(NewFD->getLocation(), diag::err_config_scalar_return); + + Context.setcudaConfigureCallDecl(NewFD); + } + + // Variadic functions, other than a *declaration* of printf, are not allowed + // in device-side CUDA code, unless someone passed + // -fcuda-allow-variadic-functions. + if (!getLangOpts().CUDAAllowVariadicFunctions && NewFD->isVariadic() && + (NewFD->hasAttr<CUDADeviceAttr>() || + NewFD->hasAttr<CUDAGlobalAttr>()) && + !(II && II->isStr("printf") && NewFD->isExternC() && + !D.isFunctionDefinition())) { + Diag(NewFD->getLocation(), diag::err_variadic_device_fn); + } } if (getLangOpts().CPlusPlus) { @@ -8242,7 +8570,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, Diag(D.getIdentifierLoc(), diag::err_static_kernel); D.setInvalidType(); } - + // OpenCL v1.2, s6.9 -- Kernels can only have return type void. if (!NewFD->getReturnType()->isVoidType()) { SourceRange RTRange = NewFD->getReturnTypeSourceRange(); @@ -8253,12 +8581,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, } llvm::SmallPtrSet<const Type *, 16> ValidTypes; - for (auto Param : NewFD->params()) + for (auto Param : NewFD->parameters()) checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes); } - for (FunctionDecl::param_iterator PI = NewFD->param_begin(), - PE = NewFD->param_end(); PI != PE; ++PI) { - ParmVarDecl *Param = *PI; + for (const ParmVarDecl *Param : NewFD->parameters()) { QualType PT = Param->getType(); // OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value @@ -8276,25 +8602,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, MarkUnusedFileScopedDecl(NewFD); - if (getLangOpts().CUDA) - if (IdentifierInfo *II = NewFD->getIdentifier()) - if (!NewFD->isInvalidDecl() && - NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) { - if (II->isStr("cudaConfigureCall")) { - if (!R->getAs<FunctionType>()->getReturnType()->isScalarType()) - Diag(NewFD->getLocation(), diag::err_config_scalar_return); - - Context.setcudaConfigureCallDecl(NewFD); - } - } - // Here we have an function template explicit specialization at class scope. // The actually specialization will be postponed to template instatiation // time via the ClassScopeFunctionSpecializationDecl node. if (isDependentClassScopeExplicitSpecialization) { ClassScopeFunctionSpecializationDecl *NewSpec = ClassScopeFunctionSpecializationDecl::Create( - Context, CurContext, SourceLocation(), + Context, CurContext, SourceLocation(), cast<CXXMethodDecl>(NewFD), HasExplicitTemplateArgs, TemplateArgs); CurContext->addDecl(NewSpec); @@ -8464,20 +8778,28 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, FunctionTemplateDecl *NewTemplateDecl = NewFD->getDescribedFunctionTemplate(); assert(NewTemplateDecl && "Template/non-template mismatch"); - if (CXXMethodDecl *Method + if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) { Method->setAccess(OldTemplateDecl->getAccess()); NewTemplateDecl->setAccess(OldTemplateDecl->getAccess()); } - + // If this is an explicit specialization of a member that is a function // template, mark it as a member specialization. - if (IsExplicitSpecialization && + if (IsExplicitSpecialization && NewTemplateDecl->getInstantiatedFromMemberTemplate()) { NewTemplateDecl->setMemberSpecialization(); assert(OldTemplateDecl->isMemberSpecialization()); + // Explicit specializations of a member template do not inherit deleted + // status from the parent member template that they are specializing. + if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) { + FunctionDecl *const OldTemplatedDecl = + OldTemplateDecl->getTemplatedDecl(); + assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl); + OldTemplatedDecl->setDeletedAsWritten(false); + } } - + } else { // This needs to happen first so that 'inline' propagates. NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl)); @@ -8493,11 +8815,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // C++-specific checks. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) { CheckConstructor(Constructor); - } else if (CXXDestructorDecl *Destructor = + } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(NewFD)) { CXXRecordDecl *Record = Destructor->getParent(); QualType ClassType = Context.getTypeDeclType(Record); - + // FIXME: Shouldn't we be able to perform this check even when the class // type is dependent? Both gcc and edg can handle that. if (!ClassType->isDependentType()) { @@ -8517,7 +8839,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, // Find any virtual functions that this function overrides. if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) { - if (!Method->isFunctionTemplateSpecialization() && + if (!Method->isFunctionTemplateSpecialization() && !Method->getDescribedFunctionTemplate() && Method->isCanonicalDecl()) { if (AddOverriddenMethods(Method->getParent(), Method)) { @@ -8527,7 +8849,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } } - + if (Method->isStatic()) checkThisInStaticMemberFunctionType(Method); } @@ -8553,7 +8875,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, CheckCXXDefaultArguments(NewFD); // If this function declares a builtin function, check the type of this - // declaration against the expected type for the builtin. + // declaration against the expected type for the builtin. if (unsigned BuiltinID = NewFD->getBuiltinID()) { ASTContext::GetBuiltinTypeError Error; LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier()); @@ -8565,7 +8887,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD, } } - // If this function is declared as being extern "C", then check to see if + // If this function is declared as being extern "C", then check to see if // the function returns a UDT (class, struct, or union type) that is not C // compatible, and if it does, warn the user. // But, issue any diagnostic on the first declaration only. @@ -8591,11 +8913,11 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { // static main is not an error under C99, but we should warn about it. // We accept _Noreturn main as an extension. if (FD->getStorageClass() == SC_Static) - Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus - ? diag::err_static_main : diag::warn_static_main) + Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus + ? diag::err_static_main : diag::warn_static_main) << FixItHint::CreateRemoval(DS.getStorageClassSpecLoc()); if (FD->isInlineSpecified()) - Diag(DS.getInlineSpecLoc(), diag::err_inline_main) + Diag(DS.getInlineSpecLoc(), diag::err_inline_main) << FixItHint::CreateRemoval(DS.getInlineSpecLoc()); if (DS.isNoreturnSpecified()) { SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc(); @@ -8722,7 +9044,7 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) { if (nparams == 1 && !FD->isInvalidDecl()) { Diag(FD->getLocation(), diag::warn_main_one_arg); } - + if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) { Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD; FD->setInvalidDecl(); @@ -8779,6 +9101,7 @@ namespace { bool isInitList; llvm::SmallVector<unsigned, 4> InitFieldIndex; + public: typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited; @@ -9000,7 +9323,7 @@ namespace { Inherited::VisitUnaryOperator(E); } - void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; } + void VisitObjCMessageExpr(ObjCMessageExpr *E) {} void VisitCXXConstructExpr(CXXConstructExpr *E) { if (E->getConstructor()->isCopyConstructor()) { @@ -9096,7 +9419,7 @@ namespace { SelfReferenceChecker(S, OrigDecl).CheckExpr(E); } -} +} // end anonymous namespace QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl, DeclarationName Name, QualType Type, @@ -9294,7 +9617,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, VarDecl *Def; if ((Def = VDecl->getDefinition()) && Def != VDecl) { NamedDecl *Hidden = nullptr; - if (!hasVisibleDefinition(Def, &Hidden) && + if (!hasVisibleDefinition(Def, &Hidden) && (VDecl->getFormalLinkage() == InternalLinkage || VDecl->getDescribedVarTemplate() || VDecl->getNumTemplateParameterLists() || @@ -9330,7 +9653,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, diag::note_previous_initializer) << 0; return; - } + } if (VDecl->hasLocalStorage()) getCurFunction()->setHasBranchProtectedScope(); @@ -9352,7 +9675,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // Get the decls type and save a reference for later, since // CheckInitializerTypes may change it. QualType DclT = VDecl->getType(), SavT = DclT; - + // Expressions default to 'id' when we're in a debugger // and we are assigning it to a variable of Objective-C pointer type. if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() && @@ -9400,7 +9723,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, if (VDecl->isInvalidDecl()) return; - InitializationSequence InitSeq(*this, Entity, Kind, Args); + InitializationSequence InitSeq(*this, Entity, Kind, Args, + /*TopLevelOfInitList=*/false, + /*TreatUnavailableAsInvalid=*/false); ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT); if (Result.isInvalid()) { VDecl->setInvalidDecl(); @@ -9486,7 +9811,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, diag::ext_aggregate_init_not_constant) << Culprit->getSourceRange(); } - } else if (VDecl->isStaticDataMember() && + } else if (VDecl->isStaticDataMember() && !VDecl->isInline() && VDecl->getLexicalDeclContext()->isRecord()) { // This is an in-class initialization for a static data member, e.g., // @@ -9500,8 +9825,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, // const enumeration type, see 9.4.2. // // C++11 [class.static.data]p3: - // If a non-volatile const static data member is of integral or - // enumeration type, its declaration in the class definition can + // If a non-volatile non-inline const static data member is of integral + // or enumeration type, its declaration in the class definition can // specify a brace-or-equal-initializer in which every initalizer-clause // that is an assignment-expression is a constant expression. A static // data member of literal type can be declared in the class definition @@ -9641,7 +9966,7 @@ void Sema::ActOnInitializerError(Decl *D) { if (Ty->isDependentType()) return; // Require a complete type. - if (RequireCompleteType(VD->getLocation(), + if (RequireCompleteType(VD->getLocation(), Context.getBaseElementType(Ty), diag::err_typecheck_decl_incomplete_type)) { VD->setInvalidDecl(); @@ -9684,23 +10009,32 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // the definition of a variable [...] or the declaration of a static data // member. if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) { - if (Var->isStaticDataMember()) - Diag(Var->getLocation(), - diag::err_constexpr_static_mem_var_requires_init) - << Var->getDeclName(); - else + if (Var->isStaticDataMember()) { + // C++1z removes the relevant rule; the in-class declaration is always + // a definition there. + if (!getLangOpts().CPlusPlus1z) { + Diag(Var->getLocation(), + diag::err_constexpr_static_mem_var_requires_init) + << Var->getDeclName(); + Var->setInvalidDecl(); + return; + } + } else { Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl); - Var->setInvalidDecl(); - return; + Var->setInvalidDecl(); + return; + } } // C++ Concepts TS [dcl.spec.concept]p1: [...] A variable template // definition having the concept specifier is called a variable concept. A // concept definition refers to [...] a variable concept and its initializer. - if (Var->isConcept()) { - Diag(Var->getLocation(), diag::err_var_concept_not_initialized); - Var->setInvalidDecl(); - return; + if (VarTemplateDecl *VTD = Var->getDescribedVarTemplate()) { + if (VTD->isConcept()) { + Diag(Var->getLocation(), diag::err_var_concept_not_initialized); + Var->setInvalidDecl(); + return; + } } // OpenCL v1.1 s6.5.3: variables declared in the constant address space must @@ -9720,17 +10054,17 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, // We have an out-of-line definition of a static data member // that has an in-class initializer, so we type-check this like - // a declaration. + // a declaration. // // Fall through - + case VarDecl::DeclarationOnly: - // It's only a declaration. + // It's only a declaration. // Block scope. C99 6.7p7: If an identifier for an object is // declared with no linkage (C99 6.2.2p6), the type for the // object shall be complete. - if (!Type->isDependentType() && Var->isLocalVarDecl() && + if (!Type->isDependentType() && Var->isLocalVarDecl() && !Var->hasLinkage() && !Var->isInvalidDecl() && RequireCompleteType(Var->getLocation(), Type, diag::err_typecheck_decl_incomplete_type)) @@ -9747,7 +10081,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, Diag(Var->getLocation(), diag::warn_private_extern); Diag(Var->getLocation(), diag::note_private_extern); } - + return; case VarDecl::TentativeDefinition: @@ -9852,7 +10186,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, getCurFunction()->setHasBranchProtectedScope(); } } - + // C++03 [dcl.init]p9: // If no initializer is specified for an object, and the // object is of (possibly cv-qualified) non-POD class type (or @@ -9886,6 +10220,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl, } void Sema::ActOnCXXForRangeDecl(Decl *D) { + // If there is no declaration, there was an error parsing it. Ignore it. + if (!D) + return; + VarDecl *VD = dyn_cast<VarDecl>(D); if (!VD) { Diag(D->getLocation(), diag::err_for_range_decl_must_be_var); @@ -9957,6 +10295,18 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc, void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (var->isInvalidDecl()) return; + if (getLangOpts().OpenCL) { + // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an + // initialiser + if (var->getTypeSourceInfo()->getType()->isBlockPointerType() && + !var->hasInit()) { + Diag(var->getLocation(), diag::err_opencl_invalid_block_declaration) + << 1 /*Init*/; + var->setInvalidDecl(); + return; + } + } + // In Objective-C, don't allow jumps past the implicit initialization of a // local retaining variable. if (getLangOpts().ObjC1 && @@ -10014,7 +10364,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) { if (getLangOpts().CPlusPlus11) Diag(var->getLocation(), diag::note_use_thread_local); } - } // Apply section attributes and pragmas to global variables. @@ -10165,15 +10514,63 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) { } } - // Static locals inherit dll attributes from their function. if (VD->isStaticLocal()) { if (FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod())) { + // Static locals inherit dll attributes from their function. if (Attr *A = getDLLAttr(FD)) { auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext())); NewAttr->setInherited(true); VD->addAttr(NewAttr); } + // 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); + VD->setInvalidDecl(); + } + } + } + + // Perform check for initializers of device-side global variables. + // CUDA allows empty constructors as initializers (see E.2.3.1, CUDA + // 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) { + 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()) + 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(); + } } } @@ -10416,6 +10813,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec()) Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread) << DeclSpec::getSpecifierName(TSCS); + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (DS.isConstexprSpecified()) Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr) << 0; @@ -10431,7 +10831,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { // Check that there are no default arguments inside the type of this // parameter. CheckExtraCXXDefaultArguments(D); - + // Parameter declarators cannot be qualified (C++ [dcl.meaning]p1). if (D.getCXXScopeSpec().isSet()) { Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator) @@ -10491,7 +10891,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) { assert(S->getFunctionPrototypeDepth() >= 1); New->setScopeInfo(S->getFunctionPrototypeDepth() - 1, S->getNextFunctionPrototypeIndex()); - + // Add the parameter declaration into this scope. S->AddDecl(New); if (II) @@ -10526,26 +10926,23 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC, return Param; } -void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param, - ParmVarDecl * const *ParamEnd) { +void Sema::DiagnoseUnusedParameters(ArrayRef<ParmVarDecl *> Parameters) { // Don't diagnose unused-parameter errors in template instantiations; we // will already have done so in the template itself. if (!ActiveTemplateInstantiations.empty()) return; - for (; Param != ParamEnd; ++Param) { - if (!(*Param)->isReferenced() && (*Param)->getDeclName() && - !(*Param)->hasAttr<UnusedAttr>()) { - Diag((*Param)->getLocation(), diag::warn_unused_parameter) - << (*Param)->getDeclName(); + for (const ParmVarDecl *Parameter : Parameters) { + if (!Parameter->isReferenced() && Parameter->getDeclName() && + !Parameter->hasAttr<UnusedAttr>()) { + Diag(Parameter->getLocation(), diag::warn_unused_parameter) + << Parameter->getDeclName(); } } } -void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, - ParmVarDecl * const *ParamEnd, - QualType ReturnTy, - NamedDecl *D) { +void Sema::DiagnoseSizeOfParametersAndReturnValue( + ArrayRef<ParmVarDecl *> Parameters, QualType ReturnTy, NamedDecl *D) { if (LangOpts.NumLargeByValueCopy == 0) // No check. return; @@ -10560,14 +10957,14 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param, // Warn if any parameter is pass-by-value and larger than the specified // threshold. - for (; Param != ParamEnd; ++Param) { - QualType T = (*Param)->getType(); + for (const ParmVarDecl *Parameter : Parameters) { + QualType T = Parameter->getType(); if (T->isDependentType() || !T.isPODType(Context)) continue; unsigned Size = Context.getTypeSizeInChars(T).getQuantity(); if (Size > LangOpts.NumLargeByValueCopy) - Diag((*Param)->getLocation(), diag::warn_parameter_size) - << (*Param)->getDeclName() << Size; + Diag(Parameter->getLocation(), diag::warn_parameter_size) + << Parameter->getDeclName() << Size; } } @@ -10599,7 +10996,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, } ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name, - Context.getAdjustedParameterType(T), + Context.getAdjustedParameterType(T), TSInfo, SC, nullptr); // Parameters can not be abstract class types. @@ -10613,7 +11010,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, // Parameter declarators cannot be interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { - SourceLocation TypeEndLoc = TSInfo->getTypeLoc().getLocEnd(); + SourceLocation TypeEndLoc = + getLocForEndOfToken(TSInfo->getTypeLoc().getLocEnd()); Diag(NameLoc, diag::err_object_cannot_be_passed_returned_by_value) << 1 << T << FixItHint::CreateInsertion(TypeEndLoc, "*"); @@ -10621,7 +11019,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, New->setType(T); } - // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage + // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage // duration shall not be qualified by an address-space qualifier." // Since all parameters have automatic store duration, they can not have // an address space. @@ -10632,7 +11030,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, Diag(NameLoc, diag::err_arg_with_address_space); New->setInvalidDecl(); } - } + } return New; } @@ -10686,11 +11084,11 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D, return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody); } -void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) { - Consumer.HandleInlineMethodDefinition(D); +void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) { + Consumer.HandleInlineFunctionDefinition(D); } -static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, +static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD, const FunctionDecl*& PossibleZeroParamPrototype) { // Don't warn about invalid declarations. if (FD->isInvalidDecl()) @@ -10786,11 +11184,10 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD, FD->setInvalidDecl(); } - -static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, +static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, Sema &S) { CXXRecordDecl *const LambdaClass = CallOperator->getParent(); - + LambdaScopeInfo *LSI = S.PushLambdaScope(); LSI->CallOperator = CallOperator; LSI->Lambda = LambdaClass; @@ -10804,12 +11201,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, else if (LCD == LCD_ByRef) LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref; DeclarationNameInfo DNI = CallOperator->getNameInfo(); - - LSI->IntroducerRange = DNI.getCXXOperatorNameRange(); + + LSI->IntroducerRange = DNI.getCXXOperatorNameRange(); LSI->Mutable = !CallOperator->isConst(); // Add the captures to the LSI so they can be noted as already - // captured within tryCaptureVar. + // captured within tryCaptureVar. auto I = LambdaClass->field_begin(); for (const auto &C : LambdaClass->captures()) { if (C.capturesVariable()) { @@ -10818,15 +11215,16 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator, S.CurrentInstantiationScope->InstantiatedLocal(VD, VD); QualType CaptureType = VD->getType(); const bool ByRef = C.getCaptureKind() == LCK_ByRef; - LSI->addCapture(VD, /*IsBlock*/false, ByRef, + LSI->addCapture(VD, /*IsBlock*/false, ByRef, /*RefersToEnclosingVariableOrCapture*/true, C.getLocation(), - /*EllipsisLoc*/C.isPackExpansion() + /*EllipsisLoc*/C.isPackExpansion() ? C.getEllipsisLoc() : SourceLocation(), CaptureType, /*Expr*/ nullptr); } else if (C.capturesThis()) { - LSI->addThisCapture(/*Nested*/ false, C.getLocation(), - S.getCurrentThisType(), /*Expr*/ nullptr); + LSI->addThisCapture(/*Nested*/ false, C.getLocation(), + /*Expr*/ nullptr, + C.getCaptureKind() == LCK_StarThis); } else { LSI->addVLATypeCapture(C.getLocation(), I->getType()); } @@ -10838,7 +11236,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, SkipBodyInfo *SkipBody) { // Clear the last template instantiation error context. LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation(); - + if (!D) return D; FunctionDecl *FD = nullptr; @@ -10859,16 +11257,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, // 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 - // LambdaScopeInfo. + // that's already been calculated (ActOnLambdaExpr) to prime the current + // LambdaScopeInfo. // When the template operator is being specialized, the LambdaScopeInfo, // has to be properly restored so that tryCaptureVariable doesn't try // and capture any new variables. In addition when calculating potential - // captures during transformation of nested lambdas, it is necessary to - // have the LSI properly restored. + // captures during transformation of nested lambdas, it is necessary to + // have the LSI properly restored. if (isGenericLambdaCallOperatorSpecialization(FD)) { assert(ActiveTemplateInstantiations.size() && - "There should be an active template instantiation on the stack " + "There should be an active template instantiation on the stack " "when instantiating a generic lambda!"); RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D), *this); } @@ -10898,11 +11296,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, PushDeclContext(FnBodyScope, FD); // Check the validity of our function parameters - CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(), + CheckParmsForFunctionDef(FD->parameters(), /*CheckParameterNames=*/true); // Introduce our parameters into the function scope - for (auto Param : FD->params()) { + for (auto Param : FD->parameters()) { Param->setOwningFunction(FD); // If this has an identifier, add it to the scope stack. @@ -10965,15 +11363,15 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D, getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl && getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation) Diag(FD->getLocation(), diag::warn_function_def_in_objc_container); - + return D; } /// \brief Given the set of return statements within a function body, -/// compute the variables that are subject to the named return value +/// compute the variables that are subject to the named return value /// optimization. /// -/// Each of the variables that is subject to the named return value +/// Each of the variables that is subject to the named return value /// optimization will be marked as NRVO variables in the AST, and any /// return statement that has a marked NRVO variable as its NRVO candidate can /// use the named return value optimization. @@ -11033,7 +11431,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) { FD->setHasSkippedBody(); else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl)) MD->setHasSkippedBody(); - return ActOnFinishFunctionBody(Decl, nullptr); + return Decl; } Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) { @@ -11053,22 +11451,26 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (FD) { FD->setBody(Body); - if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body && - !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) { - // If the function has a deduced result type but contains no 'return' - // statements, the result type as written must be exactly 'auto', and - // the deduced result type is 'void'. - if (!FD->getReturnType()->getAs<AutoType>()) { - Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) - << FD->getReturnType(); - FD->setInvalidDecl(); - } else { - // Substitute 'void' for the 'auto' in the type. - TypeLoc ResultType = getReturnTypeLoc(FD); - Context.adjustDeducedFunctionResultType( - FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); + if (getLangOpts().CPlusPlus14) { + if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() && + FD->getReturnType()->isUndeducedType()) { + // If the function has a deduced result type but contains no 'return' + // statements, the result type as written must be exactly 'auto', and + // the deduced result type is 'void'. + if (!FD->getReturnType()->getAs<AutoType>()) { + Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto) + << FD->getReturnType(); + FD->setInvalidDecl(); + } else { + // Substitute 'void' for the 'auto' in the type. + TypeLoc ResultType = getReturnTypeLoc(FD); + Context.adjustDeducedFunctionResultType( + FD, SubstAutoType(ResultType.getType(), Context.VoidTy)); + } } } else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) { + // In C++11, we don't use 'auto' deduction rules for lambda call + // operators because we don't support return type deduction. auto *LSI = getCurLambda(); if (LSI->HasImplicitReturnType) { deduceClosureReturnType(*LSI); @@ -11112,8 +11514,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, if (!FD->isInvalidDecl()) { // Don't diagnose unused parameters of defaulted or deleted functions. if (!FD->isDeleted() && !FD->isDefaulted()) - DiagnoseUnusedParameters(FD->param_begin(), FD->param_end()); - DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(), + DiagnoseUnusedParameters(FD->parameters()); + DiagnoseSizeOfParametersAndReturnValue(FD->parameters(), FD->getReturnType(), FD); // If this is a structor, we need a vtable. @@ -11121,7 +11523,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, MarkVTableUsed(FD->getLocation(), Constructor->getParent()); else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD)) MarkVTableUsed(FD->getLocation(), Destructor->getParent()); - + // Try to apply the named return value optimization. We have to check // if we can do this here because lambdas keep return statements around // to deduce an implicit return type. @@ -11184,8 +11586,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, assert(MD == getCurMethodDecl() && "Method parsing confused"); MD->setBody(Body); if (!MD->isInvalidDecl()) { - DiagnoseUnusedParameters(MD->param_begin(), MD->param_end()); - DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(), + DiagnoseUnusedParameters(MD->parameters()); + DiagnoseSizeOfParametersAndReturnValue(MD->parameters(), MD->getReturnType(), MD); if (Body) @@ -11245,7 +11647,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, // Verify this. if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body)) DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body)); - + // Verify that gotos and switch cases don't jump into scopes illegally. if (getCurFunction()->NeedsScopeChecking() && !PP.isCodeCompletionEnabled()) @@ -11258,7 +11660,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(), Destructor->getParent()); } - + // If any errors have occurred, clear out any temporaries that may have // been leftover. This ensures that these temporaries won't be picked up for // deletion in some later function. @@ -11292,11 +11694,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, assert(ExprCleanupObjects.size() == ExprEvalContexts.back().NumCleanupObjects && "Leftover temporaries in function"); - assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); + assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function"); assert(MaybeODRUseExprs.empty() && "Leftover expressions for odr-use checking"); } - + if (!IsInstantiation) PopDeclContext(); @@ -11311,7 +11713,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body, return dcl; } - /// When we finish delayed parsing of an attribute, we must attach it to the /// relevant Decl. void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, @@ -11319,14 +11720,13 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D, // Always attach attributes to the underlying decl. if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D)) D = TD->getTemplatedDecl(); - ProcessDeclAttributeList(S, D, Attrs.getList()); - + ProcessDeclAttributeList(S, D, Attrs.getList()); + if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D)) if (Method->isStatic()) checkThisInStaticMemberFunctionAttributes(Method); } - /// ImplicitlyDefineFunction - An undeclared identifier was used in a function /// call, forming a call to an implicitly defined function (per C99 6.5.1p2). NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc, @@ -11473,14 +11873,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { FD->getLocation())); if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr<NoThrowAttr>()) FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); + if (Context.BuiltinInfo.isPure(BuiltinID) && !FD->hasAttr<PureAttr>()) + FD->addAttr(PureAttr::CreateImplicit(Context, FD->getLocation())); if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr<ConstAttr>()) FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation())); - if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads && - Context.BuiltinInfo.isTSBuiltin(BuiltinID) && + if (getLangOpts().CUDA && Context.BuiltinInfo.isTSBuiltin(BuiltinID) && !FD->hasAttr<CUDADeviceAttr>() && !FD->hasAttr<CUDAHostAttr>()) { - // Assign appropriate attribute depending on CUDA compilation - // mode and the target builtin belongs to. E.g. during host - // compilation, aux builtins are __device__, the rest are __host__. + // Add the appropriate attribute, depending on the CUDA compilation mode + // and which target the builtin belongs to. For example, during host + // compilation, aux builtins are __device__, while the rest are __host__. if (getLangOpts().CUDAIsDevice != Context.BuiltinInfo.isAuxBuiltinID(BuiltinID)) FD->addAttr(CUDADeviceAttr::CreateImplicit(Context, FD->getLocation())); @@ -11489,6 +11890,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) { } } + // If C++ exceptions are enabled but we are told extern "C" functions cannot + // throw, add an implicit nothrow attribute to any extern "C" function we come + // across. + if (getLangOpts().CXXExceptions && getLangOpts().ExternCNoUnwind && + FD->isExternC() && !FD->hasAttr<NoThrowAttr>()) { + const auto *FPT = FD->getType()->getAs<FunctionProtoType>(); + if (!FPT || FPT->getExceptionSpecType() == EST_None) + FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation())); + } + IdentifierInfo *Name = FD->getIdentifier(); if (!Name) return; @@ -11543,7 +11954,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, NewTD->setInvalidDecl(); return NewTD; } - + if (D.getDeclSpec().isModulePrivateSpecified()) { if (CurContext->isFunctionOrMethod()) Diag(NewTD->getLocation(), diag::err_module_private_local) @@ -11553,7 +11964,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, else NewTD->setModulePrivate(); } - + // C++ [dcl.typedef]p8: // If the typedef declaration defines an unnamed class (or // enum), the first typedef-name declared by the declaration @@ -11578,7 +11989,6 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T, return NewTD; } - /// \brief Check that this is a valid underlying type for an enum declaration. bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) { SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc(); @@ -12006,7 +12416,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, } // A tag 'foo::bar' must already exist. - Diag(NameLoc, diag::err_not_tag_in_scope) + Diag(NameLoc, diag::err_not_tag_in_scope) << Kind << Name << DC << SS.getRange(); Name = nullptr; Invalid = true; @@ -12030,12 +12440,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // When declaring or defining a tag, ignore ambiguities introduced // by types using'ed into this scope. - if (Previous.isAmbiguous() && + if (Previous.isAmbiguous() && (TUK == TUK_Definition || TUK == TUK_Declaration)) { LookupResult::Filter F = Previous.makeFilter(); while (F.hasNext()) { NamedDecl *ND = F.next(); - if (ND->getDeclContext()->getRedeclContext() != SearchDC) + if (!ND->getDeclContext()->getRedeclContext()->Equals( + SearchDC->getRedeclContext())) F.erase(); } F.done(); @@ -12106,10 +12517,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, DC->Equals(getStdNamespace()) && 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 + // name lookup). Fill in this implicit declaration as the previous // declaration, so that the declarations get chained appropriately. Previous.addDecl(getStdBadAlloc()); } @@ -12422,7 +12833,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK, // is non-NULL, it's a definition of the tag declared by // PrevDecl. If it's NULL, we have a new definition. - // Otherwise, PrevDecl is not a tag, but was found with tag // lookup. This is only actually possible in C++, where a few // things like templates still live in the tag namespace. @@ -12523,8 +12933,8 @@ CreateNewDecl: else if (getLangOpts().CPlusPlus) DiagID = diag::err_forward_ref_enum; Diag(Loc, DiagID); - - // If this is a forward-declared reference to an enumeration, make a + + // If this is a forward-declared reference to an enumeration, make a // note of it; we won't actually be introducing the declaration into // the declaration context. if (TUK == TUK_Reference) @@ -12540,7 +12950,6 @@ CreateNewDecl: ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); ED->setPromotionType(ED->getIntegerType()); } - } else { // struct/union/class @@ -12569,10 +12978,10 @@ CreateNewDecl: // Maybe add qualifier info. if (SS.isNotEmpty()) { if (SS.isSet()) { - // If this is either a declaration or a definition, check the + // If this is either a declaration or a definition, check the // nested-name-specifier against the current context. We don't do this // for explicit specializations, because they have similar checking - // (with more specific diagnostics) in the call to + // (with more specific diagnostics) in the call to // CheckMemberSpecialization, below. if (!isExplicitSpecialization && (TUK == TUK_Definition || TUK == TUK_Declaration) && @@ -12681,7 +13090,6 @@ CreateNewDecl: PushOnScopeChains(New, S, !IsForwardReference); if (IsForwardReference) SearchDC->makeDeclVisibleInContext(New); - } else { CurContext->addDecl(New); } @@ -12709,7 +13117,7 @@ CreateNewDecl: void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD); - + // Enter the tag context. PushDeclContext(S, Tag); @@ -12721,7 +13129,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) { } Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) { - assert(isa<ObjCContainerDecl>(IDecl) && + assert(isa<ObjCContainerDecl>(IDecl) && "ActOnObjCContainerStartDefinition - Not ObjCContainerDecl"); DeclContext *OCD = cast<DeclContext>(IDecl); assert(getContainingDC(OCD) == CurContext && @@ -12768,10 +13176,10 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD, } void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD, - SourceLocation RBraceLoc) { + SourceRange BraceRange) { AdjustDeclIfTemplate(TagD); TagDecl *Tag = cast<TagDecl>(TagD); - Tag->setRBraceLoc(RBraceLoc); + Tag->setBraceRange(BraceRange); // Make sure we "complete" the definition even it is invalid. if (Tag->isBeingDefined()) { @@ -12826,7 +13234,7 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) { // ActOnStartCXXMemberDeclarations, so we don't have to mess with // the FieldCollector. - PopDeclContext(); + PopDeclContext(); } // Note that FieldName may be null for anonymous bitfields. @@ -12961,15 +13369,19 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, D.setInvalidType(); } - // OpenCL 1.2 spec, s6.9 r: - // The event type cannot be used to declare a structure or union field. - if (LangOpts.OpenCL && T->isEventT()) { - Diag(Loc, diag::err_event_t_struct_field); + // OpenCL v1.2 s6.9b,r & OpenCL v2.0 s6.12.5 - The following types cannot be + // used as structure or union field: image, sampler, event or block types. + if (LangOpts.OpenCL && (T->isEventT() || T->isImageType() || + T->isSamplerT() || T->isBlockPointerType())) { + Diag(Loc, diag::err_opencl_type_struct_or_union_field) << T; D.setInvalidType(); } DiagnoseFunctionSpecifiers(D.getDeclSpec()); + if (D.getDeclSpec().isInlineSpecified()) + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) @@ -12984,11 +13396,11 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, case LookupResult::FoundUnresolvedValue: PrevDecl = Previous.getAsSingle<NamedDecl>(); break; - + case LookupResult::FoundOverloaded: PrevDecl = Previous.getRepresentativeDecl(); break; - + case LookupResult::NotFound: case LookupResult::NotFoundInCurrentInstantiation: case LookupResult::Ambiguous: @@ -13018,7 +13430,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record, if (D.getDeclSpec().isModulePrivateSpecified()) NewFD->setModulePrivate(); - + if (NewFD->isInvalidDecl() && PrevDecl) { // Don't introduce NewFD into scope; there's already something // with the same name in the same scope. @@ -13250,9 +13662,9 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) { if (!getLangOpts().CPlusPlus11 && getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) { // Objective-C++ ARC: it is an error to have a non-trivial field of - // a union. However, system headers in Objective-C programs + // a union. However, system headers in Objective-C programs // occasionally have Objective-C lifetime objects within unions, - // and rather than cause the program to fail, we make those + // and rather than cause the program to fail, we make those // members unavailable. SourceLocation Loc = FD->getLocation(); if (getSourceManager().isInSystemHeader(Loc)) { @@ -13348,7 +13760,7 @@ Decl *Sema::ActOnIvar(Scope *S, else EnclosingContext = EnclosingDecl; } else { - if (ObjCCategoryDecl *CDecl = + if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) { Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension(); @@ -13386,33 +13798,33 @@ Decl *Sema::ActOnIvar(Scope *S, if (D.getDeclSpec().isModulePrivateSpecified()) NewID->setModulePrivate(); - + if (II) { // FIXME: When interfaces are DeclContexts, we'll need to add // these to the interface. S->AddDecl(NewID); IdResolver.AddDecl(NewID); } - + if (LangOpts.ObjCRuntime.isNonFragile() && !NewID->isInvalidDecl() && isa<ObjCInterfaceDecl>(EnclosingDecl)) Diag(Loc, diag::warn_ivars_in_interface); - + return NewID; } -/// ActOnLastBitfield - This routine handles synthesized bitfields rules for -/// class and class extensions. For every class \@interface and class -/// extension \@interface, if the last ivar is a bitfield of any type, +/// ActOnLastBitfield - This routine handles synthesized bitfields rules for +/// class and class extensions. For every class \@interface and class +/// extension \@interface, if the last ivar is a bitfield of any type, /// then add an implicit `char :0` ivar to the end of that interface. void Sema::ActOnLastBitfield(SourceLocation DeclLoc, SmallVectorImpl<Decl *> &AllIvarDecls) { if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty()) return; - + Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1]; ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl); - + if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0) return; ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext); @@ -13431,7 +13843,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc, Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext), DeclLoc, DeclLoc, nullptr, - Context.CharTy, + Context.CharTy, Context.getTrivialTypeSourceInfo(Context.CharTy, DeclLoc), ObjCIvarDecl::Private, BW, @@ -13460,7 +13872,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, break; } } - + RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl); // Start counting up the number of named members; make sure to include @@ -13514,7 +13926,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, FD->setInvalidDecl(); EnclosingDecl->setInvalidDecl(); continue; - } else if (FDTy->isIncompleteArrayType() && Record && + } else if (FDTy->isIncompleteArrayType() && Record && ((i + 1 == Fields.end() && !Record->isUnion()) || ((getLangOpts().MicrosoftExt || getLangOpts().CPlusPlus) && @@ -13530,14 +13942,12 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, : getLangOpts().CPlusPlus ? diag::ext_flexible_array_union_gnu : diag::err_flexible_array_union; - else if (Fields.size() == 1) + else if (NumNamedMembers < 1) DiagID = getLangOpts().MicrosoftExt ? diag::ext_flexible_array_empty_aggregate_ms : getLangOpts().CPlusPlus ? diag::ext_flexible_array_empty_aggregate_gnu - : NumNamedMembers < 1 - ? diag::err_flexible_array_empty_aggregate - : 0; + : diag::err_flexible_array_empty_aggregate; if (DiagID) Diag(FD->getLocation(), DiagID) << FD->getDeclName() @@ -13631,7 +14041,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, UnavailableAttr::IR_ARCFieldWithOwnership, loc)); } } else { - Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag) + Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag) << T->isBlockPointerType() << Record->getTagKind(); } ARCErrReported = true; @@ -13644,7 +14054,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, Record->setHasObjectMember(true); else if (Context.getAsArrayType(FD->getType())) { QualType BaseType = Context.getBaseElementType(FD->getType()); - if (BaseType->isRecordType() && + if (BaseType->isRecordType() && BaseType->getAs<RecordType>()->getDecl()->hasObjectMember()) Record->setHasObjectMember(true); else if (BaseType->isObjCObjectPointerType() || @@ -13669,51 +14079,53 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, I = CXXRecord->conversion_begin(), E = CXXRecord->conversion_end(); I != E; ++I) I.setAccess((*I)->getAccess()); - - if (!CXXRecord->isDependentType()) { - if (CXXRecord->hasUserDeclaredDestructor()) { - // Adjust user-defined destructor exception spec. - if (getLangOpts().CPlusPlus11) - AdjustDestructorExceptionSpec(CXXRecord, - CXXRecord->getDestructor()); - } + } + if (!CXXRecord->isDependentType()) { + if (CXXRecord->hasUserDeclaredDestructor()) { + // Adjust user-defined destructor exception spec. + if (getLangOpts().CPlusPlus11) + AdjustDestructorExceptionSpec(CXXRecord, + CXXRecord->getDestructor()); + } + + if (!CXXRecord->isInvalidDecl()) { // Add any implicitly-declared members to this class. AddImplicitlyDeclaredMembersToClass(CXXRecord); - // If we have virtual base classes, we may end up finding multiple - // final overriders for a given virtual function. Check for this + // If we have virtual base classes, we may end up finding multiple + // final overriders for a given virtual function. Check for this // problem now. if (CXXRecord->getNumVBases()) { CXXFinalOverriderMap FinalOverriders; CXXRecord->getFinalOverriders(FinalOverriders); - - for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), + + for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(), MEnd = FinalOverriders.end(); M != MEnd; ++M) { - for (OverridingMethods::iterator SO = M->second.begin(), + for (OverridingMethods::iterator SO = M->second.begin(), SOEnd = M->second.end(); SO != SOEnd; ++SO) { - assert(SO->second.size() > 0 && + assert(SO->second.size() > 0 && "Virtual function without overridding functions?"); if (SO->second.size() == 1) continue; - + // C++ [class.virtual]p2: // In a derived class, if a virtual member function of a base // class subobject has more than one final overrider the // program is ill-formed. Diag(Record->getLocation(), diag::err_multiple_final_overriders) << (const NamedDecl *)M->first << Record; - Diag(M->first->getLocation(), + Diag(M->first->getLocation(), diag::note_overridden_virtual_function); - for (OverridingMethods::overriding_iterator - OM = SO->second.begin(), + for (OverridingMethods::overriding_iterator + OM = SO->second.begin(), OMEnd = SO->second.end(); OM != OMEnd; ++OM) Diag(OM->Method->getLocation(), diag::note_final_overrider) << (const NamedDecl *)M->first << OM->Method->getParent(); - + Record->setInvalidDecl(); } } @@ -13723,7 +14135,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } } } - + if (!Completed) Record->completeDefinition(); @@ -13812,7 +14224,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac); IMPDecl->setIvarLBraceLoc(LBrac); IMPDecl->setIvarRBraceLoc(RBrac); - } else if (ObjCCategoryDecl *CDecl = + } else if (ObjCCategoryDecl *CDecl = dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) { // case of ivars in class extension; all other cases have been // reported as errors elsewhere. @@ -13823,18 +14235,18 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, ObjCInterfaceDecl *IDecl = CDecl->getClassInterface(); for (unsigned i = 0, e = RecFields.size(); i != e; ++i) { if (IDecl) { - if (const ObjCIvarDecl *ClsIvar = + if (const ObjCIvarDecl *ClsIvar = IDecl->getIvarDecl(ClsFields[i]->getIdentifier())) { - Diag(ClsFields[i]->getLocation(), - diag::err_duplicate_ivar_declaration); + Diag(ClsFields[i]->getLocation(), + diag::err_duplicate_ivar_declaration); Diag(ClsIvar->getLocation(), diag::note_previous_definition); continue; } for (const auto *Ext : IDecl->known_extensions()) { if (const ObjCIvarDecl *ClsExtIvar = Ext->getIvarDecl(ClsFields[i]->getIdentifier())) { - Diag(ClsFields[i]->getLocation(), - diag::err_duplicate_ivar_declaration); + Diag(ClsFields[i]->getLocation(), + diag::err_duplicate_ivar_declaration); Diag(ClsExtIvar->getLocation(), diag::note_previous_definition); continue; } @@ -13859,37 +14271,37 @@ static bool isRepresentableIntegerValue(ASTContext &Context, QualType T) { assert(T->isIntegralType(Context) && "Integral type required!"); unsigned BitWidth = Context.getIntWidth(T); - + if (Value.isUnsigned() || Value.isNonNegative()) { - if (T->isSignedIntegerOrEnumerationType()) + if (T->isSignedIntegerOrEnumerationType()) --BitWidth; return Value.getActiveBits() <= BitWidth; - } + } return Value.getMinSignedBits() <= BitWidth; } // \brief Given an integral type, return the next larger integral type // (or a NULL type of no such type exists). static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) { - // FIXME: Int128/UInt128 support, which also needs to be introduced into + // FIXME: Int128/UInt128 support, which also needs to be introduced into // enum checking below. assert(T->isIntegralType(Context) && "Integral type required!"); const unsigned NumTypes = 4; - QualType SignedIntegralTypes[NumTypes] = { + QualType SignedIntegralTypes[NumTypes] = { Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy }; - QualType UnsignedIntegralTypes[NumTypes] = { - Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, + QualType UnsignedIntegralTypes[NumTypes] = { + Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy, Context.UnsignedLongLongTy }; - + unsigned BitWidth = Context.getTypeSize(T); QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes : UnsignedIntegralTypes; for (unsigned I = 0; I != NumTypes; ++I) if (Context.getTypeSize(Types[I]) > BitWidth) return Types[I]; - + return QualType(); } @@ -13945,12 +14357,15 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } else Diag(IdLoc, diag::err_enumerator_too_large) << EltTy; } else - Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get(); + Val = ImpCastExprToType(Val, EltTy, + EltTy->isBooleanType() ? + CK_IntegralToBoolean : CK_IntegralCast) + .get(); } else if (getLangOpts().CPlusPlus) { // C++11 [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: - // - If an initializer is specified for an enumerator, the + // - If an initializer is specified for an enumerator, the // initializing value has the same type as the expression. EltTy = Val->getType(); } else { @@ -13981,10 +14396,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // C++0x [dcl.enum]p5: // If the underlying type is not fixed, the type of each enumerator // is the type of its initializing value: - // - If no initializer is specified for the first enumerator, the + // - If no initializer is specified for the first enumerator, the // initializing value has an unspecified integral type. // - // GCC uses 'int' for its unspecified integral type, as does + // GCC uses 'int' for its unspecified integral type, as does // C99 6.7.2.2p3. if (Enum->isFixed()) { EltTy = Enum->getIntegerType(); @@ -14007,12 +14422,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, // - Otherwise the type of the initializing value is the same as // the type of the initializing value of the preceding enumerator // unless the incremented value is not representable in that type, - // in which case the type is an unspecified integral type + // in which case the type is an unspecified integral type // sufficient to contain the incremented value. If no such type // exists, the program is ill-formed. QualType T = getNextLargerIntegralType(Context, EltTy); if (T.isNull() || Enum->isFixed()) { - // There is no integral type larger enough to represent this + // There is no integral type larger enough to represent this // value. Complain, then allow the value to wrap around. EnumVal = LastEnumConst->getInitVal(); EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2); @@ -14028,15 +14443,15 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } else { EltTy = T; } - + // Retrieve the last enumerator's value, extent that type to the // type that is supposed to be large enough to represent the incremented // value, then increment. EnumVal = LastEnumConst->getInitVal(); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy)); - ++EnumVal; - + ++EnumVal; + // If we're not in C++, diagnose the overflow of enumerator values, // which in C99 means that the enumerator value is not representable in // an int (C99 6.7.2.2p2). However, we support GCC's extension that @@ -14054,12 +14469,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum, } if (!EltTy->isDependentType()) { - // Make the enumerator value match the signedness and size of the + // Make the enumerator value match the signedness and size of the // enumerator's type. EnumVal = EnumVal.extOrTrunc(Context.getIntWidth(EltTy)); EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType()); } - + return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy, Val, EnumVal); } @@ -14114,14 +14529,14 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst, } // C++ [class.mem]p15: - // If T is the name of a class, then each of the following shall have a name + // If T is the name of a class, then each of the following shall have a name // different from T: - // - every enumerator of every member of class T that is an unscoped + // - every enumerator of every member of class T that is an unscoped // enumerated type if (!TheEnumDecl->isScoped()) DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(), DeclarationNameInfo(Id, IdLoc)); - + EnumConstantDecl *New = CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val); if (!New) @@ -14360,8 +14775,8 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val, return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val)); } -void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, - SourceLocation RBraceLoc, Decl *EnumDeclX, +void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange, + Decl *EnumDeclX, ArrayRef<Decl *> Elements, Scope *S, AttributeList *Attr) { EnumDecl *Enum = cast<EnumDecl>(EnumDeclX); @@ -14430,7 +14845,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc, // int, long long int, or unsigned long long int. // C99 6.4.4.3p2: // An identifier declared as an enumeration constant has type int. - // The C99 rule is modified by a gcc extension + // The C99 rule is modified by a gcc extension QualType BestPromotionType; bool Packed = Enum->hasAttr<PackedAttr>(); @@ -14646,8 +15061,8 @@ void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) { return checkModuleImportContext(*this, M, ImportLoc, CurContext); } -DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, - SourceLocation ImportLoc, +DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, + SourceLocation ImportLoc, ModuleIdPath Path) { Module *Mod = getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible, @@ -14663,11 +15078,10 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, // 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, diag::err_module_self_import) + Diag(ImportLoc, getLangOpts().CompilingModule + ? diag::err_module_self_import + : diag::err_module_import_in_implementation) << Mod->getFullModuleName() << getLangOpts().CurrentModule; - else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule) - Diag(ImportLoc, diag::err_module_import_in_implementation) - << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule; SmallVector<SourceLocation, 2> IdentifierLocs; Module *ModCheck = Mod; @@ -14677,13 +15091,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc, if (!ModCheck) break; ModCheck = ModCheck->Parent; - + IdentifierLocs.push_back(Path[I].second); } - ImportDecl *Import = ImportDecl::Create(Context, + ImportDecl *Import = ImportDecl::Create(Context, Context.getTranslationUnitDecl(), - AtLoc.isValid()? AtLoc : ImportLoc, + AtLoc.isValid()? AtLoc : ImportLoc, Mod, IdentifierLocs); Context.getTranslationUnitDecl()->addDecl(Import); return Import; @@ -14701,9 +15115,17 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { TUKind == TU_Module && getSourceManager().isWrittenInMainFile(DirectiveLoc); - // If this module import was due to an inclusion directive, create an + // 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()); + + // If this module import was due to an inclusion directive, create an // implicit import declaration to capture it in the AST. - if (!IsInModuleIncludes) { + if (ShouldAddImport) { TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl(); ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU, DirectiveLoc, Mod, @@ -14711,7 +15133,7 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) { TU->addDecl(ImportD); Consumer.HandleImplicitImportDecl(ImportD); } - + getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc); VisibleModules.setVisible(Mod, DirectiveLoc); } @@ -14731,6 +15153,9 @@ void Sema::ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod) { VisibleModules = std::move(VisibleModulesStack.back()); VisibleModulesStack.pop_back(); VisibleModules.setVisible(Mod, DirectiveLoc); + // Leaving a module hides namespace names, so our visible namespace cache + // is now out of date. + VisibleNamespaceCache.clear(); } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp index f94c822b90f5..a5780a7d71fb 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/Sema/SemaInternal.h" +#include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclCXX.h" @@ -27,10 +28,12 @@ #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" #include "clang/Sema/DelayedDiagnostic.h" +#include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "llvm/ADT/StringExtras.h" #include "llvm/Support/MathExtras.h" + using namespace clang; using namespace sema; @@ -40,7 +43,7 @@ namespace AttributeLangSupport { Cpp, ObjC }; -} +} // end namespace AttributeLangSupport //===----------------------------------------------------------------------===// // Helper functions @@ -52,6 +55,7 @@ namespace AttributeLangSupport { static bool isFunctionOrMethod(const Decl *D) { return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D); } + /// \brief Return true if the given decl has function type (function or /// function-typed variable) or an Objective-C method or a block. static bool isFunctionOrMethodOrBlock(const Decl *D) { @@ -801,6 +805,8 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D, } static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.Diag(Attr.getLoc(), diag::ext_clang_enable_if); + Expr *Cond = Attr.getArgAsExpr(0); if (!Cond->isTypeDependent()) { ExprResult Converted = S.PerformContextuallyConvertToBool(Cond); @@ -887,7 +893,6 @@ static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } - static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, const AttributeList &Attr) { ASTContext &CurrContext = S.getASTContext(); @@ -905,7 +910,6 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD, return true; } - static void handleCallableWhenAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) @@ -944,7 +948,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D, States.size(), Attr.getAttributeSpellingListIndex())); } - static void handleParamTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ParamTypestateAttr::ConsumedState ParamState; @@ -982,7 +985,6 @@ static void handleParamTypestateAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } - static void handleReturnTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { ReturnTypestateAttr::ConsumedState ReturnState; @@ -1031,7 +1033,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } - static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr)) return; @@ -1548,6 +1549,28 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) { + StringRef Str; + if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Aliases should be on declarations, not definitions. + const auto *FD = cast<FunctionDecl>(D); + if (FD->isThisDeclarationADefinition()) { + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1; + return; + } + // FIXME: it should be handled as a target specific attribute. + if (S.Context.getTargetInfo().getTriple().getObjectFormat() != + llvm::Triple::ELF) { + S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName(); + return; + } + + D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str, + Attr.getAttributeSpellingListIndex())); +} + static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef Str; if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str)) @@ -1557,17 +1580,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) { S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin); return; } + if (S.Context.getTargetInfo().getTriple().isNVPTX()) { + S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx); + } // Aliases should be on declarations, not definitions. if (const auto *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isThisDeclarationADefinition()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0; return; } } else { const auto *VD = cast<VarDecl>(D); if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) { - S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD; + S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0; return; } } @@ -1804,6 +1830,28 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) { Attr.getAttributeSpellingListIndex())); } +static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName(); + + if (IsCXX1zAttr && isa<VarDecl>(D)) { + // The C++1z spelling of this attribute cannot be applied to a static data + // member per [dcl.attr.unused]p2. + if (cast<VarDecl>(D)->isStaticDataMember()) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedForMaybeUnused; + return; + } + } + + // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // about using it as an extension. + if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr) + S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + + D->addAttr(::new (S.Context) UnusedAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) { uint32_t priority = ConstructorAttr::DefaultPriority; if (Attr.getNumArgs() && @@ -1910,11 +1958,14 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y, AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, IdentifierInfo *Platform, + bool Implicit, VersionTuple Introduced, VersionTuple Deprecated, VersionTuple Obsoleted, bool IsUnavailable, StringRef Message, + bool IsStrict, + StringRef Replacement, AvailabilityMergeKind AMK, unsigned AttrSpellingListIndex) { VersionTuple MergedIntroduced = Introduced; @@ -1952,14 +2003,14 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, // If there is an existing availability attribute for this platform that // is explicit and the new one is implicit use the explicit one and // discard the new implicit attribute. - if (OldAA->getRange().isValid() && Range.isInvalid()) { + if (!OldAA->isImplicit() && Implicit) { return nullptr; } // If there is an existing attribute for this platform that is implicit // and the new attribute is explicit then erase the old one and // continue processing the attributes. - if (Range.isValid() && OldAA->getRange().isInvalid()) { + if (!Implicit && OldAA->isImplicit()) { Attrs.erase(Attrs.begin() + i); --e; continue; @@ -2058,10 +2109,13 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range, if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced, MergedDeprecated, MergedObsoleted) && !OverrideOrImpl) { - return ::new (Context) AvailabilityAttr(Range, Context, Platform, + auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform, Introduced, Deprecated, Obsoleted, IsUnavailable, Message, + IsStrict, Replacement, AttrSpellingListIndex); + Avail->setImplicit(Implicit); + return Avail; } return nullptr; } @@ -2088,16 +2142,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated(); AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted(); bool IsUnavailable = Attr.getUnavailableLoc().isValid(); + bool IsStrict = Attr.getStrictLoc().isValid(); StringRef Str; if (const StringLiteral *SE = dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr())) Str = SE->getString(); + StringRef Replacement; + if (const StringLiteral *SE = + dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr())) + Replacement = SE->getString(); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II, + false/*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, + IsStrict, Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2136,12 +2197,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version); AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - SourceRange(), + Attr.getRange(), NewII, + true/*Implicit*/, NewIntroduced, NewDeprecated, NewObsoleted, IsUnavailable, Str, + IsStrict, + Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2158,12 +2222,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D, if (NewII) { AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, - SourceRange(), + Attr.getRange(), NewII, + true/*Implicit*/, Introduced.Version, Deprecated.Version, Obsoleted.Version, IsUnavailable, Str, + IsStrict, + Replacement, Sema::AMK_None, Index); if (NewAttr) @@ -2455,6 +2522,12 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr) return; } + // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // about using it as an extension. + if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() && + !Attr.getScopeName()) + S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName(); + D->addAttr(::new (S.Context) WarnUnusedResultAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -2611,7 +2684,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) { D->addAttr(NewAttr); } - static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) { VarDecl *VD = cast<VarDecl>(D); if (!VD->hasLocalStorage()) { @@ -3069,7 +3141,6 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E, // Save dependent expressions in the AST to be instantiated. D->addAttr(::new (Context) AlignValueAttr(TmpAttr)); - return; } static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3293,6 +3364,8 @@ bool Sema::checkMSInheritanceAttrOnDefinition( /// attribute. static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, bool &IntegerMode, bool &ComplexMode) { + IntegerMode = true; + ComplexMode = false; switch (Str.size()) { case 2: switch (Str[0]) { @@ -3328,7 +3401,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth, // FIXME: glibc uses 'word' to define register_t; this is narrower than a // pointer on PIC16 and other embedded platforms. if (Str == "word") - DestWidth = S.Context.getTargetInfo().getPointerWidth(0); + DestWidth = S.Context.getTargetInfo().getRegisterWidth(); else if (Str == "byte") DestWidth = S.Context.getTargetInfo().getCharWidth(); break; @@ -3359,9 +3432,15 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { } IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident; - StringRef Str = Name->getName(); + S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex()); +} + +void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name, + unsigned SpellingListIndex, bool InInstantiation) { + StringRef Str = Name->getName(); normalizeName(Str); + SourceLocation AttrLoc = AttrRange.getBegin(); unsigned DestWidth = 0; bool IntegerMode = true; @@ -3377,25 +3456,43 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (VectorStringLength && !Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) && VectorSize.isPowerOf2()) { - parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth, + parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth, IntegerMode, ComplexMode); - S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated); + // Avoid duplicate warning from template instantiation. + if (!InInstantiation) + Diag(AttrLoc, diag::warn_vector_mode_deprecated); } else { VectorSize = 0; } } if (!VectorSize) - parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode); + parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode); + + // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t + // and friends, at least with glibc. + // FIXME: Make sure floating-point mappings are accurate + // FIXME: Support XF and TF types + if (!DestWidth) { + Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name; + return; + } QualType OldTy; if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) OldTy = TD->getUnderlyingType(); - else if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) - OldTy = VD->getType(); - else { - S.Diag(D->getLocation(), diag::err_attr_wrong_decl) - << Attr.getName() << Attr.getRange(); + else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) { + // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'. + // Try to get type from enum declaration, default to int. + OldTy = ED->getIntegerType(); + if (OldTy.isNull()) + OldTy = Context.IntTy; + } else + OldTy = cast<ValueDecl>(D)->getType(); + + if (OldTy->isDependentType()) { + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); return; } @@ -3405,91 +3502,83 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (const VectorType *VT = OldTy->getAs<VectorType>()) OldElemTy = VT->getElementType(); - if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_not_primitive); + // GCC allows 'mode' attribute on enumeration types (even incomplete), except + // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete + // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected. + if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) && + VectorSize.getBoolValue()) { + Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange; + return; + } + bool IntegralOrAnyEnumType = + OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>(); + + if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() && + !IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_not_primitive); else if (IntegerMode) { - if (!OldElemTy->isIntegralOrEnumerationType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + if (!IntegralOrAnyEnumType) + Diag(AttrLoc, diag::err_mode_wrong_type); } else if (ComplexMode) { if (!OldElemTy->isComplexType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); } else { if (!OldElemTy->isFloatingType()) - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); - } - - // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t - // and friends, at least with glibc. - // FIXME: Make sure floating-point mappings are accurate - // FIXME: Support XF and TF types - if (!DestWidth) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name; - return; + Diag(AttrLoc, diag::err_mode_wrong_type); } QualType NewElemTy; if (IntegerMode) - NewElemTy = S.Context.getIntTypeForBitwidth( - DestWidth, OldElemTy->isSignedIntegerType()); + NewElemTy = Context.getIntTypeForBitwidth(DestWidth, + OldElemTy->isSignedIntegerType()); else - NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth); + NewElemTy = Context.getRealTypeForBitwidth(DestWidth); if (NewElemTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name; + Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name; return; } if (ComplexMode) { - NewElemTy = S.Context.getComplexType(NewElemTy); + NewElemTy = Context.getComplexType(NewElemTy); } QualType NewTy = NewElemTy; if (VectorSize.getBoolValue()) { - NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(), - VectorType::GenericVector); + NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(), + VectorType::GenericVector); } else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) { // Complex machine mode does not support base vector types. if (ComplexMode) { - S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type); + Diag(AttrLoc, diag::err_complex_mode_vector_type); return; } - unsigned NumElements = S.Context.getTypeSize(OldElemTy) * + unsigned NumElements = Context.getTypeSize(OldElemTy) * OldVT->getNumElements() / - S.Context.getTypeSize(NewElemTy); + Context.getTypeSize(NewElemTy); NewTy = - S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); + Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind()); } if (NewTy.isNull()) { - S.Diag(Attr.getLoc(), diag::err_mode_wrong_type); + Diag(AttrLoc, diag::err_mode_wrong_type); return; } // Install the new type. if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D)) TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy); + else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) + ED->setIntegerType(NewTy); else cast<ValueDecl>(D)->setType(NewTy); - D->addAttr(::new (S.Context) - ModeAttr(Attr.getRange(), S.Context, Name, - Attr.getAttributeSpellingListIndex())); + D->addAttr(::new (Context) + ModeAttr(AttrRange, Context, Name, SpellingListIndex)); } static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) { - if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { - if (!VD->hasGlobalStorage()) - S.Diag(Attr.getLoc(), - diag::warn_attribute_requires_functions_or_static_globals) - << Attr.getName(); - } else if (!isFunctionOrMethod(D)) { - S.Diag(Attr.getLoc(), - diag::warn_attribute_requires_functions_or_static_globals) - << Attr.getName(); - return; - } - D->addAttr(::new (S.Context) NoDebugAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); @@ -3622,11 +3711,21 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) { : FixItHint()); return; } + if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) { + if (Method->isInstance()) { + S.Diag(Method->getLocStart(), diag::err_kern_is_nonstatic_method) + << Method; + return; + } + S.Diag(Method->getLocStart(), diag::warn_kern_is_method) << Method; + } + // Only warn for "inline" when compiling for host, to cut down on noise. + if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice) + S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD; D->addAttr(::new (S.Context) CUDAGlobalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); - } static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) { @@ -3682,6 +3781,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { PascalAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; + case AttributeList::AT_SwiftCall: + D->addAttr(::new (S.Context) + SwiftCallAttr(Attr.getRange(), S.Context, + Attr.getAttributeSpellingListIndex())); + return; case AttributeList::AT_VectorCall: D->addAttr(::new (S.Context) VectorCallAttr(Attr.getRange(), S.Context, @@ -3720,7 +3824,14 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) { IntelOclBiccAttr(Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); return; - + case AttributeList::AT_PreserveMost: + D->addAttr(::new (S.Context) PreserveMostAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; + case AttributeList::AT_PreserveAll: + D->addAttr(::new (S.Context) PreserveAllAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); + return; default: llvm_unreachable("unexpected attribute kind"); } @@ -3731,6 +3842,11 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, if (attr.isInvalid()) return true; + if (attr.hasProcessingCache()) { + CC = (CallingConv) attr.getProcessingCache(); + return false; + } + unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0; if (!checkAttributeNumArgs(*this, attr, ReqArgs)) { attr.setInvalid(); @@ -3744,6 +3860,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, case AttributeList::AT_StdCall: CC = CC_X86StdCall; break; case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break; 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_MSABI: CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C : @@ -3772,6 +3889,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, return true; } case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break; + case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break; + case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break; default: llvm_unreachable("unexpected attribute kind"); } @@ -3783,16 +3902,108 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC, // This convention is not valid for the target. Use the default function or // method calling convention. - TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown; - if (FD) - MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member : - TargetInfo::CCMT_NonMember; - CC = TI.getDefaultCallingConv(MT); + bool IsCXXMethod = false, IsVariadic = false; + if (FD) { + IsCXXMethod = FD->isCXXInstanceMember(); + IsVariadic = FD->isVariadic(); + } + CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod); } + attr.setProcessingCache((unsigned) CC); return false; } +/// Pointer-like types in the default address space. +static bool isValidSwiftContextType(QualType type) { + if (!type->hasPointerRepresentation()) + return type->isDependentType(); + return type->getPointeeType().getAddressSpace() == 0; +} + +/// Pointers and references in the default address space. +static bool isValidSwiftIndirectResultType(QualType type) { + if (auto ptrType = type->getAs<PointerType>()) { + type = ptrType->getPointeeType(); + } else if (auto refType = type->getAs<ReferenceType>()) { + type = refType->getPointeeType(); + } else { + return type->isDependentType(); + } + return type.getAddressSpace() == 0; +} + +/// Pointers and references to pointers in the default address space. +static bool isValidSwiftErrorResultType(QualType type) { + if (auto ptrType = type->getAs<PointerType>()) { + type = ptrType->getPointeeType(); + } else if (auto refType = type->getAs<ReferenceType>()) { + type = refType->getPointeeType(); + } else { + return type->isDependentType(); + } + if (!type.getQualifiers().empty()) + return false; + return isValidSwiftContextType(type); +} + +static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr, + ParameterABI abi) { + S.AddParameterABIAttr(attr.getRange(), D, abi, + attr.getAttributeSpellingListIndex()); +} + +void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi, + unsigned spellingIndex) { + + QualType type = cast<ParmVarDecl>(D)->getType(); + + if (auto existingAttr = D->getAttr<ParameterABIAttr>()) { + if (existingAttr->getABI() != abi) { + Diag(range.getBegin(), diag::err_attributes_are_not_compatible) + << getParameterABISpelling(abi) << existingAttr; + Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); + return; + } + } + + switch (abi) { + case ParameterABI::Ordinary: + llvm_unreachable("explicit attribute for ordinary parameter ABI?"); + + case ParameterABI::SwiftContext: + if (!isValidSwiftContextType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer to pointer */ 0 << type; + } + D->addAttr(::new (Context) + SwiftContextAttr(range, Context, spellingIndex)); + return; + + case ParameterABI::SwiftErrorResult: + if (!isValidSwiftErrorResultType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer to pointer */ 1 << type; + } + D->addAttr(::new (Context) + SwiftErrorResultAttr(range, Context, spellingIndex)); + return; + + case ParameterABI::SwiftIndirectResult: + if (!isValidSwiftIndirectResultType(type)) { + Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type) + << getParameterABISpelling(abi) + << /*pointer*/ 0 << type; + } + D->addAttr(::new (Context) + SwiftIndirectResultAttr(range, Context, spellingIndex)); + return; + } + llvm_unreachable("bad parameter ABI attribute"); +} + /// Checks a regparm attribute, returning true if it is ill-formed and /// otherwise setting numParams to the appropriate value. bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { @@ -3829,49 +4040,60 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) { return false; } -// Checks whether an argument of launch_bounds attribute is acceptable -// May output an error. -static bool checkLaunchBoundsArgument(Sema &S, Expr *E, - const CUDALaunchBoundsAttr &Attr, - const unsigned Idx) { - +// Checks whether an argument of launch_bounds attribute is +// acceptable, performs implicit conversion to Rvalue, and returns +// non-nullptr Expr result on success. Otherwise, it returns nullptr +// and may output an error. +static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E, + const CUDALaunchBoundsAttr &Attr, + const unsigned Idx) { if (S.DiagnoseUnexpandedParameterPack(E)) - return false; + return nullptr; // Accept template arguments for now as they depend on something else. // We'll get to check them when they eventually get instantiated. if (E->isValueDependent()) - return true; + return E; llvm::APSInt I(64); if (!E->isIntegerConstantExpr(I, S.Context)) { S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type) << &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange(); - return false; + return nullptr; } // Make sure we can fit it in 32 bits. if (!I.isIntN(32)) { S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false) << 32 << /* Unsigned */ 1; - return false; + return nullptr; } if (I < 0) S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative) << &Attr << Idx << E->getSourceRange(); - return true; + // We may need to perform implicit conversion of the argument. + InitializedEntity Entity = InitializedEntity::InitializeParameter( + S.Context, S.Context.getConstType(S.Context.IntTy), /*consume*/ false); + ExprResult ValArg = S.PerformCopyInitialization(Entity, SourceLocation(), E); + assert(!ValArg.isInvalid() && + "Unexpected PerformCopyInitialization() failure."); + + return ValArg.getAs<Expr>(); } void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads, Expr *MinBlocks, unsigned SpellingListIndex) { CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex); - - if (!checkLaunchBoundsArgument(*this, MaxThreads, TmpAttr, 0)) + MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0); + if (MaxThreads == nullptr) return; - if (MinBlocks && !checkLaunchBoundsArgument(*this, MinBlocks, TmpAttr, 1)) - return; + if (MinBlocks) { + MinBlocks = makeLaunchBoundsArgExpr(*this, MinBlocks, TmpAttr, 1); + if (MinBlocks == nullptr) + return; + } D->addAttr(::new (Context) CUDALaunchBoundsAttr( AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex)); @@ -3977,6 +4199,7 @@ static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) { type->isObjCObjectPointerType() || S.Context.isObjCNSObjectType(type); } + static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { return type->isDependentType() || type->isPointerType() || @@ -3984,36 +4207,49 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) { } static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) { + S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(), + Attr.getKind() == AttributeList::AT_NSConsumed, + /*template instantiation*/ false); +} + +void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D, + unsigned spellingIndex, bool isNSConsumed, + bool isTemplateInstantiation) { ParmVarDecl *param = cast<ParmVarDecl>(D); - bool typeOK, cf; + bool typeOK; - if (Attr.getKind() == AttributeList::AT_NSConsumed) { - typeOK = isValidSubjectOfNSAttribute(S, param->getType()); - cf = false; + if (isNSConsumed) { + typeOK = isValidSubjectOfNSAttribute(*this, param->getType()); } else { - typeOK = isValidSubjectOfCFAttribute(S, param->getType()); - cf = true; + typeOK = isValidSubjectOfCFAttribute(*this, param->getType()); } if (!typeOK) { - S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type) - << Attr.getRange() << Attr.getName() << cf; - return; - } - - if (cf) - param->addAttr(::new (S.Context) - CFConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + // These attributes are normally just advisory, but in ARC, ns_consumed + // is significant. Allow non-dependent code to contain inappropriate + // attributes even in ARC, but require template instantiations to be + // set up correctly. + Diag(D->getLocStart(), + (isTemplateInstantiation && isNSConsumed && + getLangOpts().ObjCAutoRefCount + ? diag::err_ns_attribute_wrong_parameter_type + : diag::warn_ns_attribute_wrong_parameter_type)) + << attrRange + << (isNSConsumed ? "ns_consumed" : "cf_consumed") + << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1); + return; + } + + if (isNSConsumed) + param->addAttr(::new (Context) + NSConsumedAttr(attrRange, Context, spellingIndex)); else - param->addAttr(::new (S.Context) - NSConsumedAttr(Attr.getRange(), S.Context, - Attr.getAttributeSpellingListIndex())); + param->addAttr(::new (Context) + CFConsumedAttr(attrRange, Context, spellingIndex)); } static void handleNSReturnsRetainedAttr(Sema &S, Decl *D, const AttributeList &Attr) { - QualType returnType; if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) @@ -4287,10 +4523,9 @@ static void handleObjCRuntimeName(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } -// when a user wants to use objc_boxable with a union or struct -// but she doesn't have access to the declaration (legacy/third-party code) -// then she can 'enable' this feature via trick with a typedef -// e.g.: +// When a user wants to use objc_boxable with a union or struct +// but they don't have access to the declaration (legacy/third-party code) +// then they can 'enable' this feature with a typedef: // typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct; static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) { bool notify = false; @@ -4423,8 +4658,10 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr) D, Attr.getRange(), /*BestCase=*/true, Attr.getAttributeSpellingListIndex(), (MSInheritanceAttr::Spelling)Attr.getSemanticSpelling()); - if (IA) + if (IA) { D->addAttr(IA); + S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D)); + } } static void handleDeclspecThreadAttr(Sema &S, Decl *D, @@ -4446,6 +4683,38 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D, Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); } +static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) { + SmallVector<StringRef, 4> Tags; + for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { + StringRef Tag; + if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag)) + return; + Tags.push_back(Tag); + } + + if (const auto *NS = dyn_cast<NamespaceDecl>(D)) { + if (!NS->isInline()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0; + return; + } + if (NS->isAnonymousNamespace()) { + S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1; + return; + } + if (Attr.getNumArgs() == 0) + Tags.push_back(NS->getName()); + } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) + return; + + // Store tags sorted and without duplicates. + std::sort(Tags.begin(), Tags.end()); + Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end()); + + D->addAttr(::new (S.Context) + AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(), + Attr.getAttributeSpellingListIndex())); +} + static void handleARMInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Check the attribute arguments. @@ -4570,17 +4839,90 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex())); } +static void handleAnyX86InterruptAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // Semantic checks for a function with the 'interrupt' attribute. + // a) Must be a function. + // b) Must have the 'void' return type. + // c) Must take 1 or 2 arguments. + // d) The 1st argument must be a pointer. + // e) The 2nd argument (if any) must be an unsigned integer. + if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) || + CXXMethodDecl::isStaticOverloadedOperator( + cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) { + S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionWithProtoType; + return; + } + // Interrupt handler must have void return type. + if (!getFunctionOrMethodResultType(D)->isVoidType()) { + S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 0; + return; + } + // Interrupt handler must have 1 or 2 parameters. + unsigned NumParams = getFunctionOrMethodNumParams(D); + if (NumParams < 1 || NumParams > 2) { + S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 1; + return; + } + // The first argument must be a pointer. + if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) { + S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 2; + return; + } + // The second argument, if present, must be an unsigned integer. + unsigned TypeSize = + S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64 + ? 64 + : 32; + if (NumParams == 2 && + (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() || + S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) { + S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(), + diag::err_anyx86_interrupt_attribute) + << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86 + ? 0 + : 1) + << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false); + return; + } + D->addAttr(::new (S.Context) AnyX86InterruptAttr( + Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex())); + D->addAttr(UsedAttr::CreateImplicit(S.Context)); +} + static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) { // Dispatch the interrupt attribute based on the current target. - if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430) + switch (S.Context.getTargetInfo().getTriple().getArch()) { + case llvm::Triple::msp430: handleMSP430InterruptAttr(S, D, Attr); - else if (S.Context.getTargetInfo().getTriple().getArch() == - llvm::Triple::mipsel || - S.Context.getTargetInfo().getTriple().getArch() == - llvm::Triple::mips) + break; + case llvm::Triple::mipsel: + case llvm::Triple::mips: handleMipsInterruptAttr(S, D, Attr); - else + break; + case llvm::Triple::x86: + case llvm::Triple::x86_64: + handleAnyX86InterruptAttr(S, D, Attr); + break; + default: handleARMInterruptAttr(S, D, Attr); + break; + } } static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D, @@ -4634,6 +4976,24 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, Attr.getAttributeSpellingListIndex())); } +static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) { + uint32_t Version; + Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0)); + if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version)) + return; + + // TODO: Investigate what happens with the next major version of MSVC. + if (Version != LangOptions::MSVC2015) { + S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds) + << Attr.getName() << Version << VersionExpr->getSourceRange(); + return; + } + + D->addAttr(::new (S.Context) + LayoutVersionAttr(Attr.getRange(), S.Context, Version, + Attr.getAttributeSpellingListIndex())); +} + DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range, unsigned AttrSpellingListIndex) { if (D->hasAttr<DLLExportAttr>()) { @@ -4827,19 +5187,34 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) { } } + // Handle the cases where the attribute has a text message. + StringRef Str, Replacement; + if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) && + !S.checkStringLiteralArgumentAttr(Attr, 0, Str)) + return; + + // Only support a single optional message for Declspec and CXX11. + if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute()) + checkAttributeAtMostNumArgs(S, Attr, 1); + else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) && + !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement)) + return; + if (!S.getLangOpts().CPlusPlus14) if (Attr.isCXX11Attribute() && !(Attr.hasScope() && Attr.getScopeName()->isStr("gnu"))) - S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension); + S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName(); - handleAttrWithMessage<DeprecatedAttr>(S, D, Attr); + D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str, + Replacement, + Attr.getAttributeSpellingListIndex())); } static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) { if (!checkAttributeAtLeastNumArgs(S, Attr, 1)) return; - std::vector<std::string> Sanitizers; + std::vector<StringRef> Sanitizers; for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) { StringRef SanitizerName; @@ -4863,8 +5238,8 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, const AttributeList &Attr) { StringRef AttrName = Attr.getName()->getName(); normalizeName(AttrName); - std::string SanitizerName = - llvm::StringSwitch<std::string>(AttrName) + StringRef SanitizerName = + llvm::StringSwitch<StringRef>(AttrName) .Case("no_address_safety_analysis", "address") .Case("no_sanitize_address", "address") .Case("no_sanitize_thread", "thread") @@ -4882,6 +5257,15 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D, D->addAttr(Internal); } +static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) { + if (S.LangOpts.OpenCLVersion != 200) + S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version) + << Attr.getName() << "2.0" << 0; + else + S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored) + << Attr.getName() << "2.0"; +} + /// Handles semantic checking for features that are common to all attributes, /// such as checking whether a parameter was properly specified, or the correct /// number of arguments were passed, etc. @@ -4923,6 +5307,40 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D, return false; } +static void handleOpenCLAccessAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + if (D->isInvalidDecl()) + return; + + // Check if there is only one access qualifier. + if (D->hasAttr<OpenCLAccessAttr>()) { + S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers) + << D->getSourceRange(); + D->setInvalidDecl(true); + return; + } + + // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an + // image object can be read and written. + // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe + // object. Using the read_write (or __read_write) qualifier with the pipe + // qualifier is a compilation error. + if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) { + const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr(); + if (Attr.getName()->getName().find("read_write") != StringRef::npos) { + if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) { + S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write) + << Attr.getName() << PDecl->getType() << DeclTy->isImageType(); + D->setInvalidDecl(true); + return; + } + } + } + + D->addAttr(::new (S.Context) OpenCLAccessAttr( + Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex())); +} + //===----------------------------------------------------------------------===// // Top Level Sema Entry Points //===----------------------------------------------------------------------===// @@ -4958,8 +5376,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, switch (Attr.getKind()) { default: - // Type attributes are handled elsewhere; silently move on. - assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + if (!Attr.isStmtAttr()) { + // Type attributes are handled elsewhere; silently move on. + assert(Attr.isTypeAttr() && "Non-type attribute not handled"); + break; + } + S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + << Attr.getName() << D->getLocation(); break; case AttributeList::AT_Interrupt: handleInterruptAttr(S, D, Attr); @@ -4993,6 +5416,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_IBOutletCollection: handleIBOutletCollection(S, D, Attr); break; + case AttributeList::AT_IFunc: + handleIFuncAttr(S, D, Attr); + break; case AttributeList::AT_Alias: handleAliasAttr(S, D, Attr); break; @@ -5141,53 +5567,45 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecReturn: handleVecReturnAttr(S, D, Attr); break; - case AttributeList::AT_ObjCOwnership: handleObjCOwnershipAttr(S, D, Attr); break; case AttributeList::AT_ObjCPreciseLifetime: handleObjCPreciseLifetimeAttr(S, D, Attr); break; - case AttributeList::AT_ObjCReturnsInnerPointer: handleObjCReturnsInnerPointerAttr(S, D, Attr); break; - case AttributeList::AT_ObjCRequiresSuper: handleObjCRequiresSuperAttr(S, D, Attr); break; - case AttributeList::AT_ObjCBridge: handleObjCBridgeAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCBridgeMutable: handleObjCBridgeMutableAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCBridgeRelated: handleObjCBridgeRelatedAttr(S, scope, D, Attr); break; - case AttributeList::AT_ObjCDesignatedInitializer: handleObjCDesignatedInitializer(S, D, Attr); break; - case AttributeList::AT_ObjCRuntimeName: handleObjCRuntimeName(S, D, Attr); break; - + case AttributeList::AT_ObjCRuntimeVisible: + handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr); + break; case AttributeList::AT_ObjCBoxable: handleObjCBoxable(S, D, Attr); break; - case AttributeList::AT_CFAuditedTransfer: handleCFAuditedTransferAttr(S, D, Attr); break; case AttributeList::AT_CFUnknownTransfer: handleCFUnknownTransferAttr(S, D, Attr); break; - case AttributeList::AT_CFConsumed: case AttributeList::AT_NSConsumed: handleNSConsumedAttr(S, D, Attr); @@ -5195,7 +5613,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_NSConsumesSelf: handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr); break; - case AttributeList::AT_NSReturnsAutoreleased: case AttributeList::AT_NSReturnsNotRetained: case AttributeList::AT_CFReturnsNotRetained: @@ -5212,11 +5629,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_VecTypeHint: handleVecTypeHint(S, D, Attr); break; - case AttributeList::AT_InitPriority: handleInitPriorityAttr(S, D, Attr); break; - case AttributeList::AT_Packed: handlePackedAttr(S, D, Attr); break; @@ -5242,7 +5657,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr); break; case AttributeList::AT_Unused: - handleSimpleAttribute<UnusedAttr>(S, D, Attr); + handleUnusedAttr(S, D, Attr); break; case AttributeList::AT_ReturnsTwice: handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr); @@ -5324,24 +5739,48 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_FastCall: case AttributeList::AT_ThisCall: case AttributeList::AT_Pascal: + case AttributeList::AT_SwiftCall: case AttributeList::AT_VectorCall: case AttributeList::AT_MSABI: case AttributeList::AT_SysVABI: case AttributeList::AT_Pcs: case AttributeList::AT_IntelOclBicc: + case AttributeList::AT_PreserveMost: + case AttributeList::AT_PreserveAll: handleCallConvAttr(S, D, Attr); break; case AttributeList::AT_OpenCLKernel: handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr); break; - case AttributeList::AT_OpenCLImageAccess: - handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr); + case AttributeList::AT_OpenCLAccess: + handleOpenCLAccessAttr(S, D, Attr); + break; + case AttributeList::AT_OpenCLNoSVM: + handleOpenCLNoSVMAttr(S, D, Attr); + break; + case AttributeList::AT_SwiftContext: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext); + break; + case AttributeList::AT_SwiftErrorResult: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult); + break; + case AttributeList::AT_SwiftIndirectResult: + handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult); break; case AttributeList::AT_InternalLinkage: handleInternalLinkageAttr(S, D, Attr); break; + case AttributeList::AT_LTOVisibilityPublic: + handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr); + break; // Microsoft attributes: + case AttributeList::AT_EmptyBases: + handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr); + break; + case AttributeList::AT_LayoutVersion: + handleLayoutVersion(S, D, Attr); + break; case AttributeList::AT_MSNoVTable: handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr); break; @@ -5361,6 +5800,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, handleDeclspecThreadAttr(S, D, Attr); break; + case AttributeList::AT_AbiTag: + handleAbiTagAttr(S, D, Attr); + break; + // Thread safety attributes: case AttributeList::AT_AssertExclusiveLock: handleAssertExclusiveLockAttr(S, D, Attr); @@ -5466,6 +5909,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_TypeTagForDatatype: handleTypeTagForDatatypeAttr(S, D, Attr); break; + case AttributeList::AT_RenderScriptKernel: + handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr); + break; + // XRay attributes. + case AttributeList::AT_XRayInstrument: + handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr); + break; } } @@ -5744,7 +6194,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag, diag.Triggered = true; } - static bool isDeclDeprecated(Decl *D) { do { if (D->isDeprecated()) @@ -5769,6 +6218,34 @@ static bool isDeclUnavailable(Decl *D) { return false; } +static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context, + const Decl *D) { + // Check each AvailabilityAttr to find the one for this platform. + for (const auto *A : D->attrs()) { + if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) { + // FIXME: this is copied from CheckAvailability. We should try to + // de-duplicate. + + // Check if this is an App Extension "platform", and if so chop off + // the suffix for matching with the actual platform. + StringRef ActualPlatform = Avail->getPlatform()->getName(); + StringRef RealizedPlatform = ActualPlatform; + if (Context.getLangOpts().AppExt) { + size_t suffix = RealizedPlatform.rfind("_app_extension"); + if (suffix != StringRef::npos) + RealizedPlatform = RealizedPlatform.slice(0, suffix); + } + + StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); + + // Match the platform name. + if (RealizedPlatform == TargetPlatform) + return Avail; + } + } + return nullptr; +} + static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, Decl *Ctx, const NamedDecl *D, StringRef Message, SourceLocation Loc, @@ -5850,7 +6327,6 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, } } } - break; case Sema::AD_Partial: @@ -5862,23 +6338,61 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K, break; } + CharSourceRange UseRange; + StringRef Replacement; + if (K == Sema::AD_Deprecation) { + if (auto attr = D->getAttr<DeprecatedAttr>()) + Replacement = attr->getReplacement(); + if (auto attr = getAttrForPlatform(S.Context, D)) + Replacement = attr->getReplacement(); + + if (!Replacement.empty()) + UseRange = + CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc)); + } + if (!Message.empty()) { - S.Diag(Loc, diag_message) << D << Message; + S.Diag(Loc, diag_message) << D << Message + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else if (!UnknownObjCClass) { - S.Diag(Loc, diag) << D; + S.Diag(Loc, diag) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); if (ObjCProperty) S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute) << ObjCProperty->getDeclName() << property_note_select; } else { - S.Diag(Loc, diag_fwdclass_message) << D; + S.Diag(Loc, diag_fwdclass_message) << D + << (UseRange.isValid() ? + FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint()); S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class); } - S.Diag(D->getLocation(), diag_available_here) - << D << available_here_select_kind; + // The declaration can have multiple availability attributes, we are looking + // at one of them. + const AvailabilityAttr *A = getAttrForPlatform(S.Context, D); + if (A && A->isInherited()) { + for (const Decl *Redecl = D->getMostRecentDecl(); Redecl; + Redecl = Redecl->getPreviousDecl()) { + const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context, + Redecl); + if (AForRedecl && !AForRedecl->isInherited()) { + // If D is a declaration with inherited attributes, the note should + // point to the declaration with actual attributes. + S.Diag(Redecl->getLocation(), diag_available_here) << D + << available_here_select_kind; + break; + } + } + } + else + S.Diag(D->getLocation(), diag_available_here) + << D << available_here_select_kind; + if (K == Sema::AD_Partial) S.Diag(Loc, diag::note_partial_availability_silence) << D; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp index 82d81a85fa90..e161c87f1739 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp @@ -471,7 +471,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old, continue; } - // We found our guy. + // We found the right previous declaration. break; } @@ -3356,34 +3356,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor, ExprResult BaseInit; switch (ImplicitInitKind) { - case IIK_Inherit: { - const CXXRecordDecl *Inherited = - Constructor->getInheritedConstructor()->getParent(); - const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl(); - if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) { - // C++11 [class.inhctor]p8: - // Each expression in the expression-list is of the form - // static_cast<T&&>(p), where p is the name of the corresponding - // constructor parameter and T is the declared type of p. - SmallVector<Expr*, 16> Args; - for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) { - ParmVarDecl *PD = Constructor->getParamDecl(I); - ExprResult ArgExpr = - SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(), - VK_LValue, SourceLocation()); - if (ArgExpr.isInvalid()) - return true; - Args.push_back(CastForMoving(SemaRef, ArgExpr.get(), PD->getType())); - } - - InitializationKind InitKind = InitializationKind::CreateDirect( - Constructor->getLocation(), SourceLocation(), SourceLocation()); - InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args); - BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args); - break; - } - } - // Fall through. + case IIK_Inherit: case IIK_Default: { InitializationKind InitKind = InitializationKind::CreateDefault(Constructor->getLocation()); @@ -3694,12 +3667,12 @@ struct BaseAndFieldInfo { BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits) : S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) { bool Generated = Ctor->isImplicit() || Ctor->isDefaulted(); - if (Generated && Ctor->isCopyConstructor()) + if (Ctor->getInheritedConstructor()) + IIK = IIK_Inherit; + else if (Generated && Ctor->isCopyConstructor()) IIK = IIK_Copy; else if (Generated && Ctor->isMoveConstructor()) IIK = IIK_Move; - else if (Ctor->getInheritedConstructor()) - IIK = IIK_Inherit; else IIK = IIK_Default; } @@ -4774,7 +4747,6 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { // The class is either imported or exported. const bool ClassExported = ClassAttr->getKind() == attr::DLLExport; - const bool ClassImported = !ClassExported; TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind(); @@ -4809,11 +4781,20 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) { if (!Context.getTargetInfo().getCXXABI().isMicrosoft()) continue; - // MSVC versions before 2015 don't export the move assignment operators, - // so don't attempt to import them if we have a definition. - if (ClassImported && MD->isMoveAssignmentOperator() && + // MSVC versions before 2015 don't export the move assignment operators + // and move constructor, so don't attempt to import/export them if + // we have a definition. + auto *Ctor = dyn_cast<CXXConstructorDecl>(MD); + if ((MD->isMoveAssignmentOperator() || + (Ctor && Ctor->isMoveConstructor())) && !getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015)) continue; + + // MSVC2015 doesn't export trivial defaulted x-tor but copy assign + // operator is exported anyway. + if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && + (Ctor || isa<CXXDestructorDecl>(MD)) && MD->isTrivial()) + continue; } } @@ -4887,6 +4868,33 @@ void Sema::propagateDLLAttrToBaseClassTemplate( } } +static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD, + SourceLocation DefaultLoc) { + switch (S.getSpecialMember(MD)) { + case Sema::CXXDefaultConstructor: + S.DefineImplicitDefaultConstructor(DefaultLoc, + cast<CXXConstructorDecl>(MD)); + break; + case Sema::CXXCopyConstructor: + S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + break; + case Sema::CXXCopyAssignment: + S.DefineImplicitCopyAssignment(DefaultLoc, MD); + break; + case Sema::CXXDestructor: + S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD)); + break; + case Sema::CXXMoveConstructor: + S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); + break; + case Sema::CXXMoveAssignment: + S.DefineImplicitMoveAssignment(DefaultLoc, MD); + break; + case Sema::CXXInvalid: + llvm_unreachable("Invalid special member."); + } +} + /// \brief Perform semantic checks on a class definition that has been /// completing, introducing implicitly-declared members, checking for /// abstract types, etc. @@ -4982,8 +4990,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { // For an explicitly defaulted or deleted special member, we defer // determining triviality until the class is complete. That time is now! + CXXSpecialMember CSM = getSpecialMember(M); if (!M->isImplicit() && !M->isUserProvided()) { - CXXSpecialMember CSM = getSpecialMember(M); if (CSM != CXXInvalid) { M->setTrivial(SpecialMemberIsTrivial(M, CSM)); @@ -4991,6 +4999,20 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { Record->finishedDefaultedOrDeletedMember(M); } } + + if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() && + M->hasAttr<DLLExportAttr>()) { + if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) && + M->isTrivial() && + (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor || + CSM == CXXDestructor)) + M->dropAttr<DLLExportAttr>(); + + if (M->hasAttr<DLLExportAttr>()) { + DefineImplicitSpecialMember(*this, M, M->getLocation()); + ActOnFinishInlineFunctionDef(M); + } + } } } @@ -5016,15 +5038,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) { Diag(Record->getLocation(), diag::warn_cxx_ms_struct); } - // Declare inheriting constructors. We do this eagerly here because: - // - The standard requires an eager diagnostic for conflicting inheriting - // constructors from different classes. - // - The lazy declaration of the other implicit constructors is so as to not - // waste space and performance on classes that are not meant to be - // instantiated (e.g. meta-functions). This doesn't apply to classes that - // have inheriting constructors. - DeclareInheritingConstructors(Record); - checkClassLevelDLLAttribute(Record); } @@ -5058,11 +5071,108 @@ static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember( LHSQuals & Qualifiers::Volatile); } +class Sema::InheritedConstructorInfo { + Sema &S; + SourceLocation UseLoc; + + /// A mapping from the base classes through which the constructor was + /// inherited to the using shadow declaration in that base class (or a null + /// pointer if the constructor was declared in that base class). + llvm::DenseMap<CXXRecordDecl *, ConstructorUsingShadowDecl *> + InheritedFromBases; + +public: + InheritedConstructorInfo(Sema &S, SourceLocation UseLoc, + ConstructorUsingShadowDecl *Shadow) + : S(S), UseLoc(UseLoc) { + bool DiagnosedMultipleConstructedBases = false; + CXXRecordDecl *ConstructedBase = nullptr; + UsingDecl *ConstructedBaseUsing = nullptr; + + // Find the set of such base class subobjects and check that there's a + // unique constructed subobject. + for (auto *D : Shadow->redecls()) { + auto *DShadow = cast<ConstructorUsingShadowDecl>(D); + auto *DNominatedBase = DShadow->getNominatedBaseClass(); + auto *DConstructedBase = DShadow->getConstructedBaseClass(); + + InheritedFromBases.insert( + std::make_pair(DNominatedBase->getCanonicalDecl(), + DShadow->getNominatedBaseClassShadowDecl())); + if (DShadow->constructsVirtualBase()) + InheritedFromBases.insert( + std::make_pair(DConstructedBase->getCanonicalDecl(), + DShadow->getConstructedBaseClassShadowDecl())); + else + assert(DNominatedBase == DConstructedBase); + + // [class.inhctor.init]p2: + // If the constructor was inherited from multiple base class subobjects + // of type B, the program is ill-formed. + if (!ConstructedBase) { + ConstructedBase = DConstructedBase; + ConstructedBaseUsing = D->getUsingDecl(); + } else if (ConstructedBase != DConstructedBase && + !Shadow->isInvalidDecl()) { + if (!DiagnosedMultipleConstructedBases) { + S.Diag(UseLoc, diag::err_ambiguous_inherited_constructor) + << Shadow->getTargetDecl(); + S.Diag(ConstructedBaseUsing->getLocation(), + diag::note_ambiguous_inherited_constructor_using) + << ConstructedBase; + DiagnosedMultipleConstructedBases = true; + } + S.Diag(D->getUsingDecl()->getLocation(), + diag::note_ambiguous_inherited_constructor_using) + << DConstructedBase; + } + } + + if (DiagnosedMultipleConstructedBases) + Shadow->setInvalidDecl(); + } + + /// Find the constructor to use for inherited construction of a base class, + /// and whether that base class constructor inherits the constructor from a + /// virtual base class (in which case it won't actually invoke it). + std::pair<CXXConstructorDecl *, bool> + findConstructorForBase(CXXRecordDecl *Base, CXXConstructorDecl *Ctor) const { + auto It = InheritedFromBases.find(Base->getCanonicalDecl()); + if (It == InheritedFromBases.end()) + return std::make_pair(nullptr, false); + + // This is an intermediary class. + if (It->second) + return std::make_pair( + S.findInheritingConstructor(UseLoc, Ctor, It->second), + It->second->constructsVirtualBase()); + + // This is the base class from which the constructor was inherited. + return std::make_pair(Ctor, false); + } +}; + /// Is the special member function which would be selected to perform the /// specified operation on the specified class type a constexpr constructor? -static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, - Sema::CXXSpecialMember CSM, - unsigned Quals, bool ConstRHS) { +static bool +specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, + Sema::CXXSpecialMember CSM, unsigned Quals, + bool ConstRHS, + CXXConstructorDecl *InheritedCtor = nullptr, + Sema::InheritedConstructorInfo *Inherited = nullptr) { + // If we're inheriting a constructor, see if we need to call it for this base + // class. + if (InheritedCtor) { + assert(CSM == Sema::CXXDefaultConstructor); + auto BaseCtor = + Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first; + if (BaseCtor) + return BaseCtor->isConstexpr(); + } + + if (CSM == Sema::CXXDefaultConstructor) + return ClassDecl->hasConstexprDefaultConstructor(); + Sema::SpecialMemberOverloadResult *SMOR = lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS); if (!SMOR || !SMOR->getMethod()) @@ -5074,9 +5184,10 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, /// Determine whether the specified special member function would be constexpr /// if it were implicitly defined. -static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, - Sema::CXXSpecialMember CSM, - bool ConstArg) { +static bool defaultedSpecialMemberIsConstexpr( + Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM, + bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr, + Sema::InheritedConstructorInfo *Inherited = nullptr) { if (!S.getLangOpts().CPlusPlus11) return false; @@ -5085,6 +5196,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, bool Ctor = true; switch (CSM) { case Sema::CXXDefaultConstructor: + if (Inherited) + break; // Since default constructor lookup is essentially trivial (and cannot // involve, for instance, template instantiation), we compute whether a // defaulted default constructor is constexpr directly within CXXRecordDecl. @@ -5119,7 +5232,10 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, // will be initialized (if the constructor isn't deleted), we just don't know // which one. if (Ctor && ClassDecl->isUnion()) - return true; + return CSM == Sema::CXXDefaultConstructor + ? ClassDecl->hasInClassInitializer() || + !ClassDecl->hasVariantMembers() + : true; // -- the class shall not have any virtual base classes; if (Ctor && ClassDecl->getNumVBases()) @@ -5139,7 +5255,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, if (!BaseType) continue; CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg)) + if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg, + InheritedCtor, Inherited)) return false; } @@ -5153,6 +5270,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, for (const auto *F : ClassDecl->fields()) { if (F->isInvalidDecl()) continue; + if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer()) + continue; QualType BaseType = S.Context.getBaseElementType(F->getType()); if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) { CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl()); @@ -5160,6 +5279,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl, BaseType.getCVRQualifiers(), ConstArg && !F->isMutable())) return false; + } else if (CSM == Sema::CXXDefaultConstructor) { + return false; } } @@ -5187,7 +5308,8 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) { } assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() && "only special members have implicit exception specs"); - return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD)); + return S.ComputeInheritingCtorExceptionSpec(Loc, + cast<CXXConstructorDecl>(MD)); } static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S, @@ -5384,7 +5506,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) { // [For a] user-provided explicitly-defaulted function [...] if such a // function is implicitly defined as deleted, the program is ill-formed. Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM; - ShouldDeleteSpecialMember(MD, CSM, /*Diagnose*/true); + ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true); HadError = true; } } @@ -5445,6 +5567,7 @@ struct SpecialMemberDeletionInfo { Sema &S; CXXMethodDecl *MD; Sema::CXXSpecialMember CSM; + Sema::InheritedConstructorInfo *ICI; bool Diagnose; // Properties of the special member, computed for convenience. @@ -5454,11 +5577,11 @@ struct SpecialMemberDeletionInfo { bool AllFieldsAreConst; SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD, - Sema::CXXSpecialMember CSM, bool Diagnose) - : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose), - IsConstructor(false), IsAssignment(false), IsMove(false), - ConstArg(false), Loc(MD->getLocation()), - AllFieldsAreConst(true) { + Sema::CXXSpecialMember CSM, + Sema::InheritedConstructorInfo *ICI, bool Diagnose) + : S(S), MD(MD), CSM(CSM), ICI(ICI), Diagnose(Diagnose), + IsConstructor(false), IsAssignment(false), IsMove(false), + ConstArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) { switch (CSM) { case Sema::CXXDefaultConstructor: case Sema::CXXCopyConstructor: @@ -5490,6 +5613,10 @@ struct SpecialMemberDeletionInfo { bool inUnion() const { return MD->getParent()->isUnion(); } + Sema::CXXSpecialMember getEffectiveCSM() { + return ICI ? Sema::CXXInvalid : CSM; + } + /// Look up the corresponding special member in the given class. Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class, unsigned Quals, bool IsMutable) { @@ -5566,13 +5693,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall( if (Field) { S.Diag(Field->getLocation(), diag::note_deleted_special_member_class_subobject) - << CSM << MD->getParent() << /*IsField*/true + << getEffectiveCSM() << MD->getParent() << /*IsField*/true << Field << DiagKind << IsDtorCallInCtor; } else { CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>(); S.Diag(Base->getLocStart(), diag::note_deleted_special_member_class_subobject) - << CSM << MD->getParent() << /*IsField*/false + << getEffectiveCSM() << MD->getParent() << /*IsField*/false << Base->getType() << DiagKind << IsDtorCallInCtor; } @@ -5631,7 +5758,29 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) { CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl(); // If program is correct, BaseClass cannot be null, but if it is, the error // must be reported elsewhere. - return BaseClass && shouldDeleteForClassSubobject(BaseClass, Base, 0); + if (!BaseClass) + return false; + // If we have an inheriting constructor, check whether we're calling an + // inherited constructor instead of a default constructor. + if (ICI) { + assert(CSM == Sema::CXXDefaultConstructor); + auto *BaseCtor = + ICI->findConstructorForBase(BaseClass, cast<CXXConstructorDecl>(MD) + ->getInheritedConstructor() + .getConstructor()) + .first; + if (BaseCtor) { + if (BaseCtor->isDeleted() && Diagnose) { + S.Diag(Base->getLocStart(), + diag::note_deleted_special_member_class_subobject) + << getEffectiveCSM() << MD->getParent() << /*IsField*/false + << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false; + S.NoteDeletedFunction(BaseCtor); + } + return BaseCtor->isDeleted(); + } + } + return shouldDeleteForClassSubobject(BaseClass, Base, 0); } /// Check whether we should delete a special member function due to the class @@ -5646,7 +5795,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) - << MD->getParent() << FD << FieldType << /*Reference*/0; + << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0; return true; } // C++11 [class.ctor]p5: any non-variant non-static data member of @@ -5658,7 +5807,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { (!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) { if (Diagnose) S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field) - << MD->getParent() << FD << FD->getType() << /*Const*/1; + << !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1; return true; } @@ -5717,7 +5866,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) { if (Diagnose) S.Diag(FieldRecord->getLocation(), diag::note_deleted_default_ctor_all_const) - << MD->getParent() << /*anonymous union*/1; + << !!ICI << MD->getParent() << /*anonymous union*/1; return true; } @@ -5745,7 +5894,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { if (Diagnose) S.Diag(MD->getParent()->getLocation(), diag::note_deleted_default_ctor_all_const) - << MD->getParent() << /*not anonymous union*/0; + << !!ICI << MD->getParent() << /*not anonymous union*/0; return true; } return false; @@ -5755,6 +5904,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() { /// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11, /// C++11 [class.copy]p23, and C++11 [class.dtor]p5. bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, + InheritedConstructorInfo *ICI, bool Diagnose) { if (MD->isInvalidDecl()) return false; @@ -5844,7 +5994,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM, } } - SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose); + SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose); for (auto &BI : RD->bases()) if (!BI.isVirtual() && @@ -6452,27 +6602,33 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc, /// [special]p1). This routine can only be executed just before the /// definition of the class is complete. void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { - if (!ClassDecl->hasUserDeclaredConstructor()) + if (ClassDecl->needsImplicitDefaultConstructor()) { ++ASTContext::NumImplicitDefaultConstructors; - if (!ClassDecl->hasUserDeclaredCopyConstructor()) { + if (ClassDecl->hasInheritedConstructor()) + DeclareImplicitDefaultConstructor(ClassDecl); + } + + if (ClassDecl->needsImplicitCopyConstructor()) { ++ASTContext::NumImplicitCopyConstructors; // If the properties or semantics of the copy constructor couldn't be // determined while the class was being declared, force a declaration // of it now. - if (ClassDecl->needsOverloadResolutionForCopyConstructor()) + if (ClassDecl->needsOverloadResolutionForCopyConstructor() || + ClassDecl->hasInheritedConstructor()) DeclareImplicitCopyConstructor(ClassDecl); } if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) { ++ASTContext::NumImplicitMoveConstructors; - if (ClassDecl->needsOverloadResolutionForMoveConstructor()) + if (ClassDecl->needsOverloadResolutionForMoveConstructor() || + ClassDecl->hasInheritedConstructor()) DeclareImplicitMoveConstructor(ClassDecl); } - if (!ClassDecl->hasUserDeclaredCopyAssignment()) { + if (ClassDecl->needsImplicitCopyAssignment()) { ++ASTContext::NumImplicitCopyAssignmentOperators; // If we have a dynamic class, then the copy assignment operator may be @@ -6480,7 +6636,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // it shows up in the right place in the vtable and that we diagnose // problems with the implicit exception specification. if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForCopyAssignment()) + ClassDecl->needsOverloadResolutionForCopyAssignment() || + ClassDecl->hasInheritedAssignment()) DeclareImplicitCopyAssignment(ClassDecl); } @@ -6489,11 +6646,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) { // Likewise for the move assignment operator. if (ClassDecl->isDynamicClass() || - ClassDecl->needsOverloadResolutionForMoveAssignment()) + ClassDecl->needsOverloadResolutionForMoveAssignment() || + ClassDecl->hasInheritedAssignment()) DeclareImplicitMoveAssignment(ClassDecl); } - if (!ClassDecl->hasUserDeclaredDestructor()) { + if (ClassDecl->needsImplicitDestructor()) { ++ASTContext::NumImplicitDestructors; // If we have a dynamic class, then the destructor may be virtual, so we @@ -7738,7 +7896,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, // function will silently decide not to build a shadow decl, which // will pre-empt further diagnostics. // - // We don't need to do this in C++0x because we do the check once on + // We don't need to do this in C++11 because we do the check once on // the qualifier. // // FIXME: diagnose the following if we care enough: @@ -7796,6 +7954,12 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, for (LookupResult::iterator I = Previous.begin(), E = Previous.end(); I != E; ++I) { NamedDecl *D = (*I)->getUnderlyingDecl(); + // 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)) + continue; + if (IsEquivalentForUsingDecl(Context, D, Target)) { if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I)) PrevShadow = Shadow; @@ -7863,12 +8027,21 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig, return true; } +/// Determine whether a direct base class is a virtual base class. +static bool isVirtualDirectBase(CXXRecordDecl *Derived, CXXRecordDecl *Base) { + if (!Derived->getNumVBases()) + return false; + for (auto &B : Derived->bases()) + if (B.getType()->getAsCXXRecordDecl() == Base) + return B.isVirtual(); + llvm_unreachable("not a direct base class"); +} + /// Builds a shadow declaration corresponding to a 'using' declaration. UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, UsingDecl *UD, NamedDecl *Orig, UsingShadowDecl *PrevDecl) { - // If we resolved to another shadow declaration, just coalesce them. NamedDecl *Target = Orig; if (isa<UsingShadowDecl>(Target)) { @@ -7876,9 +8049,21 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S, assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration"); } - UsingShadowDecl *Shadow - = UsingShadowDecl::Create(Context, CurContext, - UD->getLocation(), UD, Target); + NamedDecl *NonTemplateTarget = Target; + if (auto *TargetTD = dyn_cast<TemplateDecl>(Target)) + NonTemplateTarget = TargetTD->getTemplatedDecl(); + + UsingShadowDecl *Shadow; + if (isa<CXXConstructorDecl>(NonTemplateTarget)) { + bool IsVirtualBase = + isVirtualDirectBase(cast<CXXRecordDecl>(CurContext), + UD->getQualifier()->getAsRecordDecl()); + Shadow = ConstructorUsingShadowDecl::Create( + Context, CurContext, UD->getLocation(), UD, Orig, IsVirtualBase); + } else { + Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD, + Target); + } UD->addShadowDecl(Shadow); Shadow->setAccess(UD->getAccess()); @@ -7980,6 +8165,9 @@ public: if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier()) return false; + // FIXME: Don't correct to a name that CheckUsingDeclRedeclaration would + // reject. + if (RequireMemberOf) { auto *FoundRecord = dyn_cast<CXXRecordDecl>(ND); if (FoundRecord && FoundRecord->isInjectedClassName()) { @@ -8060,8 +8248,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, 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. + DeclarationNameInfo UsingName = NameInfo; + if (UsingName.getName().getNameKind() == DeclarationName::CXXConstructorName) + if (auto *RD = dyn_cast<CXXRecordDecl>(CurContext)) + UsingName.setName(Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(RD)))); + // Do the redeclaration lookup in the current scope. - LookupResult Previous(*this, NameInfo, LookupUsingDeclName, + LookupResult Previous(*this, UsingName, LookupUsingDeclName, ForRedeclaration); Previous.setHideTags(false); if (S) { @@ -8118,8 +8315,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, auto Build = [&](bool Invalid) { UsingDecl *UD = - UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo, - HasTypenameKeyword); + UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, + UsingName, HasTypenameKeyword); UD->setAccess(AS); CurContext->addDecl(UD); UD->setInvalidDecl(Invalid); @@ -8174,6 +8371,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, // If we corrected to an inheriting constructor, handle it as one. auto *RD = dyn_cast<CXXRecordDecl>(ND); if (RD && RD->isInjectedClassName()) { + // The parent of the injected class name is the class itself. + RD = cast<CXXRecordDecl>(RD->getParent()); + // Fix up the information we'll use to build the using declaration. if (Corrected.WillReplaceSpecifier()) { NestedNameSpecifierLocBuilder Builder; @@ -8182,13 +8382,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, QualifierLoc = Builder.getWithLocInContext(Context); } - NameInfo.setName(Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Context.getRecordType(RD)))); - NameInfo.setNamedTypeInfo(nullptr); + // In this case, the name we introduce is the name of a derived class + // constructor. + auto *CurClass = cast<CXXRecordDecl>(CurContext); + UsingName.setName(Context.DeclarationNames.getCXXConstructorName( + Context.getCanonicalType(Context.getRecordType(CurClass)))); + UsingName.setNamedTypeInfo(nullptr); for (auto *Ctor : LookupConstructors(RD)) R.addDecl(Ctor); + R.resolveKind(); } else { - // FIXME: Pick up all the declarations if we found an overloaded function. + // FIXME: Pick up all the declarations if we found an overloaded + // function. + UsingName.setName(ND->getDeclName()); R.addDecl(ND); } } else { @@ -8221,7 +8427,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, } } - // C++0x N2914 [namespace.udecl]p6: + // C++14 [namespace.udecl]p6: // A using-declaration shall not name a namespace. if (R.getAsSingle<NamespaceDecl>()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace) @@ -8229,19 +8435,28 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS, return BuildInvalid(); } + // C++14 [namespace.udecl]p7: + // A using-declaration shall not name a scoped enumerator. + if (auto *ED = R.getAsSingle<EnumConstantDecl>()) { + if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) { + Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum) + << SS.getRange(); + return BuildInvalid(); + } + } + UsingDecl *UD = BuildValid(); - // The normal rules do not apply to inheriting constructor declarations. - if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { + // Some additional rules apply to inheriting constructors. + if (UsingName.getName().getNameKind() == + DeclarationName::CXXConstructorName) { // Suppress access diagnostics; the access check is instead performed at the // point of use for an inheriting constructor. R.suppressDiagnostics(); - CheckInheritingConstructorUsingDecl(UD); - return UD; + if (CheckInheritingConstructorUsingDecl(UD)) + return UD; } - // Otherwise, look up the target name. - for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) { UsingShadowDecl *PrevDecl = nullptr; if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl)) @@ -8353,8 +8568,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, // If we weren't able to compute a valid scope, it must be a // dependent class scope. - if (!NamedContext || NamedContext->isRecord()) { - auto *RD = dyn_cast_or_null<CXXRecordDecl>(NamedContext); + if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) { + auto *RD = NamedContext + ? cast<CXXRecordDecl>(NamedContext->getRedeclContext()) + : nullptr; if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD)) RD = nullptr; @@ -8403,6 +8620,20 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, Diag(UsingLoc, diag::note_using_decl_class_member_workaround) << 2 // reference declaration << FixIt; + } else if (R.getAsSingle<EnumConstantDecl>()) { + // Don't provide a fixit outside C++11 mode; we don't want to suggest + // repeating the type of the enumeration here, and we can't do so if + // the type is anonymous. + FixItHint FixIt; + if (getLangOpts().CPlusPlus11) { + // Convert 'using X::Y;' to 'auto &Y = X::Y;'. + FixIt = FixItHint::CreateReplacement( + UsingLoc, "constexpr auto " + NameInfo.getName().getAsString() + " = "); + } + + Diag(UsingLoc, diag::note_using_decl_class_member_workaround) + << (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable + << FixIt; } return true; } @@ -8438,7 +8669,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, return true; if (getLangOpts().CPlusPlus11) { - // C++0x [namespace.udecl]p3: + // C++11 [namespace.udecl]p3: // In a using-declaration used as a member-declaration, the // nested-name-specifier shall name a base class of the class // being defined. @@ -8579,6 +8810,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, } TemplateParameterList *TemplateParams = TemplateParamLists[0]; + // Check that we can declare a template here. + if (CheckTemplateDeclScope(S, TemplateParams)) + return nullptr; + // Only consider previous declarations in the same scope. FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false, /*ExplicitInstantiationOrSpecialization*/false); @@ -8650,9 +8885,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, NewND = NewTD; } - if (!Redeclaration) - PushOnScopeChains(NewND, S); - + PushOnScopeChains(NewND, S); ActOnDocumentableDecl(NewND); return NewND; } @@ -8796,7 +9029,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc, } Sema::ImplicitExceptionSpecification -Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { +Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc, + CXXConstructorDecl *CD) { CXXRecordDecl *ClassDecl = CD->getParent(); // C++ [except.spec]p14: @@ -8805,36 +9039,26 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) { if (ClassDecl->isInvalidDecl()) return ExceptSpec; - // Inherited constructor. - const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor(); - const CXXRecordDecl *InheritedDecl = InheritedCD->getParent(); - // FIXME: Copying or moving the parameters could add extra exceptions to the - // set, as could the default arguments for the inherited constructor. This - // will be addressed when we implement the resolution of core issue 1351. - ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD); + auto Inherited = CD->getInheritedConstructor(); + InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl()); - // Direct base-class constructors. - for (const auto &B : ClassDecl->bases()) { - if (B.isVirtual()) // Handled below. - continue; - - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (BaseClassDecl == InheritedDecl) + // Direct and virtual base-class constructors. + for (bool VBase : {false, true}) { + for (CXXBaseSpecifier &B : + VBase ? ClassDecl->vbases() : ClassDecl->bases()) { + // Don't visit direct vbases twice. + if (B.isVirtual() != VBase) continue; - CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); - if (Constructor) - ExceptSpec.CalledDecl(B.getLocStart(), Constructor); - } - } - // Virtual base-class constructors. - for (const auto &B : ClassDecl->vbases()) { - if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) { - CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (BaseClassDecl == InheritedDecl) + CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl(); + if (!BaseClass) continue; - CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl); + + CXXConstructorDecl *Constructor = + ICI.findConstructorForBase(BaseClass, Inherited.getConstructor()) + .first; + if (!Constructor) + Constructor = LookupDefaultConstructor(BaseClass); if (Constructor) ExceptSpec.CalledDecl(B.getLocStart(), Constructor); } @@ -8862,10 +9086,11 @@ namespace { struct DeclaringSpecialMember { Sema &S; Sema::SpecialMemberDecl D; + Sema::ContextRAII SavedContext; bool WasAlreadyBeingDeclared; DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM) - : S(S), D(RD, CSM) { + : S(S), D(RD, CSM), SavedContext(S, RD) { WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second; if (WasAlreadyBeingDeclared) // This almost never happens, but if it does, ensure that our cache @@ -8887,6 +9112,21 @@ struct DeclaringSpecialMember { }; } +void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) { + // Look up any existing declarations, but don't trigger declaration of all + // implicit special members with this name. + DeclarationName Name = FD->getDeclName(); + LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName, + ForRedeclaration); + for (auto *D : FD->getParent()->lookup(Name)) + if (auto *Acceptable = R.getAcceptableDecl(D)) + R.addDecl(Acceptable); + R.resolveKind(); + R.suppressDiagnostics(); + + CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false); +} + CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( CXXRecordDecl *ClassDecl) { // C++ [class.ctor]p5: @@ -8935,13 +9175,16 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor( // constructors is easy to compute. DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor()); - if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) - SetDeclDeleted(DefaultCon, ClassLoc); - // Note that we have declared this constructor. ++ASTContext::NumImplicitDefaultConstructorsDeclared; - if (Scope *S = getScopeForContext(ClassDecl)) + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, DefaultCon); + + if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor)) + SetDeclDeleted(DefaultCon, ClassLoc); + + if (S) PushOnScopeChains(DefaultCon, S, false); ClassDecl->addDecl(DefaultCon); @@ -8993,325 +9236,167 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) { CheckDelayedMemberExceptionSpecs(); } -namespace { -/// Information on inheriting constructors to declare. -class InheritingConstructorInfo { -public: - InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived) - : SemaRef(SemaRef), Derived(Derived) { - // Mark the constructors that we already have in the derived class. - // - // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...] - // unless there is a user-declared constructor with the same signature in - // the class where the using-declaration appears. - visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived); - } +/// Find or create the fake constructor we synthesize to model constructing an +/// object of a derived class via a constructor of a base class. +CXXConstructorDecl * +Sema::findInheritingConstructor(SourceLocation Loc, + CXXConstructorDecl *BaseCtor, + ConstructorUsingShadowDecl *Shadow) { + CXXRecordDecl *Derived = Shadow->getParent(); + SourceLocation UsingLoc = Shadow->getLocation(); + + // FIXME: Add a new kind of DeclarationName for an inherited constructor. + // For now we use the name of the base class constructor as a member of the + // derived class to indicate a (fake) inherited constructor name. + DeclarationName Name = BaseCtor->getDeclName(); + + // Check to see if we already have a fake constructor for this inherited + // constructor call. + for (NamedDecl *Ctor : Derived->lookup(Name)) + if (declaresSameEntity(cast<CXXConstructorDecl>(Ctor) + ->getInheritedConstructor() + .getConstructor(), + BaseCtor)) + return cast<CXXConstructorDecl>(Ctor); + + DeclarationNameInfo NameInfo(Name, UsingLoc); + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(BaseCtor->getType(), UsingLoc); + FunctionProtoTypeLoc ProtoLoc = + TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>(); + + // Check the inherited constructor is valid and find the list of base classes + // from which it was inherited. + InheritedConstructorInfo ICI(*this, Loc, Shadow); + + bool Constexpr = + BaseCtor->isConstexpr() && + defaultedSpecialMemberIsConstexpr(*this, Derived, CXXDefaultConstructor, + false, BaseCtor, &ICI); + + CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( + Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo, + BaseCtor->isExplicit(), /*Inline=*/true, + /*ImplicitlyDeclared=*/true, Constexpr, + InheritedConstructor(Shadow, BaseCtor)); + if (Shadow->isInvalidDecl()) + DerivedCtor->setInvalidDecl(); + + // Build an unevaluated exception specification for this fake constructor. + const FunctionProtoType *FPT = TInfo->getType()->castAs<FunctionProtoType>(); + FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); + EPI.ExceptionSpec.Type = EST_Unevaluated; + EPI.ExceptionSpec.SourceDecl = DerivedCtor; + DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(), + FPT->getParamTypes(), EPI)); - void inheritAll(CXXRecordDecl *RD) { - visitAll(RD, &InheritingConstructorInfo::inherit); + // Build the parameter declarations. + SmallVector<ParmVarDecl *, 16> ParamDecls; + for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) { + TypeSourceInfo *TInfo = + Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc); + ParmVarDecl *PD = ParmVarDecl::Create( + Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr, + FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr); + PD->setScopeInfo(0, I); + PD->setImplicit(); + // Ensure attributes are propagated onto parameters (this matters for + // format, pass_object_size, ...). + mergeDeclAttributes(PD, BaseCtor->getParamDecl(I)); + ParamDecls.push_back(PD); + ProtoLoc.setParam(I, PD); } -private: - /// Information about an inheriting constructor. - struct InheritingConstructor { - InheritingConstructor() - : DeclaredInDerived(false), BaseCtor(nullptr), DerivedCtor(nullptr) {} - - /// If \c true, a constructor with this signature is already declared - /// in the derived class. - bool DeclaredInDerived; - - /// The constructor which is inherited. - const CXXConstructorDecl *BaseCtor; - - /// The derived constructor we declared. - CXXConstructorDecl *DerivedCtor; - }; - - /// Inheriting constructors with a given canonical type. There can be at - /// most one such non-template constructor, and any number of templated - /// constructors. - struct InheritingConstructorsForType { - InheritingConstructor NonTemplate; - SmallVector<std::pair<TemplateParameterList *, InheritingConstructor>, 4> - Templates; - - InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) { - if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) { - TemplateParameterList *ParamList = FTD->getTemplateParameters(); - for (unsigned I = 0, N = Templates.size(); I != N; ++I) - if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first, - false, S.TPL_TemplateMatch)) - return Templates[I].second; - Templates.push_back(std::make_pair(ParamList, InheritingConstructor())); - return Templates.back().second; - } + // Set up the new constructor. + assert(!BaseCtor->isDeleted() && "should not use deleted constructor"); + DerivedCtor->setAccess(BaseCtor->getAccess()); + DerivedCtor->setParams(ParamDecls); + Derived->addDecl(DerivedCtor); - return NonTemplate; - } - }; + if (ShouldDeleteSpecialMember(DerivedCtor, CXXDefaultConstructor, &ICI)) + SetDeclDeleted(DerivedCtor, UsingLoc); - /// Get or create the inheriting constructor record for a constructor. - InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor, - QualType CtorType) { - return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()] - .getEntry(SemaRef, Ctor); - } + return DerivedCtor; +} - typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*); +void Sema::NoteDeletedInheritingConstructor(CXXConstructorDecl *Ctor) { + InheritedConstructorInfo ICI(*this, Ctor->getLocation(), + Ctor->getInheritedConstructor().getShadowDecl()); + ShouldDeleteSpecialMember(Ctor, CXXDefaultConstructor, &ICI, + /*Diagnose*/true); +} - /// Process all constructors for a class. - void visitAll(const CXXRecordDecl *RD, VisitFn Callback) { - for (const auto *Ctor : RD->ctors()) - (this->*Callback)(Ctor); - for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl> - I(RD->decls_begin()), E(RD->decls_end()); - I != E; ++I) { - const FunctionDecl *FD = (*I)->getTemplatedDecl(); - if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD)) - (this->*Callback)(CD); - } - } +void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, + CXXConstructorDecl *Constructor) { + CXXRecordDecl *ClassDecl = Constructor->getParent(); + assert(Constructor->getInheritedConstructor() && + !Constructor->doesThisDeclarationHaveABody() && + !Constructor->isDeleted()); + if (Constructor->isInvalidDecl()) + return; - /// Note that a constructor (or constructor template) was declared in Derived. - void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) { - getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true; - } + ConstructorUsingShadowDecl *Shadow = + Constructor->getInheritedConstructor().getShadowDecl(); + CXXConstructorDecl *InheritedCtor = + Constructor->getInheritedConstructor().getConstructor(); - /// Inherit a single constructor. - void inherit(const CXXConstructorDecl *Ctor) { - const FunctionProtoType *CtorType = - Ctor->getType()->castAs<FunctionProtoType>(); - ArrayRef<QualType> ArgTypes = CtorType->getParamTypes(); - FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo(); + // [class.inhctor.init]p1: + // initialization proceeds as if a defaulted default constructor is used to + // initialize the D object and each base class subobject from which the + // constructor was inherited - SourceLocation UsingLoc = getUsingLoc(Ctor->getParent()); + InheritedConstructorInfo ICI(*this, CurrentLocation, Shadow); + CXXRecordDecl *RD = Shadow->getParent(); + SourceLocation InitLoc = Shadow->getLocation(); - // Core issue (no number yet): the ellipsis is always discarded. - if (EPI.Variadic) { - SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis); - SemaRef.Diag(Ctor->getLocation(), - diag::note_using_decl_constructor_ellipsis); - EPI.Variadic = false; - } + // Initializations are performed "as if by a defaulted default constructor", + // so enter the appropriate scope. + SynthesizedFunctionScope Scope(*this, Constructor); + DiagnosticErrorTrap Trap(Diags); - // Declare a constructor for each number of parameters. - // - // C++11 [class.inhctor]p1: - // The candidate set of inherited constructors from the class X named in - // the using-declaration consists of [... modulo defects ...] for each - // constructor or constructor template of X, the set of constructors or - // constructor templates that results from omitting any ellipsis parameter - // specification and successively omitting parameters with a default - // argument from the end of the parameter-type-list - unsigned MinParams = minParamsToInherit(Ctor); - unsigned Params = Ctor->getNumParams(); - if (Params >= MinParams) { - do - declareCtor(UsingLoc, Ctor, - SemaRef.Context.getFunctionType( - Ctor->getReturnType(), ArgTypes.slice(0, Params), EPI)); - while (Params > MinParams && - Ctor->getParamDecl(--Params)->hasDefaultArg()); - } - } - - /// Find the using-declaration which specified that we should inherit the - /// constructors of \p Base. - SourceLocation getUsingLoc(const CXXRecordDecl *Base) { - // No fancy lookup required; just look for the base constructor name - // directly within the derived class. - ASTContext &Context = SemaRef.Context; - DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Context.getRecordType(Base))); - DeclContext::lookup_result Decls = Derived->lookup(Name); - return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation(); - } - - unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) { - // C++11 [class.inhctor]p3: - // [F]or each constructor template in the candidate set of inherited - // constructors, a constructor template is implicitly declared - if (Ctor->getDescribedFunctionTemplate()) - return 0; - - // For each non-template constructor in the candidate set of inherited - // constructors other than a constructor having no parameters or a - // copy/move constructor having a single parameter, a constructor is - // implicitly declared [...] - if (Ctor->getNumParams() == 0) - return 1; - if (Ctor->isCopyOrMoveConstructor()) - return 2; - - // Per discussion on core reflector, never inherit a constructor which - // would become a default, copy, or move constructor of Derived either. - const ParmVarDecl *PD = Ctor->getParamDecl(0); - const ReferenceType *RT = PD->getType()->getAs<ReferenceType>(); - return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1; - } - - /// Declare a single inheriting constructor, inheriting the specified - /// constructor, with the given type. - void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor, - QualType DerivedType) { - InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType); - - // C++11 [class.inhctor]p3: - // ... a constructor is implicitly declared with the same constructor - // characteristics unless there is a user-declared constructor with - // the same signature in the class where the using-declaration appears - if (Entry.DeclaredInDerived) - return; + // Build explicit initializers for all base classes from which the + // constructor was inherited. + SmallVector<CXXCtorInitializer*, 8> Inits; + for (bool VBase : {false, true}) { + for (CXXBaseSpecifier &B : VBase ? RD->vbases() : RD->bases()) { + if (B.isVirtual() != VBase) + continue; - // C++11 [class.inhctor]p7: - // If two using-declarations declare inheriting constructors with the - // same signature, the program is ill-formed - if (Entry.DerivedCtor) { - if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) { - // Only diagnose this once per constructor. - if (Entry.DerivedCtor->isInvalidDecl()) - return; - Entry.DerivedCtor->setInvalidDecl(); - - SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict); - SemaRef.Diag(BaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_current_ctor); - SemaRef.Diag(Entry.BaseCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_ctor); - SemaRef.Diag(Entry.DerivedCtor->getLocation(), - diag::note_using_decl_constructor_conflict_previous_using); - } else { - // Core issue (no number): if the same inheriting constructor is - // produced by multiple base class constructors from the same base - // class, the inheriting constructor is defined as deleted. - SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc); - } + auto *BaseRD = B.getType()->getAsCXXRecordDecl(); + if (!BaseRD) + continue; - return; - } + auto BaseCtor = ICI.findConstructorForBase(BaseRD, InheritedCtor); + if (!BaseCtor.first) + continue; - ASTContext &Context = SemaRef.Context; - DeclarationName Name = Context.DeclarationNames.getCXXConstructorName( - Context.getCanonicalType(Context.getRecordType(Derived))); - DeclarationNameInfo NameInfo(Name, UsingLoc); + MarkFunctionReferenced(CurrentLocation, BaseCtor.first); + ExprResult Init = new (Context) CXXInheritedCtorInitExpr( + InitLoc, B.getType(), BaseCtor.first, VBase, BaseCtor.second); - TemplateParameterList *TemplateParams = nullptr; - if (const FunctionTemplateDecl *FTD = - BaseCtor->getDescribedFunctionTemplate()) { - TemplateParams = FTD->getTemplateParameters(); - // We're reusing template parameters from a different DeclContext. This - // is questionable at best, but works out because the template depth in - // both places is guaranteed to be 0. - // FIXME: Rebuild the template parameters in the new context, and - // transform the function type to refer to them. + auto *TInfo = Context.getTrivialTypeSourceInfo(B.getType(), InitLoc); + Inits.push_back(new (Context) CXXCtorInitializer( + Context, TInfo, VBase, InitLoc, Init.get(), InitLoc, + SourceLocation())); } - - // Build type source info pointing at the using-declaration. This is - // required by template instantiation. - TypeSourceInfo *TInfo = - Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc); - FunctionProtoTypeLoc ProtoLoc = - TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>(); - - CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create( - Context, Derived, UsingLoc, NameInfo, DerivedType, - TInfo, BaseCtor->isExplicit(), /*Inline=*/true, - /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr()); - - // Build an unevaluated exception specification for this constructor. - const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>(); - FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo(); - EPI.ExceptionSpec.Type = EST_Unevaluated; - EPI.ExceptionSpec.SourceDecl = DerivedCtor; - DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(), - FPT->getParamTypes(), EPI)); - - // Build the parameter declarations. - SmallVector<ParmVarDecl *, 16> ParamDecls; - for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) { - TypeSourceInfo *TInfo = - Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc); - ParmVarDecl *PD = ParmVarDecl::Create( - Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr, - FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr); - PD->setScopeInfo(0, I); - PD->setImplicit(); - ParamDecls.push_back(PD); - ProtoLoc.setParam(I, PD); - } - - // Set up the new constructor. - DerivedCtor->setAccess(BaseCtor->getAccess()); - DerivedCtor->setParams(ParamDecls); - DerivedCtor->setInheritedConstructor(BaseCtor); - if (BaseCtor->isDeleted()) - SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc); - - // If this is a constructor template, build the template declaration. - if (TemplateParams) { - FunctionTemplateDecl *DerivedTemplate = - FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name, - TemplateParams, DerivedCtor); - DerivedTemplate->setAccess(BaseCtor->getAccess()); - DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate); - Derived->addDecl(DerivedTemplate); - } else { - Derived->addDecl(DerivedCtor); - } - - Entry.BaseCtor = BaseCtor; - Entry.DerivedCtor = DerivedCtor; } - Sema &SemaRef; - CXXRecordDecl *Derived; - typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType; - MapType Map; -}; -} - -void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) { - // Defer declaring the inheriting constructors until the class is - // instantiated. - if (ClassDecl->isDependentContext()) - return; - - // Find base classes from which we might inherit constructors. - SmallVector<CXXRecordDecl*, 4> InheritedBases; - for (const auto &BaseIt : ClassDecl->bases()) - if (BaseIt.getInheritConstructors()) - InheritedBases.push_back(BaseIt.getType()->getAsCXXRecordDecl()); - - // Go no further if we're not inheriting any constructors. - if (InheritedBases.empty()) - return; - - // Declare the inherited constructors. - InheritingConstructorInfo ICI(*this, ClassDecl); - for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I) - ICI.inheritAll(InheritedBases[I]); -} + // We now proceed as if for a defaulted default constructor, with the relevant + // initializers replaced. -void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, - CXXConstructorDecl *Constructor) { - CXXRecordDecl *ClassDecl = Constructor->getParent(); - assert(Constructor->getInheritedConstructor() && - !Constructor->doesThisDeclarationHaveABody() && - !Constructor->isDeleted()); - - SynthesizedFunctionScope Scope(*this, Constructor); - DiagnosticErrorTrap Trap(Diags); - if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) || - Trap.hasErrorOccurred()) { - Diag(CurrentLocation, diag::note_inhctor_synthesized_at) - << Context.getTagDeclType(ClassDecl); + bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits); + if (HadError || Trap.hasErrorOccurred()) { + Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD; Constructor->setInvalidDecl(); return; } - SourceLocation Loc = Constructor->getLocation(); - Constructor->setBody(new (Context) CompoundStmt(Loc)); + // The exception specification is needed because we are defining the + // function. + ResolveExceptionSpec(CurrentLocation, + Constructor->getType()->castAs<FunctionProtoType>()); + + Constructor->setBody(new (Context) CompoundStmt(InitLoc)); Constructor->markUsed(Context); MarkVTableUsed(CurrentLocation, ClassDecl); @@ -9319,8 +9404,9 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation, if (ASTMutationListener *L = getASTMutationListener()) { L->CompletedImplicitDefinition(Constructor); } -} + DiagnoseUninitializedFields(*this, Constructor); +} Sema::ImplicitExceptionSpecification Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) { @@ -9397,20 +9483,21 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) { FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor); Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI)); - AddOverriddenMethods(ClassDecl, Destructor); - // We don't need to use SpecialMemberIsTrivial here; triviality for // destructors is easy to compute. Destructor->setTrivial(ClassDecl->hasTrivialDestructor()); - if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) - SetDeclDeleted(Destructor, ClassLoc); - // Note that we have declared this destructor. ++ASTContext::NumImplicitDestructorsDeclared; + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, Destructor); + + if (ShouldDeleteSpecialMember(Destructor, CXXDestructor)) + SetDeclDeleted(Destructor, ClassLoc); + // Introduce this destructor into its scope. - if (Scope *S = getScopeForContext(ClassDecl)) + if (S) PushOnScopeChains(Destructor, S, false); ClassDecl->addDecl(Destructor); @@ -9533,6 +9620,10 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) { if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft()) getDefaultArgExprsForConstructors(*this, RD); + referenceDLLExportedClassMethods(); +} + +void Sema::referenceDLLExportedClassMethods() { if (!DelayedDllExportClasses.empty()) { // Calling ReferenceDllExportedMethods might cause the current function to // be called again, so use a local copy of DelayedDllExportClasses. @@ -9969,10 +10060,10 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T, SizeType, VK_LValue, OK_Ordinary, Loc); // Construct the loop that copies all elements of this array. - return S.ActOnForStmt(Loc, Loc, InitStmt, - S.MakeFullExpr(Comparison), - nullptr, S.MakeFullDiscardedValueExpr(Increment), - Loc, Copy.get()); + return S.ActOnForStmt( + Loc, Loc, InitStmt, + S.ActOnCondition(nullptr, Loc, Comparison, Sema::ConditionKind::Boolean), + S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get()); } static StmtResult @@ -10107,20 +10198,21 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) { nullptr); CopyAssignment->setParams(FromParam); - AddOverriddenMethods(ClassDecl, CopyAssignment); - CopyAssignment->setTrivial( ClassDecl->needsOverloadResolutionForCopyAssignment() ? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment) : ClassDecl->hasTrivialCopyAssignment()); - if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) - SetDeclDeleted(CopyAssignment, ClassLoc); - // Note that we have added this copy-assignment operator. ++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared; - if (Scope *S = getScopeForContext(ClassDecl)) + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, CopyAssignment); + + if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment)) + SetDeclDeleted(CopyAssignment, ClassLoc); + + if (S) PushOnScopeChains(CopyAssignment, S, false); ClassDecl->addDecl(CopyAssignment); @@ -10498,22 +10590,23 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) { nullptr); MoveAssignment->setParams(FromParam); - AddOverriddenMethods(ClassDecl, MoveAssignment); - MoveAssignment->setTrivial( ClassDecl->needsOverloadResolutionForMoveAssignment() ? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment) : ClassDecl->hasTrivialMoveAssignment()); + // Note that we have added this copy-assignment operator. + ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; + + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, MoveAssignment); + if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) { ClassDecl->setImplicitMoveAssignmentIsDeleted(); SetDeclDeleted(MoveAssignment, ClassLoc); } - // Note that we have added this copy-assignment operator. - ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared; - - if (Scope *S = getScopeForContext(ClassDecl)) + if (S) PushOnScopeChains(MoveAssignment, S, false); ClassDecl->addDecl(MoveAssignment); @@ -10939,13 +11032,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor( ? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor) : ClassDecl->hasTrivialCopyConstructor()); - if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) - SetDeclDeleted(CopyConstructor, ClassLoc); - // Note that we have declared this constructor. ++ASTContext::NumImplicitCopyConstructorsDeclared; - if (Scope *S = getScopeForContext(ClassDecl)) + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, CopyConstructor); + + if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor)) + SetDeclDeleted(CopyConstructor, ClassLoc); + + if (S) PushOnScopeChains(CopyConstructor, S, false); ClassDecl->addDecl(CopyConstructor); @@ -11116,15 +11212,18 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor( ? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor) : ClassDecl->hasTrivialMoveConstructor()); + // Note that we have declared this constructor. + ++ASTContext::NumImplicitMoveConstructorsDeclared; + + Scope *S = getScopeForContext(ClassDecl); + CheckImplicitSpecialMemberDeclaration(S, MoveConstructor); + if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) { ClassDecl->setImplicitMoveConstructorIsDeleted(); SetDeclDeleted(MoveConstructor, ClassLoc); } - // Note that we have declared this constructor. - ++ASTContext::NumImplicitMoveConstructorsDeclared; - - if (Scope *S = getScopeForContext(ClassDecl)) + if (S) PushOnScopeChains(MoveConstructor, S, false); ClassDecl->addDecl(MoveConstructor); @@ -11329,6 +11428,7 @@ static bool hasOneRealArgument(MultiExprArg Args) { ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + NamedDecl *FoundDecl, CXXConstructorDecl *Constructor, MultiExprArg ExprArgs, bool HadMultipleCandidates, @@ -11349,24 +11449,51 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, // 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 - if (ConstructKind == CXXConstructExpr::CK_Complete && + if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor && Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) { Expr *SubExpr = ExprArgs[0]; - Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent()); + Elidable = SubExpr->isTemporaryObject( + Context, cast<CXXRecordDecl>(FoundDecl->getDeclContext())); } - return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor, + return BuildCXXConstructExpr(ConstructLoc, DeclInitType, + FoundDecl, Constructor, Elidable, ExprArgs, HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization, RequiresZeroInit, ConstructKind, ParenRange); } +ExprResult +Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, + NamedDecl *FoundDecl, + CXXConstructorDecl *Constructor, + bool Elidable, + MultiExprArg ExprArgs, + bool HadMultipleCandidates, + bool IsListInitialization, + bool IsStdInitListInitialization, + bool RequiresZeroInit, + unsigned ConstructKind, + SourceRange ParenRange) { + if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) { + Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow); + if (DiagnoseUseOfDecl(Constructor, ConstructLoc)) + return ExprError(); + } + + return BuildCXXConstructExpr( + ConstructLoc, DeclInitType, Constructor, Elidable, ExprArgs, + HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization, + RequiresZeroInit, ConstructKind, ParenRange); +} + /// BuildCXXConstructExpr - Creates a complete call to a constructor, /// including handling of its default argument expressions. ExprResult Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, - CXXConstructorDecl *Constructor, bool Elidable, + CXXConstructorDecl *Constructor, + bool Elidable, MultiExprArg ExprArgs, bool HadMultipleCandidates, bool IsListInitialization, @@ -11374,11 +11501,16 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType, bool RequiresZeroInit, unsigned ConstructKind, SourceRange ParenRange) { + assert(declaresSameEntity( + Constructor->getParent(), + DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) && + "given constructor for wrong type"); MarkFunctionReferenced(ConstructLoc, Constructor); + return CXXConstructExpr::Create( - Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs, - HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization, - RequiresZeroInit, + Context, DeclInitType, ConstructLoc, Constructor, Elidable, + ExprArgs, HadMultipleCandidates, IsListInitialization, + IsStdInitListInitialization, RequiresZeroInit, static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind), ParenRange); } @@ -11398,8 +11530,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) { CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - assert(Lookup.size() == 1); - FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + + // 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 && + "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]); + } + if (InstantiateInClassInitializer(Loc, Field, Pattern, getTemplateInstantiationArgs(Field))) return ExprError(); @@ -11660,7 +11803,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { diag::err_operator_overload_static) << FnDecl->getDeclName(); } else { bool ClassOrEnumParam = false; - for (auto Param : FnDecl->params()) { + for (auto Param : FnDecl->parameters()) { QualType ParamType = Param->getType().getNonReferenceType(); if (ParamType->isDependentType() || ParamType->isRecordType() || ParamType->isEnumeralType()) { @@ -11682,7 +11825,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { // Only the function-call operator allows default arguments // (C++ [over.call]p1). if (Op != OO_Call) { - for (auto Param : FnDecl->params()) { + for (auto Param : FnDecl->parameters()) { if (Param->hasDefaultArg()) return Diag(Param->getLocation(), diag::err_operator_overload_default_arg) @@ -11765,6 +11908,49 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) { return false; } +static bool +checkLiteralOperatorTemplateParameterList(Sema &SemaRef, + FunctionTemplateDecl *TpDecl) { + TemplateParameterList *TemplateParams = TpDecl->getTemplateParameters(); + + // Must have one or two template parameters. + if (TemplateParams->size() == 1) { + NonTypeTemplateParmDecl *PmDecl = + dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(0)); + + // The template parameter must be a char parameter pack. + if (PmDecl && PmDecl->isTemplateParameterPack() && + SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy)) + return false; + + } else if (TemplateParams->size() == 2) { + TemplateTypeParmDecl *PmType = + dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0)); + NonTypeTemplateParmDecl *PmArgs = + dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(1)); + + // The second template parameter must be a parameter pack with the + // first template parameter as its type. + if (PmType && PmArgs && !PmType->isTemplateParameterPack() && + PmArgs->isTemplateParameterPack()) { + const TemplateTypeParmType *TArgs = + PmArgs->getType()->getAs<TemplateTypeParmType>(); + if (TArgs && TArgs->getDepth() == PmType->getDepth() && + TArgs->getIndex() == PmType->getIndex()) { + if (SemaRef.ActiveTemplateInstantiations.empty()) + SemaRef.Diag(TpDecl->getLocation(), + diag::ext_string_literal_operator_template); + return false; + } + } + } + + SemaRef.Diag(TpDecl->getTemplateParameters()->getSourceRange().getBegin(), + diag::err_literal_operator_template) + << TpDecl->getTemplateParameters()->getSourceRange(); + return true; +} + /// CheckLiteralOperatorDeclaration - Check whether the declaration /// of this literal operator function is well-formed. If so, returns /// false; otherwise, emits appropriate diagnostics and returns true. @@ -11780,10 +11966,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { return true; } - bool Valid = false; - // This might be the definition of a literal operator template. FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate(); + // This might be a specialization of a literal operator template. if (!TpDecl) TpDecl = FnDecl->getPrimaryTemplate(); @@ -11792,104 +11977,120 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) { // template <class T, T...> type operator "" name() are the only valid // template signatures, and the only valid signatures with no parameters. if (TpDecl) { - if (FnDecl->param_size() == 0) { - // Must have one or two template parameters - TemplateParameterList *Params = TpDecl->getTemplateParameters(); - if (Params->size() == 1) { - NonTypeTemplateParmDecl *PmDecl = - dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0)); - - // The template parameter must be a char parameter pack. - if (PmDecl && PmDecl->isTemplateParameterPack() && - Context.hasSameType(PmDecl->getType(), Context.CharTy)) - Valid = true; - } else if (Params->size() == 2) { - TemplateTypeParmDecl *PmType = - dyn_cast<TemplateTypeParmDecl>(Params->getParam(0)); - NonTypeTemplateParmDecl *PmArgs = - dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1)); - - // The second template parameter must be a parameter pack with the - // first template parameter as its type. - if (PmType && PmArgs && - !PmType->isTemplateParameterPack() && - PmArgs->isTemplateParameterPack()) { - const TemplateTypeParmType *TArgs = - PmArgs->getType()->getAs<TemplateTypeParmType>(); - if (TArgs && TArgs->getDepth() == PmType->getDepth() && - TArgs->getIndex() == PmType->getIndex()) { - Valid = true; - if (ActiveTemplateInstantiations.empty()) - Diag(FnDecl->getLocation(), - diag::ext_string_literal_operator_template); - } - } + if (FnDecl->param_size() != 0) { + Diag(FnDecl->getLocation(), + diag::err_literal_operator_template_with_params); + return true; + } + + if (checkLiteralOperatorTemplateParameterList(*this, TpDecl)) + return true; + + } else if (FnDecl->param_size() == 1) { + const ParmVarDecl *Param = FnDecl->getParamDecl(0); + + QualType ParamType = Param->getType().getUnqualifiedType(); + + // Only unsigned long long int, long double, any character type, and const + // char * are allowed as the only parameters. + if (ParamType->isSpecificBuiltinType(BuiltinType::ULongLong) || + ParamType->isSpecificBuiltinType(BuiltinType::LongDouble) || + Context.hasSameType(ParamType, Context.CharTy) || + Context.hasSameType(ParamType, Context.WideCharTy) || + Context.hasSameType(ParamType, Context.Char16Ty) || + Context.hasSameType(ParamType, Context.Char32Ty)) { + } else if (const PointerType *Ptr = ParamType->getAs<PointerType>()) { + QualType InnerType = Ptr->getPointeeType(); + + // Pointer parameter must be a const char *. + if (!(Context.hasSameType(InnerType.getUnqualifiedType(), + Context.CharTy) && + InnerType.isConstQualified() && !InnerType.isVolatileQualified())) { + Diag(Param->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << ParamType << "'const char *'" << Param->getSourceRange(); + return true; } + + } else if (ParamType->isRealFloatingType()) { + Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param) + << ParamType << Context.LongDoubleTy << Param->getSourceRange(); + return true; + + } else if (ParamType->isIntegerType()) { + Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param) + << ParamType << Context.UnsignedLongLongTy << Param->getSourceRange(); + return true; + + } else { + Diag(Param->getSourceRange().getBegin(), + diag::err_literal_operator_invalid_param) + << ParamType << Param->getSourceRange(); + return true; } - } else if (FnDecl->param_size()) { - // Check the first parameter + + } else if (FnDecl->param_size() == 2) { FunctionDecl::param_iterator Param = FnDecl->param_begin(); - QualType T = (*Param)->getType().getUnqualifiedType(); - - // unsigned long long int, long double, and any character type are allowed - // as the only parameters. - if (Context.hasSameType(T, Context.UnsignedLongLongTy) || - Context.hasSameType(T, Context.LongDoubleTy) || - Context.hasSameType(T, Context.CharTy) || - Context.hasSameType(T, Context.WideCharTy) || - Context.hasSameType(T, Context.Char16Ty) || - Context.hasSameType(T, Context.Char32Ty)) { - if (++Param == FnDecl->param_end()) - Valid = true; - goto FinishedParams; - } - - // Otherwise it must be a pointer to const; let's strip those qualifiers. - const PointerType *PT = T->getAs<PointerType>(); - if (!PT) - goto FinishedParams; - T = PT->getPointeeType(); - if (!T.isConstQualified() || T.isVolatileQualified()) - goto FinishedParams; - T = T.getUnqualifiedType(); - - // Move on to the second parameter; - ++Param; + // First, verify that the first parameter is correct. - // If there is no second parameter, the first must be a const char * - if (Param == FnDecl->param_end()) { - if (Context.hasSameType(T, Context.CharTy)) - Valid = true; - goto FinishedParams; + QualType FirstParamType = (*Param)->getType().getUnqualifiedType(); + + // Two parameter function must have a pointer to const as a + // first parameter; let's strip those qualifiers. + const PointerType *PT = FirstParamType->getAs<PointerType>(); + + if (!PT) { + Diag((*Param)->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << FirstParamType << "'const char *'" << (*Param)->getSourceRange(); + return true; + } + + QualType PointeeType = PT->getPointeeType(); + // First parameter must be const + if (!PointeeType.isConstQualified() || PointeeType.isVolatileQualified()) { + Diag((*Param)->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << FirstParamType << "'const char *'" << (*Param)->getSourceRange(); + return true; } - // const char *, const wchar_t*, const char16_t*, and const char32_t* + QualType InnerType = PointeeType.getUnqualifiedType(); + // Only const char *, const wchar_t*, const char16_t*, and const char32_t* // are allowed as the first parameter to a two-parameter function - if (!(Context.hasSameType(T, Context.CharTy) || - Context.hasSameType(T, Context.WideCharTy) || - Context.hasSameType(T, Context.Char16Ty) || - Context.hasSameType(T, Context.Char32Ty))) - goto FinishedParams; - - // The second and final parameter must be an std::size_t - T = (*Param)->getType().getUnqualifiedType(); - if (Context.hasSameType(T, Context.getSizeType()) && - ++Param == FnDecl->param_end()) - Valid = true; - } - - // FIXME: This diagnostic is absolutely terrible. -FinishedParams: - if (!Valid) { - Diag(FnDecl->getLocation(), diag::err_literal_operator_params) - << FnDecl->getDeclName(); + if (!(Context.hasSameType(InnerType, Context.CharTy) || + Context.hasSameType(InnerType, Context.WideCharTy) || + Context.hasSameType(InnerType, Context.Char16Ty) || + Context.hasSameType(InnerType, Context.Char32Ty))) { + Diag((*Param)->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << FirstParamType << "'const char *'" << (*Param)->getSourceRange(); + return true; + } + + // Move on to the second and final parameter. + ++Param; + + // The second parameter must be a std::size_t. + QualType SecondParamType = (*Param)->getType().getUnqualifiedType(); + if (!Context.hasSameType(SecondParamType, Context.getSizeType())) { + Diag((*Param)->getSourceRange().getBegin(), + diag::err_literal_operator_param) + << SecondParamType << Context.getSizeType() + << (*Param)->getSourceRange(); + return true; + } + } else { + Diag(FnDecl->getLocation(), diag::err_literal_operator_bad_param_count); return true; } + // Parameters are good. + // A parameter-declaration-clause containing a default argument is not // equivalent to any of the permitted forms. - for (auto Param : FnDecl->params()) { + for (auto Param : FnDecl->parameters()) { if (Param->hasDefaultArg()) { Diag(Param->getDefaultArgRange().getBegin(), diag::err_literal_operator_default_argument) @@ -12003,6 +12204,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S, Invalid = true; } + if (ExDeclType->isVariablyModifiedType()) { + Diag(Loc, diag::err_catch_variably_modified) << ExDeclType; + Invalid = true; + } + QualType BaseType = ExDeclType; int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference unsigned DK = diag::err_catch_incomplete; @@ -12468,10 +12674,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS, // friend a member of an arbitrary specialization of your template). Decl *D; - if (unsigned NumTempParamLists = TempParams.size()) + if (!TempParams.empty()) D = FriendTemplateDecl::Create(Context, CurContext, Loc, - NumTempParamLists, - TempParams.data(), + TempParams, TSI, DS.getFriendSpecLoc()); else @@ -12894,44 +13099,20 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) { // the record is complete. const FunctionDecl *Primary = MD; if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern()) - // Find the uninstantiated declaration that actually had the '= default' - // on it. - Pattern->isDefined(Primary); + // Ask the template instantiation pattern that actually had the + // '= default' on it. + Primary = Pattern; // If the method was defaulted on its first declaration, we will have // already performed the checking in CheckCompletedCXXClass. Such a // declaration doesn't trigger an implicit definition. - if (Primary == Primary->getCanonicalDecl()) + if (Primary->getCanonicalDecl()->isDefaulted()) return; CheckExplicitlyDefaultedSpecialMember(MD); - if (MD->isInvalidDecl()) - return; - - switch (Member) { - case CXXDefaultConstructor: - DefineImplicitDefaultConstructor(DefaultLoc, - cast<CXXConstructorDecl>(MD)); - break; - case CXXCopyConstructor: - DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); - break; - case CXXCopyAssignment: - DefineImplicitCopyAssignment(DefaultLoc, MD); - break; - case CXXDestructor: - DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD)); - break; - case CXXMoveConstructor: - DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD)); - break; - case CXXMoveAssignment: - DefineImplicitMoveAssignment(DefaultLoc, MD); - break; - case CXXInvalid: - llvm_unreachable("Invalid special member."); - } + if (!MD->isInvalidDecl()) + DefineImplicitSpecialMember(*this, MD, DefaultLoc); } else { Diag(DefaultLoc, diag::err_default_special_members); } @@ -13020,19 +13201,20 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, return true; } - // C++ [class.virtual]p6: - // If the return type of D::f differs from the return type of B::f, the - // class type in the return type of D::f shall be complete at the point of - // declaration of D::f or shall be the class type D. - if (const RecordType *RT = NewClassTy->getAs<RecordType>()) { - if (!RT->isBeingDefined() && - RequireCompleteType(New->getLocation(), NewClassTy, - diag::err_covariant_return_incomplete, - New->getDeclName())) - return true; - } - if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) { + // C++14 [class.virtual]p8: + // If the class type in the covariant return type of D::f differs from + // that of B::f, the class type in the return type of D::f shall be + // complete at the point of declaration of D::f or shall be the class + // type D. + if (const RecordType *RT = NewClassTy->getAs<RecordType>()) { + if (!RT->isBeingDefined() && + RequireCompleteType(New->getLocation(), NewClassTy, + diag::err_covariant_return_incomplete, + New->getDeclName())) + return true; + } + // Check if the new class derives from the old class. if (!IsDerivedFrom(New->getLocation(), NewClassTy, OldClassTy)) { Diag(New->getLocation(), diag::err_covariant_return_not_derived) @@ -13069,7 +13251,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, Diag(Old->getLocation(), diag::note_overridden_virtual_function) << Old->getReturnTypeSourceRange(); return true; - }; + } // The new class type must have the same or less qualifiers as the old type. @@ -13081,7 +13263,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New, Diag(Old->getLocation(), diag::note_overridden_virtual_function) << Old->getReturnTypeSourceRange(); return true; - }; + } return false; } @@ -13240,14 +13422,19 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class, // checks (i.e. operator delete() lookup) when the vtable is marked used, as // the deleting destructor is emitted with the vtable, not with the // destructor definition as in the Itanium ABI. - // If it has a definition, we do the check at that point instead. - if (Context.getTargetInfo().getCXXABI().isMicrosoft() && - Class->hasUserDeclaredDestructor() && - !Class->getDestructor()->isDefined() && - !Class->getDestructor()->isDeleted()) { + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) { CXXDestructorDecl *DD = Class->getDestructor(); - ContextRAII SavedContext(*this, DD); - CheckDestructor(DD); + if (DD && DD->isVirtual() && !DD->isDeleted()) { + if (Class->hasUserDeclaredDestructor() && !DD->isDefined()) { + // If this is an out-of-line declaration, marking it referenced will + // not do anything. Manually call CheckDestructor to look up operator + // delete(). + ContextRAII SavedContext(*this, DD); + CheckDestructor(DD); + } else { + MarkFunctionReferenced(Loc, Class->getDestructor()); + } + } } } @@ -13785,6 +13972,9 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record, DiagnoseFunctionSpecifiers(D.getDeclSpec()); + if (D.getDeclSpec().isInlineSpecified()) + Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp index a2f41a7cc30a..738de77cecb7 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp @@ -21,7 +21,6 @@ #include "clang/AST/ExprObjC.h" #include "clang/Basic/SourceManager.h" #include "clang/Sema/DeclSpec.h" -#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -320,11 +319,11 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) { PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope); // The ObjC parser requires parameter names so there's no need to check. - CheckParmsForFunctionDef(MDecl->param_begin(), MDecl->param_end(), + CheckParmsForFunctionDef(MDecl->parameters(), /*CheckParameterNames=*/false); // Introduce all of the other parameters into this scope. - for (auto *Param : MDecl->params()) { + for (auto *Param : MDecl->parameters()) { if (!Param->isInvalidDecl() && getLangOpts().ObjCAutoRefCount && !HasExplicitOwnershipAttr(*this, Param)) @@ -1303,6 +1302,16 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback { }; } // end anonymous namespace +void Sema::DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId, + SourceLocation ProtocolLoc, + IdentifierInfo *TypeArgId, + SourceLocation TypeArgLoc, + bool SelectProtocolFirst) { + Diag(TypeArgLoc, diag::err_objc_type_args_and_protocols) + << SelectProtocolFirst << TypeArgId << ProtocolId + << SourceRange(ProtocolLoc); +} + void Sema::actOnObjCTypeArgsOrProtocolQualifiers( Scope *S, ParsedType baseType, @@ -1493,6 +1502,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( SourceLocation(), SourceLocation(), SourceLocation(), + SourceLocation(), SourceLocation()), parsedAttrs, starLoc); @@ -1570,11 +1580,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers( // We have a conflict: some names refer to protocols and others // refer to types. - Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols) - << (protocols[i] != nullptr) - << identifiers[i] - << identifiers[0] - << SourceRange(identifierLocs[0]); + DiagnoseTypeArgsAndProtocols(identifiers[0], identifierLocs[0], + identifiers[i], identifierLocs[i], + protocols[i] != nullptr); protocols.clear(); typeArgs.clear(); @@ -1831,6 +1839,13 @@ Decl *Sema::ActOnStartCategoryImplementation( if (IDecl) DiagnoseUseOfDecl(IDecl, ClassLoc); + // If the interface has the objc_runtime_visible attribute, we + // cannot implement a category for it. + if (IDecl && IDecl->hasAttr<ObjCRuntimeVisibleAttr>()) { + Diag(ClassLoc, diag::err_objc_runtime_visible_category) + << IDecl->getDeclName(); + } + /// Check that CatName, category name, is not used in another implementation. if (CatIDecl) { if (CatIDecl->getImplementation()) { @@ -1968,6 +1983,16 @@ Decl *Sema::ActOnStartClassImplementation( dyn_cast<NamedDecl>(IDecl), IMPDecl->getLocation(), 1); } + + // If the superclass has the objc_runtime_visible attribute, we + // cannot implement a subclass of it. + if (IDecl->getSuperClass() && + IDecl->getSuperClass()->hasAttr<ObjCRuntimeVisibleAttr>()) { + Diag(ClassLoc, diag::err_objc_runtime_visible_subclass) + << IDecl->getDeclName() + << IDecl->getSuperClass()->getDeclName(); + } + return ActOnObjCContainerStartDefinition(IMPDecl); } @@ -2734,7 +2759,8 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, for (auto *I : CDecl->class_methods()) { if (!ClsMapSeen.insert(I->getSelector()).second) continue; - if (!ClsMap.count(I->getSelector())) { + if (!I->isPropertyAccessor() && + !ClsMap.count(I->getSelector())) { if (ImmediateClass) WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl, diag::warn_undef_method_impl); @@ -2743,12 +2769,14 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap, IMPDecl->getClassMethod(I->getSelector()); assert(CDecl->getClassMethod(I->getSelector()) && "Expected to find the method through lookup as well"); - if (!WarnCategoryMethodImpl) - WarnConflictingTypedMethods(ImpMethodDecl, I, - isa<ObjCProtocolDecl>(CDecl)); - else - WarnExactTypedMethods(ImpMethodDecl, I, - isa<ObjCProtocolDecl>(CDecl)); + // ImpMethodDecl may be null as in a @dynamic property. + if (ImpMethodDecl) { + if (!WarnCategoryMethodImpl) + WarnConflictingTypedMethods(ImpMethodDecl, I, + isa<ObjCProtocolDecl>(CDecl)); + else if (!I->isPropertyAccessor()) + WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl)); + } } } @@ -3147,6 +3175,26 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left, return true; } +static bool isMethodContextSameForKindofLookup(ObjCMethodDecl *Method, + ObjCMethodDecl *MethodInList) { + auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext()); + auto *MethodInListProtocol = + dyn_cast<ObjCProtocolDecl>(MethodInList->getDeclContext()); + // If this method belongs to a protocol but the method in list does not, or + // vice versa, we say the context is not the same. + if ((MethodProtocol && !MethodInListProtocol) || + (!MethodProtocol && MethodInListProtocol)) + return false; + + if (MethodProtocol && MethodInListProtocol) + return true; + + ObjCInterfaceDecl *MethodInterface = Method->getClassInterface(); + ObjCInterfaceDecl *MethodInListInterface = + MethodInList->getClassInterface(); + return MethodInterface == MethodInListInterface; +} + void Sema::addMethodToGlobalList(ObjCMethodList *List, ObjCMethodDecl *Method) { // Record at the head of the list whether there were 0, 1, or >= 2 methods @@ -3166,17 +3214,42 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, // We've seen a method with this name, see if we have already seen this type // signature. ObjCMethodList *Previous = List; + ObjCMethodList *ListWithSameDeclaration = nullptr; for (; List; Previous = List, List = List->getNext()) { // If we are building a module, keep all of the methods. - if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty()) + if (getLangOpts().CompilingModule) continue; - if (!MatchTwoMethodDeclarations(Method, List->getMethod())) { + bool SameDeclaration = MatchTwoMethodDeclarations(Method, + List->getMethod()); + // Looking for method with a type bound requires the correct context exists. + // We need to insert a method into the list if the context is different. + // If the method's declaration matches the list + // a> the method belongs to a different context: we need to insert it, in + // order to emit the availability message, we need to prioritize over + // availability among the methods with the same declaration. + // b> the method belongs to the same context: there is no need to insert a + // new entry. + // If the method's declaration does not match the list, we insert it to the + // end. + if (!SameDeclaration || + !isMethodContextSameForKindofLookup(Method, List->getMethod())) { // Even if two method types do not match, we would like to say // there is more than one declaration so unavailability/deprecated // warning is not too noisy. if (!Method->isDefined()) List->setHasMoreThanOneDecl(true); + + // For methods with the same declaration, the one that is deprecated + // should be put in the front for better diagnostics. + if (Method->isDeprecated() && SameDeclaration && + !ListWithSameDeclaration && !List->getMethod()->isDeprecated()) + ListWithSameDeclaration = List; + + if (Method->isUnavailable() && SameDeclaration && + !ListWithSameDeclaration && + List->getMethod()->getAvailability() < AR_Deprecated) + ListWithSameDeclaration = List; continue; } @@ -3212,6 +3285,16 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List, // We have a new signature for an existing method - add it. // This is extremely rare. Only 1% of Cocoa selectors are "overloaded". ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>(); + + // We insert it right before ListWithSameDeclaration. + if (ListWithSameDeclaration) { + auto *List = new (Mem) ObjCMethodList(*ListWithSameDeclaration); + // FIXME: should we clear the other bits in ListWithSameDeclaration? + ListWithSameDeclaration->setMethod(Method); + ListWithSameDeclaration->setNext(List); + return; + } + Previous->setNext(new (Mem) ObjCMethodList(Method)); } @@ -3222,6 +3305,12 @@ void Sema::ReadMethodPool(Selector Sel) { ExternalSource->ReadMethodPool(Sel); } +void Sema::updateOutOfDateSelector(Selector Sel) { + if (!ExternalSource) + return; + ExternalSource->updateOutOfDateSelector(Sel); +} + void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl, bool instance) { // Ignore methods of invalid containers. @@ -3261,25 +3350,95 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen, return (chosen->getReturnType()->isIntegerType()); } +/// Return true if the given method is wthin the type bound. +static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method, + const ObjCObjectType *TypeBound) { + if (!TypeBound) + return true; + + if (TypeBound->isObjCId()) + // FIXME: should we handle the case of bounding to id<A, B> differently? + return true; + + auto *BoundInterface = TypeBound->getInterface(); + assert(BoundInterface && "unexpected object type!"); + + // Check if the Method belongs to a protocol. We should allow any method + // defined in any protocol, because any subclass could adopt the protocol. + auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext()); + if (MethodProtocol) { + return true; + } + + // If the Method belongs to a class, check if it belongs to the class + // hierarchy of the class bound. + if (ObjCInterfaceDecl *MethodInterface = Method->getClassInterface()) { + // We allow methods declared within classes that are part of the hierarchy + // of the class bound (superclass of, subclass of, or the same as the class + // bound). + return MethodInterface == BoundInterface || + MethodInterface->isSuperClassOf(BoundInterface) || + BoundInterface->isSuperClassOf(MethodInterface); + } + llvm_unreachable("unknow method context"); +} + +/// We first select the type of the method: Instance or Factory, then collect +/// all methods with that type. bool Sema::CollectMultipleMethodsInGlobalPool( - Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) { + Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, + bool InstanceFirst, bool CheckTheOther, + const ObjCObjectType *TypeBound) { if (ExternalSource) ReadMethodPool(Sel); GlobalMethodPool::iterator Pos = MethodPool.find(Sel); if (Pos == MethodPool.end()) return false; + // Gather the non-hidden methods. - ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second; + ObjCMethodList &MethList = InstanceFirst ? Pos->second.first : + Pos->second.second; for (ObjCMethodList *M = &MethList; M; M = M->getNext()) - if (M->getMethod() && !M->getMethod()->isHidden()) - Methods.push_back(M->getMethod()); + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } + + // Return if we find any method with the desired kind. + if (!Methods.empty()) + return Methods.size() > 1; + + if (!CheckTheOther) + return false; + + // Gather the other kind. + ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second : + Pos->second.first; + for (ObjCMethodList *M = &MethList2; M; M = M->getNext()) + if (M->getMethod() && !M->getMethod()->isHidden()) { + if (FilterMethodsByTypeBound(M->getMethod(), TypeBound)) + Methods.push_back(M->getMethod()); + } + return Methods.size() > 1; } -bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod, - SourceRange R, - bool receiverIdOrClass) { +bool Sema::AreMultipleMethodsInGlobalPool( + Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R, + bool receiverIdOrClass, SmallVectorImpl<ObjCMethodDecl *> &Methods) { + // Diagnose finding more than one method in global pool. + SmallVector<ObjCMethodDecl *, 4> FilteredMethods; + FilteredMethods.push_back(BestMethod); + + for (auto *M : Methods) + if (M != BestMethod && !M->hasAttr<UnavailableAttr>()) + FilteredMethods.push_back(M); + + if (FilteredMethods.size() > 1) + DiagnoseMultipleMethodInGlobalPool(FilteredMethods, Sel, R, + receiverIdOrClass); + GlobalMethodPool::iterator Pos = MethodPool.find(Sel); // Test for no method in the pool which should not trigger any warning by // caller. @@ -3287,17 +3446,6 @@ bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMeth return true; ObjCMethodList &MethList = BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second; - - // Diagnose finding more than one method in global pool - SmallVector<ObjCMethodDecl *, 4> Methods; - Methods.push_back(BestMethod); - for (ObjCMethodList *ML = &MethList; ML; ML = ML->getNext()) - if (ObjCMethodDecl *M = ML->getMethod()) - if (!M->isHidden() && M != BestMethod && !M->hasAttr<UnavailableAttr>()) - Methods.push_back(M); - if (Methods.size() > 1) - DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass); - return MethList.hasMoreThanOneDecl(); } @@ -3650,10 +3798,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods, // property will be synthesized when property with same name is // seen in the @implementation. for (const auto *Ext : IDecl->visible_extensions()) { - for (const auto *Property : Ext->properties()) { + for (const auto *Property : Ext->instance_properties()) { // Skip over properties declared @dynamic if (const ObjCPropertyImplDecl *PIDecl - = IC->FindPropertyImplDecl(Property->getIdentifier())) + = IC->FindPropertyImplDecl(Property->getIdentifier(), + Property->getQueryKind())) if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; @@ -3839,7 +3988,7 @@ public: } } - typedef llvm::SmallPtrSet<ObjCMethodDecl*, 128>::iterator iterator; + typedef llvm::SmallPtrSetImpl<ObjCMethodDecl*>::iterator iterator; iterator begin() const { return Overridden.begin(); } iterator end() const { return Overridden.end(); } @@ -4463,6 +4612,9 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) { Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm) << DeclSpec::getSpecifierName(SCS); } + if (DS.isInlineSpecified()) + Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function) + << getLangOpts().CPlusPlus1z; if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec()) Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(), diag::err_invalid_thread) diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp index f12bf2415dba..4a21eb308fe5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp @@ -110,11 +110,17 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) { // A type denoted in an exception-specification shall not denote a // pointer or reference to an incomplete type, other than (cv) void* or a // pointer or reference to a class currently being defined. + // In Microsoft mode, downgrade this to a warning. + unsigned DiagID = diag::err_incomplete_in_exception_spec; + bool ReturnValueOnError = true; + if (getLangOpts().MicrosoftExt) { + DiagID = diag::ext_incomplete_in_exception_spec; + ReturnValueOnError = false; + } if (!(PointeeT->isRecordType() && PointeeT->getAs<RecordType>()->isBeingDefined()) && - RequireCompleteType(Range.getBegin(), PointeeT, - diag::err_incomplete_in_exception_spec, Kind, Range)) - return true; + RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range)) + return ReturnValueOnError; return false; } @@ -995,6 +1001,10 @@ CanThrowResult Sema::canThrow(const Expr *E) { return mergeCanThrow(CT, canSubExprsThrow(*this, E)); } + case Expr::CXXInheritedCtorInitExprClass: + return canCalleeThrow(*this, E, + cast<CXXInheritedCtorInitExpr>(E)->getConstructor()); + case Expr::LambdaExprClass: { const LambdaExpr *Lambda = cast<LambdaExpr>(E); CanThrowResult CT = CT_Cannot; @@ -1136,6 +1146,7 @@ CanThrowResult Sema::canThrow(const Expr *E) { case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::ObjCProtocolExprClass: case Expr::ObjCSelectorExprClass: + case Expr::ObjCAvailabilityCheckExprClass: case Expr::OffsetOfExprClass: case Expr::PackExpansionExprClass: case Expr::PseudoObjectExprClass: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp index 5a2eb6060ee9..57159fb59715 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp @@ -49,7 +49,7 @@ using namespace sema; /// \brief Determine whether the use of this declaration is valid, without /// emitting diagnostics. -bool Sema::CanUseDecl(NamedDecl *D) { +bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) { // See if this is an auto-typed variable whose initializer we are parsing. if (ParsingInitForAutoVars.count(D)) return false; @@ -67,7 +67,7 @@ bool Sema::CanUseDecl(NamedDecl *D) { } // See if this function is unavailable. - if (D->getAvailability() == AR_Unavailable && + if (TreatUnavailableAsInvalid && D->getAvailability() == AR_Unavailable && cast<Decl>(CurContext)->getAvailability() != AR_Unavailable) return false; @@ -76,10 +76,14 @@ bool Sema::CanUseDecl(NamedDecl *D) { static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) { // Warn if this is used but marked unused. - if (D->hasAttr<UnusedAttr>()) { - const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext()); - if (DC && !DC->hasAttr<UnusedAttr>()) - S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); + if (const auto *A = D->getAttr<UnusedAttr>()) { + // [[maybe_unused]] should not diagnose uses, but __attribute__((unused)) + // should diagnose them. + if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) { + const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext()); + if (DC && !DC->hasAttr<UnusedAttr>()) + S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName(); + } } } @@ -137,7 +141,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc, const ObjCPropertyDecl *ObjCPDecl = nullptr; if (Result == AR_Deprecated || Result == AR_Unavailable || - AR_NotYetIntroduced) { + Result == AR_NotYetIntroduced) { if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) { AvailabilityResult PDeclResult = PD->getAvailability(nullptr); @@ -212,25 +216,14 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) { // deleted. This might fail, if that reason no longer applies. CXXSpecialMember CSM = getSpecialMember(Method); if (CSM != CXXInvalid) - ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true); + ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true); return; } - if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Decl)) { - if (CXXConstructorDecl *BaseCD = - const_cast<CXXConstructorDecl*>(CD->getInheritedConstructor())) { - Diag(Decl->getLocation(), diag::note_inherited_deleted_here); - if (BaseCD->isDeleted()) { - NoteDeletedFunction(BaseCD); - } else { - // FIXME: An explanation of why exactly it can't be inherited - // would be nice. - Diag(BaseCD->getLocation(), diag::note_cannot_inherit); - } - return; - } - } + auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl); + if (Ctor && Ctor->isInheritingConstructor()) + return NoteDeletedInheritingConstructor(Ctor); Diag(Decl->getLocation(), diag::note_availability_specified_here) << Decl << true; @@ -357,7 +350,13 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, // See if this is a deleted function. if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { if (FD->isDeleted()) { - Diag(Loc, diag::err_deleted_function_use); + auto *Ctor = dyn_cast<CXXConstructorDecl>(FD); + if (Ctor && Ctor->isInheritingConstructor()) + Diag(Loc, diag::err_deleted_inherited_ctor_use) + << Ctor->getParent() + << Ctor->getInheritedConstructor().getConstructor()->getParent(); + else + Diag(Loc, diag::err_deleted_function_use); NoteDeletedFunction(FD); return true; } @@ -368,6 +367,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc, DeduceReturnType(FD, Loc)) return true; } + + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions + // Only the variables omp_in and omp_out are allowed in the combiner. + // Only the variables omp_priv and omp_orig are allowed in the + // initializer-clause. + auto *DRD = dyn_cast<OMPDeclareReductionDecl>(CurContext); + if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) && + isa<VarDecl>(D)) { + Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction) + << getCurFunction()->HasOMPDeclareReductionCombiner; + Diag(D->getLocation(), diag::note_entity_declared_at) << D; + return true; + } DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass, ObjCPropertyAccess); @@ -695,7 +707,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) { // balance that. if (getLangOpts().ObjCAutoRefCount && E->getType().getObjCLifetime() == Qualifiers::OCL_Weak) - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E, nullptr, VK_RValue); @@ -1138,6 +1150,48 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS, /*convertFloat=*/!IsCompAssign); } +/// \brief Diagnose attempts to convert between __float128 and long double if +/// there is no support for such conversion. Helper function of +/// UsualArithmeticConversions(). +static bool unsupportedTypeConversion(const Sema &S, QualType LHSType, + QualType RHSType) { + /* No issue converting if at least one of the types is not a floating point + type or the two types have the same rank. + */ + if (!LHSType->isFloatingType() || !RHSType->isFloatingType() || + S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0) + return false; + + assert(LHSType->isFloatingType() && RHSType->isFloatingType() && + "The remaining types must be floating point types."); + + auto *LHSComplex = LHSType->getAs<ComplexType>(); + auto *RHSComplex = RHSType->getAs<ComplexType>(); + + QualType LHSElemType = LHSComplex ? + LHSComplex->getElementType() : LHSType; + QualType RHSElemType = RHSComplex ? + RHSComplex->getElementType() : RHSType; + + // No issue if the two types have the same representation + if (&S.Context.getFloatTypeSemantics(LHSElemType) == + &S.Context.getFloatTypeSemantics(RHSElemType)) + return false; + + bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty && + RHSElemType == S.Context.LongDoubleTy); + Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy && + RHSElemType == S.Context.Float128Ty); + + /* We've handled the situation where __float128 and long double have the same + representation. The only other allowable conversion is if long double is + really just double. + */ + return Float128AndLongDouble && + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != + &llvm::APFloat::IEEEdouble); +} + typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType); namespace { @@ -1301,6 +1355,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS, // At this point, we have two different arithmetic types. + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSType, RHSType)) + return QualType(); + // Handle complex types first (C99 6.3.1.8p1). if (LHSType->isComplexType() || RHSType->isComplexType()) return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType, @@ -1719,10 +1778,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK, !Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart())) recordUseOfEvaluatedWeak(E); - // Just in case we're building an illegal pointer-to-member. - FieldDecl *FD = dyn_cast<FieldDecl>(D); - if (FD && FD->isBitField()) - E->setObjectKind(OK_BitField); + if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) { + UnusedPrivateFields.remove(FD); + // Just in case we're building an illegal pointer-to-member. + if (FD->isBitField()) + E->setObjectKind(OK_BitField); + } return E; } @@ -2840,6 +2901,7 @@ ExprResult Sema::BuildDeclarationNameExpr( // Unresolved using declarations are dependent. case Decl::EnumConstant: case Decl::UnresolvedUsingValue: + case Decl::OMPDeclareReduction: valueKind = VK_RValue; break; @@ -2877,6 +2939,7 @@ ExprResult Sema::BuildDeclarationNameExpr( case Decl::Var: case Decl::VarTemplateSpecialization: case Decl::VarTemplatePartialSpecialization: + case Decl::OMPCapturedExpr: // In C, "extern void blah;" is valid and is an r-value. if (!getLangOpts().CPlusPlus && !type.hasQualifiers() && @@ -3297,12 +3360,21 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) { if (Literal.isFloatingLiteral()) { QualType Ty; - if (Literal.isFloat) + if (Literal.isHalf){ + if (getOpenCLOptions().cl_khr_fp16) + Ty = Context.HalfTy; + else { + Diag(Tok.getLocation(), diag::err_half_const_requires_fp16); + return ExprError(); + } + } else if (Literal.isFloat) Ty = Context.FloatTy; - else if (!Literal.isLong) - Ty = Context.DoubleTy; - else + else if (Literal.isLong) Ty = Context.LongDoubleTy; + else if (Literal.isFloat128) + Ty = Context.Float128Ty; + else + Ty = Context.DoubleTy; Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation()); @@ -3890,14 +3962,24 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo, if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) { if (auto *TT = T->getAs<TypedefType>()) { - if (auto *CSI = dyn_cast<CapturingScopeInfo>(FunctionScopes.back())) { + for (auto I = FunctionScopes.rbegin(), + E = std::prev(FunctionScopes.rend()); + I != E; ++I) { + auto *CSI = dyn_cast<CapturingScopeInfo>(*I); + if (CSI == nullptr) + break; DeclContext *DC = nullptr; - if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI)) + if (auto *LSI = dyn_cast<LambdaScopeInfo>(CSI)) DC = LSI->CallOperator; - else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) + else if (auto *CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI)) DC = CRSI->TheCapturedDecl; - if (DC && TT->getDecl()->getDeclContext() != DC) + else if (auto *BSI = dyn_cast<BlockScopeInfo>(CSI)) + DC = BSI->TheDecl; + if (DC) { + if (DC->containsDecl(TT->getDecl())) + break; captureVariablyModifiedType(Context, T, CSI); + } } } } @@ -4141,12 +4223,18 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, ExprResult Result = CheckPlaceholderExpr(LowerBound); if (Result.isInvalid()) return ExprError(); + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) + return ExprError(); LowerBound = Result.get(); } if (Length && Length->getType()->isNonOverloadPlaceholderType()) { ExprResult Result = CheckPlaceholderExpr(Length); if (Result.isInvalid()) return ExprError(); + Result = DefaultLvalueConversion(Result.get()); + if (Result.isInvalid()) + return ExprError(); Length = Result.get(); } @@ -4253,6 +4341,13 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc, return ExprError(); } + if (!Base->getType()->isSpecificPlaceholderType( + BuiltinType::OMPArraySection)) { + ExprResult Result = DefaultFunctionArrayLvalueConversion(Base); + if (Result.isInvalid()) + return ExprError(); + Base = Result.get(); + } return new (Context) OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy, VK_LValue, OK_Ordinary, ColonLoc, RBLoc); @@ -4466,6 +4561,13 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, } } + // If the default argument expression is not set yet, we are building it now. + if (!Param->hasInit()) { + Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return ExprError(); + } + // If the default expression creates temporaries, we need to // push them to the current stack of expression temporaries so they'll // be properly destroyed. @@ -4473,15 +4575,15 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, // bound temporaries; see the comment in PR5810. // We don't need to do that with block decls, though, because // blocks in default argument expression can never capture anything. - if (isa<ExprWithCleanups>(Param->getInit())) { + if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) { // Set the "needs cleanups" bit regardless of whether there are // any explicit objects. - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects()); // Append all the objects to the cleanup list. Right now, this // should always be a no-op, because blocks in default argument // expressions should never be able to capture anything. - assert(!cast<ExprWithCleanups>(Param->getInit())->getNumObjects() && + assert(!Init->getNumObjects() && "default argument expression has capturing blocks?"); } @@ -4866,6 +4968,9 @@ static bool isPlaceholderToRemoveAsArg(QualType type) { switch (placeholder->getKind()) { // Ignore all the non-placeholder types. +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" #define PLACEHOLDER_TYPE(ID, SINGLETON_ID) #define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID: #include "clang/AST/BuiltinTypes.def" @@ -4995,6 +5100,14 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context, return OverloadDecl; } +static bool isNumberOfArgsValidForCall(Sema &S, const FunctionDecl *Callee, + std::size_t NumArgs) { + if (S.TooManyArguments(Callee->getNumParams(), NumArgs, + /*PartialOverloading=*/false)) + return Callee->isVariadic(); + return Callee->getMinRequiredArguments() <= NumArgs; +} + /// 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. @@ -5032,8 +5145,6 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, // Determine whether this is a dependent call inside a C++ template, // in which case we won't do any semantic analysis now. - // FIXME: Will need to cache the results of name lookup (including ADL) in - // Fn. bool Dependent = false; if (Fn->isTypeDependent()) Dependent = true; @@ -5126,7 +5237,14 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc, Fn->getLocStart())) return ExprError(); - if (FD->hasAttr<EnableIfAttr>()) { + // 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 + // we'll continue on as if the function call wasn't ill-formed. So, if the + // number of args looks incorrect, don't do enable_if checks; we should've + // already emitted an error about the bad call. + if (FD->hasAttr<EnableIfAttr>() && + isNumberOfArgsValidForCall(*this, FD, ArgExprs.size())) { if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) { Diag(Fn->getLocStart(), isa<CXXMethodDecl>(FD) ? @@ -5192,6 +5310,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl, FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl); unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0); + // Functions with 'interrupt' attribute cannot be called directly. + if (FDecl && FDecl->hasAttr<AnyX86InterruptAttr>()) { + Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called); + return ExprError(); + } + // Promote the function operand. // We special-case function promotion here because we only allow promoting // builtin functions to function pointers in the callee of a call. @@ -5474,7 +5598,7 @@ void Sema::maybeExtendBlockObject(ExprResult &E) { E = ImplicitCastExpr::Create(Context, E.get()->getType(), CK_ARCExtendBlockObject, E.get(), /*base path*/ nullptr, VK_RValue); - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); } /// Prepare a conversion of the given expression to an ObjC object @@ -6122,30 +6246,87 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS, lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual); rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual); + // For OpenCL: + // 1. If LHS and RHS types match exactly and: + // (a) AS match => use standard C rules, no bitcast or addrspacecast + // (b) AS overlap => generate addrspacecast + // (c) AS don't overlap => give an error + // 2. if LHS and RHS types don't match: + // (a) AS match => use standard C rules, generate bitcast + // (b) AS overlap => generate addrspacecast instead of bitcast + // (c) AS don't overlap => give an error + + // For OpenCL, non-null composite type is returned only for cases 1a and 1b. QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee); + // OpenCL cases 1c, 2a, 2b, and 2c. if (CompositeTy.isNull()) { - S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) - << LHSTy << RHSTy << LHS.get()->getSourceRange() - << RHS.get()->getSourceRange(); // In this situation, we assume void* type. No especially good // reason, but this is what gcc does, and we do have to pick // to get a consistent AST. - QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy); - LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); + QualType incompatTy; + if (S.getLangOpts().OpenCL) { + // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address + // spaces is disallowed. + unsigned ResultAddrSpace; + if (lhQual.isAddressSpaceSupersetOf(rhQual)) { + // Cases 2a and 2b. + ResultAddrSpace = lhQual.getAddressSpace(); + } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) { + // Cases 2a and 2b. + ResultAddrSpace = rhQual.getAddressSpace(); + } else { + // Cases 1c and 2c. + S.Diag(Loc, + diag::err_typecheck_op_on_nonoverlapping_address_space_pointers) + << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + return QualType(); + } + + // Continue handling cases 2a and 2b. + incompatTy = S.Context.getPointerType( + S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace)); + LHS = S.ImpCastExprToType(LHS.get(), incompatTy, + (lhQual.getAddressSpace() != ResultAddrSpace) + ? CK_AddressSpaceConversion /* 2b */ + : CK_BitCast /* 2a */); + RHS = S.ImpCastExprToType(RHS.get(), incompatTy, + (rhQual.getAddressSpace() != ResultAddrSpace) + ? CK_AddressSpaceConversion /* 2b */ + : CK_BitCast /* 2a */); + } else { + S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers) + << LHSTy << RHSTy << LHS.get()->getSourceRange() + << RHS.get()->getSourceRange(); + incompatTy = S.Context.getPointerType(S.Context.VoidTy); + LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast); + RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast); + } return incompatTy; } // The pointer types are compatible. QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual); + auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast; if (IsBlockPointer) ResultTy = S.Context.getBlockPointerType(ResultTy); - else + else { + // Cases 1a and 1b for OpenCL. + auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace(); + LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace + ? CK_BitCast /* 1a */ + : CK_AddressSpaceConversion /* 1b */; + RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace + ? CK_BitCast /* 1a */ + : CK_AddressSpaceConversion /* 1b */; ResultTy = S.Context.getPointerType(ResultTy); + } - LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast); - RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast); + // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast + // if the target type does not change. + LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind); + RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind); return ResultTy; } @@ -6413,6 +6594,18 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond, return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc); } +/// \brief Return true if the Expr is block type +static bool checkBlockType(Sema &S, const Expr *E) { + if (const CallExpr *CE = dyn_cast<CallExpr>(E)) { + QualType Ty = CE->getCallee()->getType(); + if (Ty->isBlockPointerType()) { + S.Diag(E->getExprLoc(), diag::err_opencl_ternary_with_block); + return true; + } + } + return false; +} + /// Note that LHS is not null here, even if this is the gnu "x ?: y" extension. /// In that case, LHS = cond. /// C99 6.5.15 @@ -6462,6 +6655,22 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType LHSTy = LHS.get()->getType(); QualType RHSTy = RHS.get()->getType(); + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) { + Diag(QuestionLoc, + diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } + + // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary + // selection operator (?:). + if (getLangOpts().OpenCL && + (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) { + return QualType(); + } + // If both operands have arithmetic type, do the usual arithmetic conversions // to find a common type: C99 6.5.15p3,5. if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) { @@ -6804,8 +7013,23 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc, // doesn't handle dependent types properly, so make sure any TypoExprs have // been dealt with before checking the operands. ExprResult CondResult = CorrectDelayedTyposInExpr(CondExpr); - if (!CondResult.isUsable()) return ExprError(); + ExprResult LHSResult = CorrectDelayedTyposInExpr(LHSExpr); + ExprResult RHSResult = CorrectDelayedTyposInExpr(RHSExpr); + + if (!CondResult.isUsable()) + return ExprError(); + + if (LHSExpr) { + if (!LHSResult.isUsable()) + return ExprError(); + } + + if (!RHSResult.isUsable()) + return ExprError(); + CondExpr = CondResult.get(); + LHSExpr = LHSResult.get(); + RHSExpr = RHSResult.get(); } // If this is the gnu "x ?: y" extension, analyze the types as though the LHS @@ -6918,7 +7142,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) { else if (lhq.getObjCLifetime() != rhq.getObjCLifetime()) ConvTy = Sema::IncompatiblePointerDiscardsQualifiers; - // For GCC compatibility, other qualifier mismatches are treated + // For GCC/MS compatibility, other qualifier mismatches are treated // as still compatible in C. else ConvTy = Sema::CompatiblePointerDiscardsQualifiers; } @@ -7170,9 +7394,30 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS, return IncompatibleVectors; } } + + // When the RHS comes from another lax conversion (e.g. binops between + // scalars and vectors) the result is canonicalized as a vector. When the + // LHS is also a vector, the lax is allowed by the condition above. Handle + // the case where LHS is a scalar. + if (LHSType->isScalarType()) { + const VectorType *VecType = RHSType->getAs<VectorType>(); + if (VecType && VecType->getNumElements() == 1 && + isLaxVectorConversion(RHSType, LHSType)) { + ExprResult *VecExpr = &RHS; + *VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast); + Kind = CK_BitCast; + return Compatible; + } + } + return Incompatible; } + // Diagnose attempts to convert between __float128 and long double where + // such conversions currently can't be handled. + if (unsupportedTypeConversion(*this, LHSType, RHSType)) + return Incompatible; + // Arithmetic conversions. if (LHSType->isArithmeticType() && RHSType->isArithmeticType() && !(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) { @@ -7539,13 +7784,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS, if (result != Incompatible && RHS.get()->getType() != LHSType) { QualType Ty = LHSType.getNonLValueExprType(Context); Expr *E = RHS.get(); - if (getLangOpts().ObjCAutoRefCount) - CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, - Diagnose, DiagnoseCFAudited); + + // Check for various Objective-C errors. If we are not reporting + // diagnostics and just checking for errors, e.g., during overload + // resolution, return Incompatible to indicate the failure. + if (getLangOpts().ObjCAutoRefCount && + CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion, + Diagnose, DiagnoseCFAudited) != ACR_okay) { + if (!Diagnose) + return Incompatible; + } if (getLangOpts().ObjC1 && (CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType, E->getType(), E, Diagnose) || ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) { + if (!Diagnose) + return Incompatible; + // Replace the expression with a corrected version and continue so we + // can find further errors. RHS = E; return Compatible; } @@ -7693,14 +7949,16 @@ 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. - // FIXME: Should we really be allowing this? - // FIXME: We really just pick the LHS type arbitrarily? - if (isLaxVectorConversion(RHSType, LHSType)) { - QualType resultType = LHSType; - RHS = ImpCastExprToType(RHS.get(), resultType, CK_BitCast); - return resultType; + // 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. + 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; } // Okay, the expression is invalid. @@ -9244,7 +9502,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS, } // Return a signed type for the vector. - return GetSignedVectorType(LHSType); + return GetSignedVectorType(vType); } QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS, @@ -9411,7 +9669,16 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) { // Decide whether the first capture was for a block or a lambda. DeclContext *DC = S.CurContext, *Prev = nullptr; - while (DC != var->getDeclContext()) { + // Decide whether the first capture was for a block or a lambda. + while (DC) { + // For init-capture, it is possible that the variable belongs to the + // template pattern of the current context. + if (auto *FD = dyn_cast<FunctionDecl>(DC)) + if (var->isInitCapture() && + FD->getTemplateInstantiationPattern() == var->getDeclContext()) + break; + if (DC == var->getDeclContext()) + break; Prev = DC; DC = DC->getParent(); } @@ -9558,6 +9825,9 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E, /// emit an error and return true. If so, return false. static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) { assert(!E->hasPlaceholderType(BuiltinType::PseudoObject)); + + S.CheckShadowingDeclModification(E, Loc); + SourceLocation OrigLoc = Loc; Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context, &Loc); @@ -9798,6 +10068,67 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS, ? LHSType : LHSType.getUnqualifiedType()); } +// Only ignore explicit casts to void. +static bool IgnoreCommaOperand(const Expr *E) { + E = E->IgnoreParens(); + + if (const CastExpr *CE = dyn_cast<CastExpr>(E)) { + if (CE->getCastKind() == CK_ToVoid) { + return true; + } + } + + return false; +} + +// Look for instances where it is likely the comma operator is confused with +// another operator. There is a whitelist of acceptable expressions for the +// left hand side of the comma operator, otherwise emit a warning. +void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) { + // No warnings in macros + if (Loc.isMacroID()) + return; + + // Don't warn in template instantiations. + if (!ActiveTemplateInstantiations.empty()) + return; + + // Scope isn't fine-grained enough to whitelist the specific cases, so + // instead, skip more than needed, then call back into here with the + // CommaVisitor in SemaStmt.cpp. + // The whitelisted locations are the initialization and increment portions + // of a for loop. The additional checks are on the condition of + // if statements, do/while loops, and for loops. + const unsigned ForIncrementFlags = + Scope::ControlScope | Scope::ContinueScope | Scope::BreakScope; + const unsigned ForInitFlags = Scope::ControlScope | Scope::DeclScope; + const unsigned ScopeFlags = getCurScope()->getFlags(); + if ((ScopeFlags & ForIncrementFlags) == ForIncrementFlags || + (ScopeFlags & ForInitFlags) == ForInitFlags) + return; + + // If there are multiple comma operators used together, get the RHS of the + // of the comma operator as the LHS. + while (const BinaryOperator *BO = dyn_cast<BinaryOperator>(LHS)) { + if (BO->getOpcode() != BO_Comma) + break; + LHS = BO->getRHS(); + } + + // Only allow some expressions on LHS to not warn. + if (IgnoreCommaOperand(LHS)) + return; + + Diag(Loc, diag::warn_comma_operator); + Diag(LHS->getLocStart(), diag::note_cast_to_void) + << LHS->getSourceRange() + << FixItHint::CreateInsertion(LHS->getLocStart(), + LangOpts.CPlusPlus ? "static_cast<void>(" + : "(void)(") + << FixItHint::CreateInsertion(PP.getLocForEndOfToken(LHS->getLocEnd()), + ")"); +} + // C99 6.5.17 static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, SourceLocation Loc) { @@ -9827,6 +10158,9 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS, diag::err_incomplete_type); } + if (!S.getDiagnostics().isIgnored(diag::warn_comma_operator, Loc)) + S.DiagnoseCommaOperator(LHS.get(), Loc); + return RHS.get()->getType(); } @@ -10075,8 +10409,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { if (sfinae) return QualType(); // Materialize the temporary as an lvalue so that we can take its address. - OrigOp = op = new (Context) - MaterializeTemporaryExpr(op->getType(), OrigOp.get(), true); + OrigOp = op = + CreateMaterializeTemporaryExpr(op->getType(), OrigOp.get(), true); } else if (isa<ObjCSelectorExpr>(op)) { return Context.getPointerType(op->getType()); } else if (lval == Expr::LV_MemberFunction) { @@ -10199,6 +10533,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) { // If the operand has type "type", the result has type "pointer to type". if (op->getType()->isObjCObjectType()) return Context.getObjCObjectPointerType(op->getType()); + return Context.getPointerType(op->getType()); } @@ -10240,7 +10575,9 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK, } if (const PointerType *PT = OpTy->getAs<PointerType>()) + { Result = PT->getPointeeType(); + } else if (const ObjCObjectPointerType *OPT = OpTy->getAs<ObjCObjectPointerType>()) Result = OPT->getPointeeType(); @@ -10478,10 +10815,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } if (getLangOpts().OpenCL) { + QualType LHSTy = LHSExpr->getType(); + QualType RHSTy = RHSExpr->getType(); // OpenCLC v2.0 s6.13.11.1 allows atomic variables to be initialized by // the ATOMIC_VAR_INIT macro. - if (LHSExpr->getType()->isAtomicType() || - RHSExpr->getType()->isAtomicType()) { + if (LHSTy->isAtomicType() || RHSTy->isAtomicType()) { SourceRange SR(LHSExpr->getLocStart(), RHSExpr->getLocEnd()); if (BO_Assign == Opc) Diag(OpLoc, diag::err_atomic_init_constant) << SR; @@ -10489,6 +10827,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, ResultTy = InvalidOperands(OpLoc, LHS, RHS); return ExprError(); } + + // OpenCL special types - image, sampler, pipe, and blocks are to be used + // only with a builtin functions and therefore should be disallowed here. + if (LHSTy->isImageType() || RHSTy->isImageType() || + LHSTy->isSamplerT() || RHSTy->isSamplerT() || + LHSTy->isPipeType() || RHSTy->isPipeType() || + LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) { + ResultTy = InvalidOperands(OpLoc, LHS, RHS); + return ExprError(); + } } switch (Opc) { @@ -10959,8 +11307,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, ExprObjectKind OK = OK_Ordinary; QualType resultType; if (getLangOpts().OpenCL) { + QualType Ty = InputExpr->getType(); // The only legal unary operation for atomics is '&'. - if (Opc != UO_AddrOf && InputExpr->getType()->isAtomicType()) { + if ((Opc != UO_AddrOf && Ty->isAtomicType()) || + // OpenCL special types - image, sampler, pipe, and blocks are to be used + // only with a builtin functions and therefore should be disallowed here. + (Ty->isImageType() || Ty->isSamplerT() || Ty->isPipeType() + || Ty->isBlockPointerType())) { return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr) << InputExpr->getType() << Input.get()->getSourceRange()); @@ -11273,7 +11626,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt, if (hasAnyUnrecoverableErrorsInThisFunction()) DiscardCleanupsInEvaluationContext(); - assert(!ExprNeedsCleanups && "cleanups within StmtExpr not correctly bound!"); + assert(!Cleanup.exprNeedsCleanups() && + "cleanups within StmtExpr not correctly bound!"); PopExpressionEvaluationContext(); // FIXME: there are a variety of strange constraints to enforce here, for @@ -11697,8 +12051,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, // Set the parameters on the block decl. if (!Params.empty()) { CurBlock->TheDecl->setParams(Params); - CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(), - CurBlock->TheDecl->param_end(), + CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(), /*CheckParameterNames=*/false); } @@ -11706,7 +12059,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo, ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo); // Put the parameter variables in scope. - for (auto AI : CurBlock->TheDecl->params()) { + for (auto AI : CurBlock->TheDecl->parameters()) { AI->setOwningFunction(CurBlock->TheDecl); // If this has an identifier, add it to the scope stack. @@ -11736,12 +12089,13 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, Stmt *Body, Scope *CurScope) { // If blocks are disabled, emit an error. if (!LangOpts.Blocks) - Diag(CaretLoc, diag::err_blocks_disable); + Diag(CaretLoc, diag::err_blocks_disable) << LangOpts.OpenCL; // Leave the expression-evaluation context. if (hasAnyUnrecoverableErrorsInThisFunction()) DiscardCleanupsInEvaluationContext(); - assert(!ExprNeedsCleanups && "cleanups within block not correctly bound!"); + assert(!Cleanup.exprNeedsCleanups() && + "cleanups within block not correctly bound!"); PopExpressionEvaluationContext(); BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back()); @@ -11805,8 +12159,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, BlockTy = Context.getFunctionType(RetTy, None, EPI); } - DiagnoseUnusedParameters(BSI->TheDecl->param_begin(), - BSI->TheDecl->param_end()); + DiagnoseUnusedParameters(BSI->TheDecl->parameters()); BlockTy = Context.getBlockPointerType(BlockTy); // If needed, diagnose invalid gotos and switches in the block. @@ -11832,7 +12185,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, if (Result->getBlockDecl()->hasCaptures()) { // First, this expression has a new cleanup object. ExprCleanupObjects.push_back(Result->getBlockDecl()); - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); // It also gets a branch-protected scope if any of the captured // variables needs destruction. @@ -11848,9 +12201,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc, return Result; } -ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, - Expr *E, ParsedType Ty, - SourceLocation RPLoc) { +ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty, + SourceLocation RPLoc) { TypeSourceInfo *TInfo; GetTypeFromParser(Ty, &TInfo); return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc); @@ -11862,6 +12214,15 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc, Expr *OrigExpr = E; bool IsMS = false; + // CUDA device code does not support varargs. + if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) { + if (const FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) { + CUDAFunctionTarget T = IdentifyCUDATarget(F); + if (T == CFT_Global || T == CFT_Device || T == CFT_HostDevice) + return ExprError(Diag(E->getLocStart(), diag::err_va_arg_in_device)); + } + } + // It might be a __builtin_ms_va_list. (But don't ever mark a va_arg() // as Microsoft ABI on an actual Microsoft platform, where // __builtin_ms_va_list and __builtin_va_list are the same.) @@ -12000,10 +12361,11 @@ bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp, StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr); if (!SL || !SL->isAscii()) return false; - if (Diagnose) + if (Diagnose) { Diag(SL->getLocStart(), diag::err_missing_atsign_prefix) << FixItHint::CreateInsertion(SL->getLocStart(), "@"); - Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get(); + Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get(); + } return true; } @@ -12460,10 +12822,9 @@ void Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext, Decl *LambdaContextDecl, bool IsDecltype) { - ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), - ExprNeedsCleanups, LambdaContextDecl, - IsDecltype); - ExprNeedsCleanups = false; + ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup, + LambdaContextDecl, IsDecltype); + Cleanup.reset(); if (!MaybeODRUseExprs.empty()) std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs); } @@ -12514,12 +12875,12 @@ void Sema::PopExpressionEvaluationContext() { if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) { ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects, ExprCleanupObjects.end()); - ExprNeedsCleanups = Rec.ParentNeedsCleanups; + Cleanup = Rec.ParentCleanup; CleanupVarDeclMarking(); std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs); // Otherwise, merge the contexts together. } else { - ExprNeedsCleanups |= Rec.ParentNeedsCleanups; + Cleanup.mergeFrom(Rec.ParentCleanup); MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(), Rec.SavedMaybeODRUseExprs.end()); } @@ -12538,7 +12899,7 @@ void Sema::DiscardCleanupsInEvaluationContext() { ExprCleanupObjects.erase( ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects, ExprCleanupObjects.end()); - ExprNeedsCleanups = false; + Cleanup.reset(); MaybeODRUseExprs.clear(); } @@ -12563,6 +12924,11 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { // definition of a null pointer constant is completely crazy.) return false; + case Sema::DiscardedStatement: + // These are technically a potentially evaluated but they have the effect + // of suppressing use marking. + return false; + case Sema::ConstantEvaluated: case Sema::PotentiallyEvaluated: // We are in a potentially evaluated expression (or a constant-expression @@ -12581,7 +12947,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) { /// \brief Mark a function referenced, and check whether it is odr-used /// (C++ [basic.def.odr]p2, C99 6.9p3) void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, - bool OdrUse) { + bool MightBeOdrUse) { assert(Func && "No function?"); Func->setReferenced(); @@ -12592,39 +12958,53 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // set of overloaded functions [...]. // // We (incorrectly) mark overload resolution as an unevaluated context, so we - // can just check that here. Skip the rest of this function if we've already - // marked the function as used. - if (Func->isUsed(/*CheckUsedAttr=*/false) || - !IsPotentiallyEvaluatedContext(*this)) { - // C++11 [temp.inst]p3: - // Unless a function template specialization has been explicitly - // instantiated or explicitly specialized, the function template - // specialization is implicitly instantiated when the specialization is - // referenced in a context that requires a function definition to exist. - // - // We consider constexpr function templates to be referenced in a context - // that requires a definition to exist whenever they are referenced. - // - // FIXME: This instantiates constexpr functions too frequently. If this is - // really an unevaluated context (and we're not just in the definition of a - // function template or overload resolution or other cases which we - // incorrectly consider to be unevaluated contexts), and we're not in a - // subexpression which we actually need to evaluate (for instance, a - // template argument, array bound or an expression in a braced-init-list), - // we are not permitted to instantiate this constexpr function definition. - // - // FIXME: This also implicitly defines special members too frequently. They - // are only supposed to be implicitly defined if they are odr-used, but they - // are not odr-used from constant expressions in unevaluated contexts. - // However, they cannot be referenced if they are deleted, and they are - // deleted whenever the implicit definition of the special member would - // fail. - if (!Func->isConstexpr() || Func->getBody()) - return; - CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); - if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided())) - return; - } + // can just check that here. + bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this); + + // Determine whether we require a function definition to exist, per + // C++11 [temp.inst]p3: + // Unless a function template specialization has been explicitly + // instantiated or explicitly specialized, the function template + // specialization is implicitly instantiated when the specialization is + // referenced in a context that requires a function definition to exist. + // + // We consider constexpr function templates to be referenced in a context + // that requires a definition to exist whenever they are referenced. + // + // FIXME: This instantiates constexpr functions too frequently. If this is + // really an unevaluated context (and we're not just in the definition of a + // function template or overload resolution or other cases which we + // incorrectly consider to be unevaluated contexts), and we're not in a + // subexpression which we actually need to evaluate (for instance, a + // template argument, array bound or an expression in a braced-init-list), + // we are not permitted to instantiate this constexpr function definition. + // + // FIXME: This also implicitly defines special members too frequently. They + // are only supposed to be implicitly defined if they are odr-used, but they + // are not odr-used from constant expressions in unevaluated contexts. + // However, they cannot be referenced if they are deleted, and they are + // deleted whenever the implicit definition of the special member would + // fail (with very few exceptions). + CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func); + bool NeedDefinition = + OdrUse || (Func->isConstexpr() && (Func->isImplicitlyInstantiable() || + (MD && !MD->isUserProvided()))); + + // C++14 [temp.expl.spec]p6: + // If a template [...] is explicitly specialized then that specialization + // shall be declared before the first use of that specialization that would + // cause an implicit instantiation to take place, in every translation unit + // in which such a use occurs + if (NeedDefinition && + (Func->getTemplateSpecializationKind() != TSK_Undeclared || + Func->getMemberSpecializationInfo())) + checkSpecializationVisibility(Loc, Func); + + // 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) && + (!NeedDefinition || Func->getBody())) + return; // Note that this declaration has been used. if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) { @@ -12659,7 +13039,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) { if (MethodDecl->isCopyAssignmentOperator()) DefineImplicitCopyAssignment(Loc, MethodDecl); - else + else if (MethodDecl->isMoveAssignmentOperator()) DefineImplicitMoveAssignment(Loc, MethodDecl); } } else if (isa<CXXConversionDecl>(MethodDecl) && @@ -12684,8 +13064,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType())) ResolveExceptionSpec(Loc, FPT); - if (!OdrUse) return; - // Implicit instantiation of function templates and member functions of // class templates. if (Func->isImplicitlyInstantiable()) { @@ -12733,10 +13111,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, // Walk redefinitions, as some of them may be instantiable. for (auto i : Func->redecls()) { if (!i->isUsed(false) && i->isImplicitlyInstantiable()) - MarkFunctionReferenced(Loc, i); + MarkFunctionReferenced(Loc, i, OdrUse); } } + if (!OdrUse) return; + // Keep track of used but undefined functions. if (!Func->isDefined()) { if (mightHaveNonExternalLinkage(Func)) @@ -12747,17 +13127,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func, UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc)); } - // Normally the most current decl is marked used while processing the use and - // any subsequent decls are marked used by decl merging. This fails with - // template instantiation since marking can happen at the end of the file - // and, because of the two phase lookup, this function is called with at - // decl in the middle of a decl chain. We loop to maintain the invariant - // that once a decl is used, all decls after it are also used. - for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) { - F->markUsed(Context); - if (F == Func) - break; - } + Func->markUsed(Context); } static void @@ -12945,7 +13315,8 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var, return false; } const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>(); - if (HasBlocksAttr || CaptureType->isReferenceType()) { + if (HasBlocksAttr || CaptureType->isReferenceType() || + (S.getLangOpts().OpenMP && S.IsOpenMPCapturedDecl(Var))) { // Block capture by reference does not change the capture or // declaration reference types. ByRef = true; @@ -13013,14 +13384,13 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, QualType &DeclRefType, const bool RefersToCapturedVariable, Sema &S) { - // By default, capture variables by reference. bool ByRef = true; // Using an LValue reference type is consistent with Lambdas (see below). - if (S.getLangOpts().OpenMP) { - ByRef = S.IsOpenMPCapturedByRef(Var, RSI); - if (S.IsOpenMPCapturedVar(Var)) + if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) { + if (S.IsOpenMPCapturedDecl(Var)) DeclRefType = DeclRefType.getUnqualifiedType(); + ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel); } if (ByRef) @@ -13060,7 +13430,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI, /// \brief Create a field within the lambda class for the variable /// being captured. -static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var, +static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, QualType FieldType, QualType DeclRefType, SourceLocation Loc, bool RefersToCapturedVariable) { @@ -13154,7 +13524,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI, // Capture this variable in the lambda. if (BuildAndDiagnose) - addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc, + addAsFieldToClosureType(S, LSI, CaptureType, DeclRefType, Loc, RefersToCapturedVariable); // Compute the type of a reference to this captured variable. @@ -13210,7 +13580,7 @@ bool Sema::tryCaptureVariable( // Capture global variables if it is required to use private copy of this // variable. bool IsGlobal = !Var->hasLocalStorage(); - if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var))) + if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var))) return true; // Walk up the stack to determine whether we can capture the variable, @@ -13226,7 +13596,6 @@ bool Sema::tryCaptureVariable( bool Nested = false; bool Explicit = (Kind != TryCapture_Implicit); unsigned FunctionScopesIndex = MaxFunctionScopesIndex; - unsigned OpenMPLevel = 0; do { // Only block literals, captured statements, and lambda expressions can // capture; other scopes don't work. @@ -13292,20 +13661,19 @@ bool Sema::tryCaptureVariable( // just break here. Similarly, global variables that are captured in a // target region should not be captured outside the scope of the region. if (RSI->CapRegionKind == CR_OpenMP) { - auto isTargetCap = isOpenMPTargetCapturedVar(Var, OpenMPLevel); + auto IsTargetCap = isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel); // When we detect target captures we are looking from inside the // target region, therefore we need to propagate the capture from the // enclosing region. Therefore, the capture is not initially nested. - if (isTargetCap) + if (IsTargetCap) FunctionScopesIndex--; - if (isTargetCap || isOpenMPPrivateVar(Var, OpenMPLevel)) { - Nested = !isTargetCap; + if (IsTargetCap || isOpenMPPrivateDecl(Var, RSI->OpenMPLevel)) { + Nested = !IsTargetCap; DeclRefType = DeclRefType.getUnqualifiedType(); CaptureType = Context.getLValueReferenceType(DeclRefType); break; } - ++OpenMPLevel; } } } @@ -13316,8 +13684,9 @@ bool Sema::tryCaptureVariable( Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName(); Diag(Var->getLocation(), diag::note_previous_decl) << Var->getDeclName(); - Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(), - diag::note_lambda_decl); + if (cast<LambdaScopeInfo>(CSI)->Lambda) + Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(), + diag::note_lambda_decl); // FIXME: If we error out because an outer lambda can not implicitly // capture a variable that an inner lambda explicitly captures, we // should have the inner lambda do the explicit capture - because @@ -13539,6 +13908,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, assert(!isa<VarTemplatePartialSpecializationDecl>(Var) && "Can't instantiate a partial template specialization."); + // If this might be a member specialization of a static data member, check + // the specialization is visible. We already did the checks for variable + // template specializations when we created them. + if (TSK != TSK_Undeclared && !isa<VarTemplateSpecializationDecl>(Var)) + SemaRef.checkSpecializationVisibility(Loc, Var); + // Perform implicit instantiation of static data members, static data member // templates of class templates, and variable template specializations. Delay // instantiations of variable templates, except for those that could be used @@ -13582,7 +13957,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, } } - if(!MarkODRUsed) return; + if (!MarkODRUsed) + return; // Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies // the requirements for appearing in a constant expression (5.19) and, if @@ -13610,13 +13986,16 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) { } static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, - Decl *D, Expr *E, bool OdrUse) { + Decl *D, Expr *E, bool MightBeOdrUse) { + if (SemaRef.isInOpenMPDeclareTargetContext()) + SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D); + if (VarDecl *Var = dyn_cast<VarDecl>(D)) { DoMarkVarDeclReferenced(SemaRef, Loc, Var, E); return; } - SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse); // If this is a call to a method via a cast, also mark the method in the // derived class used in case codegen can devirtualize the call. @@ -13638,7 +14017,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc, CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl); if (!DM || DM->isPure()) return; - SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse); + SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse); } /// \brief Perform reference-marking and odr-use handling for a DeclRefExpr. @@ -13661,30 +14040,31 @@ void Sema::MarkMemberReferenced(MemberExpr *E) { // overload resolution when referred to from a potentially-evaluated // expression, is odr-used, unless it is a pure virtual function and its // name is not explicitly qualified. - bool OdrUse = true; + bool MightBeOdrUse = true; if (E->performsVirtualDispatch(getLangOpts())) { if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl())) if (Method->isPure()) - OdrUse = false; + MightBeOdrUse = false; } SourceLocation Loc = E->getMemberLoc().isValid() ? E->getMemberLoc() : E->getLocStart(); - MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, OdrUse); + MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse); } /// \brief Perform marking for a reference to an arbitrary declaration. It /// marks the declaration referenced, and performs odr-use checking for /// functions and variables. This method should not be used when building a /// normal expression which refers to a variable. -void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) { - if (OdrUse) { +void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, + bool MightBeOdrUse) { + if (MightBeOdrUse) { if (auto *VD = dyn_cast<VarDecl>(D)) { MarkVariableReferenced(Loc, VD); return; } } if (auto *FD = dyn_cast<FunctionDecl>(D)) { - MarkFunctionReferenced(Loc, FD, OdrUse); + MarkFunctionReferenced(Loc, FD, MightBeOdrUse); return; } D->setReferenced(); @@ -13838,6 +14218,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement, switch (ExprEvalContexts.back().Context) { case Unevaluated: case UnevaluatedAbstract: + case DiscardedStatement: // The argument will never be evaluated, so don't complain. break; @@ -13987,7 +14368,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) { } } -ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { +ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E, + bool IsConstexpr) { DiagnoseAssignmentAsCondition(E); if (ParenExpr *parenE = dyn_cast<ParenExpr>(E)) DiagnoseEqualityWithExtraParens(parenE); @@ -13998,7 +14380,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { if (!E->isTypeDependent()) { if (getLangOpts().CPlusPlus) - return CheckCXXBooleanCondition(E); // C++ 6.4p4 + return CheckCXXBooleanCondition(E, IsConstexpr); // C++ 6.4p4 ExprResult ERes = DefaultFunctionArrayLvalueConversion(E); if (ERes.isInvalid()) @@ -14017,12 +14399,36 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) { return E; } -ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc, - Expr *SubExpr) { +Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc, + Expr *SubExpr, ConditionKind CK) { + // Empty conditions are valid in for-statements. if (!SubExpr) - return ExprError(); + return ConditionResult(); - return CheckBooleanCondition(SubExpr, Loc); + ExprResult Cond; + switch (CK) { + case ConditionKind::Boolean: + Cond = CheckBooleanCondition(Loc, SubExpr); + break; + + case ConditionKind::ConstexprIf: + Cond = CheckBooleanCondition(Loc, SubExpr, true); + break; + + case ConditionKind::Switch: + Cond = CheckSwitchCondition(Loc, SubExpr); + break; + } + if (Cond.isInvalid()) + return ConditionError(); + + // FIXME: FullExprArg doesn't have an invalid bit, so check nullness instead. + FullExprArg FullExpr = MakeFullExpr(Cond.get(), Loc); + if (!FullExpr.get()) + return ConditionError(); + + return ConditionResult(*this, nullptr, FullExpr, + CK == ConditionKind::ConstexprIf); } namespace { @@ -14457,6 +14863,12 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) { ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType, Expr *CastExpr, CastKind &CastKind, ExprValueKind &VK, CXXCastPath &Path) { + // The type we're casting to must be either void or complete. + if (!CastType->isVoidType() && + RequireCompleteType(TypeRange.getBegin(), CastType, + diag::err_typecheck_cast_to_incomplete)) + return ExprError(); + // Rewrite the casted expression from scratch. ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr); if (!result.isUsable()) return ExprError(); @@ -14559,16 +14971,20 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { case BuiltinType::Overload: { // Try to resolve a single function template specialization. // This is obligatory. - ExprResult result = E; - if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) { - return result; + ExprResult Result = E; + if (ResolveAndFixSingleFunctionTemplateSpecialization(Result, false)) + return Result; + + // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization + // leaves Result unchanged on failure. + Result = E; + if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result)) + return Result; // If that failed, try to recover with a call. - } else { - tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable), - /*complain*/ true); - return result; - } + tryToRecoverWithCall(Result, PDiag(diag::err_ovl_unresolvable), + /*complain*/ true); + return Result; } // Bound member functions. @@ -14627,8 +15043,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) { return ExprError(); // Everything else should be impossible. -#define BUILTIN_TYPE(Id, SingletonId) \ +#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: +#include "clang/Basic/OpenCLImageTypes.def" +#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id: #define PLACEHOLDER_TYPE(Id, SingletonId) #include "clang/AST/BuiltinTypes.def" break; @@ -14665,3 +15083,27 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) { return new (Context) ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc); } + +ExprResult Sema::ActOnObjCAvailabilityCheckExpr( + llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc, + SourceLocation RParen) { + + StringRef Platform = getASTContext().getTargetInfo().getPlatformName(); + + auto Spec = std::find_if(AvailSpecs.begin(), AvailSpecs.end(), + [&](const AvailabilitySpec &Spec) { + return Spec.getPlatform() == Platform; + }); + + 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/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp index 38fbea18d790..2cd00f8218a6 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp @@ -113,7 +113,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, bool LookInScope = false; if (SS.isInvalid()) - return ParsedType(); + return nullptr; // If we have an object type, it's because we are in a // pseudo-destructor-expression or a member access expression, and @@ -198,7 +198,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, // FIXME: Should we be suppressing ambiguities here? if (Found.isAmbiguous()) - return ParsedType(); + return nullptr; if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) { QualType T = Context.getTypeDeclType(Type); @@ -320,12 +320,12 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc, } } - return ParsedType(); + return nullptr; } ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType) - return ParsedType(); + return nullptr; assert(DS.getTypeSpecType() == DeclSpec::TST_decltype && "only get destructor types from declspecs"); QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc()); @@ -336,7 +336,7 @@ ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) { Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch) << T << SearchType; - return ParsedType(); + return nullptr; } bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS, @@ -508,23 +508,60 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc, return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc); } +/// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to +/// a single GUID. +static void +getUuidAttrOfType(Sema &SemaRef, QualType QT, + llvm::SmallSetVector<const UuidAttr *, 1> &UuidAttrs) { + // Optionally remove one level of pointer, reference or array indirection. + const Type *Ty = QT.getTypePtr(); + if (QT->isPointerType() || QT->isReferenceType()) + Ty = QT->getPointeeType().getTypePtr(); + else if (QT->isArrayType()) + Ty = Ty->getBaseElementTypeUnsafe(); + + const auto *RD = Ty->getAsCXXRecordDecl(); + if (!RD) + return; + + if (const auto *Uuid = RD->getMostRecentDecl()->getAttr<UuidAttr>()) { + UuidAttrs.insert(Uuid); + return; + } + + // __uuidof can grab UUIDs from template arguments. + if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) { + const TemplateArgumentList &TAL = CTSD->getTemplateArgs(); + for (const TemplateArgument &TA : TAL.asArray()) { + const UuidAttr *UuidForTA = nullptr; + if (TA.getKind() == TemplateArgument::Type) + getUuidAttrOfType(SemaRef, TA.getAsType(), UuidAttrs); + else if (TA.getKind() == TemplateArgument::Declaration) + getUuidAttrOfType(SemaRef, TA.getAsDecl()->getType(), UuidAttrs); + + if (UuidForTA) + UuidAttrs.insert(UuidForTA); + } + } +} + /// \brief Build a Microsoft __uuidof expression with a type operand. ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, TypeSourceInfo *Operand, SourceLocation RParenLoc) { + StringRef UuidStr; if (!Operand->getType()->isDependentType()) { - bool HasMultipleGUIDs = false; - if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType(), - &HasMultipleGUIDs)) { - if (HasMultipleGUIDs) - return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - else - return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); - } + llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; + getUuidAttrOfType(*this, Operand->getType(), UuidAttrs); + if (UuidAttrs.empty()) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + if (UuidAttrs.size() > 1) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); + UuidStr = UuidAttrs.back()->getGuid(); } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, + return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } @@ -533,18 +570,22 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType, SourceLocation TypeidLoc, Expr *E, SourceLocation RParenLoc) { + StringRef UuidStr; if (!E->getType()->isDependentType()) { - bool HasMultipleGUIDs = false; - if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType(), &HasMultipleGUIDs) && - !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { - if (HasMultipleGUIDs) - return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); - else + if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + UuidStr = "00000000-0000-0000-0000-000000000000"; + } else { + llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs; + getUuidAttrOfType(*this, E->getType(), UuidAttrs); + if (UuidAttrs.empty()) return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid)); + if (UuidAttrs.size() > 1) + return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids)); + UuidStr = UuidAttrs.back()->getGuid(); } } - return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, + return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr, SourceRange(TypeidLoc, RParenLoc)); } @@ -831,6 +872,92 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc, return false; } +static QualType adjustCVQualifiersForCXXThisWithinLambda( + ArrayRef<FunctionScopeInfo *> FunctionScopes, QualType ThisTy, + DeclContext *CurSemaContext, ASTContext &ASTCtx) { + + QualType ClassType = ThisTy->getPointeeType(); + LambdaScopeInfo *CurLSI = nullptr; + DeclContext *CurDC = CurSemaContext; + + // Iterate through the stack of lambdas starting from the innermost lambda to + // the outermost lambda, checking if '*this' is ever captured by copy - since + // that could change the cv-qualifiers of the '*this' object. + // The object referred to by '*this' starts out with the cv-qualifiers of its + // member function. We then start with the innermost lambda and iterate + // outward checking to see if any lambda performs a by-copy capture of '*this' + // - and if so, any nested lambda must respect the 'constness' of that + // capturing lamdbda's call operator. + // + + // The issue is that we cannot rely entirely on the FunctionScopeInfo stack + // since ScopeInfos are pushed on during parsing and treetransforming. But + // since a generic lambda's call operator can be instantiated anywhere (even + // end of the TU) we need to be able to examine its enclosing lambdas and so + // we use the DeclContext to get a hold of the closure-class and query it for + // capture information. The reason we don't just resort to always using the + // DeclContext chain is that it is only mature for lambda expressions + // enclosing generic lambda's call operators that are being instantiated. + + for (int I = FunctionScopes.size(); + I-- && isa<LambdaScopeInfo>(FunctionScopes[I]); + CurDC = getLambdaAwareParentOfDeclContext(CurDC)) { + CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]); + + if (!CurLSI->isCXXThisCaptured()) + continue; + + auto C = CurLSI->getCXXThisCapture(); + + if (C.isCopyCapture()) { + ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); + if (CurLSI->CallOperator->isConst()) + ClassType.addConst(); + return ASTCtx.getPointerType(ClassType); + } + } + // We've run out of ScopeInfos but check if CurDC is a lambda (which can + // happen during instantiation of generic lambdas) + if (isLambdaCallOperator(CurDC)) { + assert(CurLSI); + assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator)); + assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator)); + + auto IsThisCaptured = + [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) { + IsConst = false; + IsByCopy = false; + for (auto &&C : Closure->captures()) { + if (C.capturesThis()) { + if (C.getCaptureKind() == LCK_StarThis) + IsByCopy = true; + if (Closure->getLambdaCallOperator()->isConst()) + IsConst = true; + return true; + } + } + return false; + }; + + bool IsByCopyCapture = false; + bool IsConstCapture = false; + CXXRecordDecl *Closure = cast<CXXRecordDecl>(CurDC->getParent()); + while (Closure && + IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) { + if (IsByCopyCapture) { + ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask); + if (IsConstCapture) + ClassType.addConst(); + return ASTCtx.getPointerType(ClassType); + } + Closure = isLambdaCallOperator(Closure->getParent()) + ? cast<CXXRecordDecl>(Closure->getParent()->getParent()) + : nullptr; + } + } + return ASTCtx.getPointerType(ClassType); +} + QualType Sema::getCurrentThisType() { DeclContext *DC = getFunctionLevelDeclContext(); QualType ThisTy = CXXThisTypeOverride; @@ -845,13 +972,29 @@ QualType Sema::getCurrentThisType() { // within a default initializer - so use the enclosing class as 'this'. // There is no enclosing member function to retrieve the 'this' pointer // from. + + // FIXME: This looks wrong. If we're in a lambda within a lambda within a + // default member initializer, we need to recurse up more parents to find + // the right context. Looks like we should be walking up to the parent of + // the closure type, checking whether that is itself a lambda, and if so, + // recursing, until we reach a class or a function that isn't a lambda + // call operator. And we should accumulate the constness of *this on the + // way. + QualType ClassTy = Context.getTypeDeclType( cast<CXXRecordDecl>(CurContext->getParent()->getParent())); // There are no cv-qualifiers for 'this' within default initializers, // per [expr.prim.general]p4. - return Context.getPointerType(ClassTy); + ThisTy = Context.getPointerType(ClassTy); } } + + // If we are within a lambda's call operator, the cv-qualifiers of 'this' + // might need to be adjusted if the lambda or any of its enclosing lambda's + // captures '*this' by copy. + if (!ThisTy.isNull() && isLambdaCallOperator(CurContext)) + return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy, + CurContext, Context); return ThisTy; } @@ -870,6 +1013,8 @@ Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S, 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)); @@ -884,28 +1029,84 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() { } } -static Expr *captureThis(ASTContext &Context, RecordDecl *RD, - QualType ThisTy, SourceLocation Loc) { - FieldDecl *Field - = FieldDecl::Create(Context, RD, Loc, Loc, nullptr, ThisTy, - Context.getTrivialTypeSourceInfo(ThisTy, Loc), - nullptr, false, ICIS_NoInit); +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'). + QualType CaptureThisFieldTy = ThisTy; + if (ByCopy) { + // If we are capturing the object referred to by '*this' by copy, ignore any + // cv qualifiers inherited from the type of the member function for the type + // of the closure-type's corresponding data member and any use of 'this'. + CaptureThisFieldTy = ThisTy->getPointeeType(); + CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask); + AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy); + } + + FieldDecl *Field = FieldDecl::Create( + Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy, + Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false, + ICIS_NoInit); + Field->setImplicit(true); Field->setAccess(AS_private); RD->addDecl(Field); - return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true); + Expr *This = + new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/ true); + if (ByCopy) { + Expr *StarThis = S.CreateBuiltinUnaryOp(Loc, + UO_Deref, + This).get(); + InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture( + nullptr, CaptureThisFieldTy, Loc); + InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc); + InitializationSequence Init(S, Entity, InitKind, StarThis); + ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis); + if (ER.isInvalid()) return nullptr; + return ER.get(); + } + return This; } -bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit, - bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) { +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; - // Otherwise, check that we can capture 'this'. - unsigned NumClosures = 0; + *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. + + // 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. + + // For a closure 'L' (at MaxFunctionScopesIndex in the FunctionScopes + // 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 + // -- 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' + // and 'L' can implicitly capture the *enclosing object*. + // -- or, every enclosing closure can implicitly capture the + // *enclosing object* + + + unsigned NumCapturingClosures = 0; for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) { if (CapturingScopeInfo *CSI = dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) { @@ -917,44 +1118,69 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit, if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) { // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) - Diag(Loc, diag::err_this_capture) << Explicit; + Diag(Loc, diag::err_this_capture) + << (Explicit && idx == MaxFunctionScopesIndex); return true; } if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block || CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion || - Explicit) { + (Explicit && idx == MaxFunctionScopesIndex)) { + // Regarding (Explicit && idx == MaxFunctionScopesIndex): only the first + // iteration through can be an explicit capture, all enclosing closures, + // if any, must perform implicit captures. + // This closure can capture 'this'; continue looking upwards. - NumClosures++; - Explicit = false; + NumCapturingClosures++; continue; } // This context can't implicitly capture 'this'; fail out. if (BuildAndDiagnose) - Diag(Loc, diag::err_this_capture) << Explicit; + Diag(Loc, diag::err_this_capture) + << (Explicit && idx == MaxFunctionScopesIndex); return true; } break; } if (!BuildAndDiagnose) return false; - // Mark that we're implicitly capturing 'this' in all the scopes we skipped. + + // If we got here, then the closure at MaxFunctionScopesIndex on the + // FunctionScopes stack, can capture the *enclosing object*, so capture it + // (including implicit by-reference captures in any enclosing closures). + + // 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 + // implicitly capturing the *enclosing object* by reference (see loop + // above)). + assert((!ByCopy || + dyn_cast<LambdaScopeInfo>(FunctionScopes[MaxFunctionScopesIndex])) && + "Only a lambda can capture the enclosing object (referred to by " + "*this) by copy"); // FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated // contexts. - for (unsigned idx = MaxFunctionScopesIndex; NumClosures; - --idx, --NumClosures) { + QualType ThisTy = getCurrentThisType(); + for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures; + --idx, --NumCapturingClosures) { CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]); Expr *ThisExpr = nullptr; - QualType ThisTy = getCurrentThisType(); - if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) - // For lambda expressions, build a field and an initializing expression. - ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc); - else if (CapturedRegionScopeInfo *RSI + + 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 = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc); + ThisExpr = + captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc, + false/*ByCopy*/); - bool isNested = NumClosures > 1; - CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr); + bool isNested = NumCapturingClosures > 1; + CSI->addThisCapture(isNested, Loc, ThisExpr, ByCopy); } return false; } @@ -996,7 +1222,14 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep, if (!TInfo) TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation()); - return BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc); + 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 + // checking for embedded typos. + if (!Result.isInvalid() && Result.get()->isInstantiationDependent() && + !Result.get()->isTypeDependent()) + Result = CorrectDelayedTyposInExpr(Result.get()); + return Result; } /// ActOnCXXTypeConstructExpr - Parse construction of a specified type. @@ -1551,7 +1784,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal, // new. if (PlacementArgs.empty() && OperatorNew && (OperatorNew->isImplicit() || - getSourceManager().isInSystemHeader(OperatorNew->getLocStart()))) { + (OperatorNew->getLocStart().isValid() && + getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) { if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){ unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign(); if (Align > SuitableAlign) @@ -2113,14 +2347,13 @@ void Sema::DeclareGlobalNewDelete() { QualType VoidPtr = Context.getPointerType(Context.VoidTy); QualType SizeT = Context.getSizeType(); - bool AssumeSaneOperatorNew = getLangOpts().AssumeSaneOperatorNew; DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_New), - VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew); + VoidPtr, SizeT, QualType()); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Array_New), - VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew); + VoidPtr, SizeT, QualType()); DeclareGlobalAllocationFunction( Context.DeclarationNames.getCXXOperatorName(OO_Delete), Context.VoidTy, VoidPtr); @@ -2141,8 +2374,7 @@ void Sema::DeclareGlobalNewDelete() { /// allocation function if it doesn't already exist. void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, QualType Return, - QualType Param1, QualType Param2, - bool AddRestrictAttr) { + QualType Param1, QualType Param2) { DeclContext *GlobalCtx = Context.getTranslationUnitDecl(); unsigned NumParams = Param2.isNull() ? 1 : 2; @@ -2165,9 +2397,6 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, // FIXME: Do we need to check for default arguments here? if (InitialParam1Type == Param1 && (NumParams == 1 || InitialParam2Type == Param2)) { - if (AddRestrictAttr && !Func->hasAttr<RestrictAttr>()) - Func->addAttr(RestrictAttr::CreateImplicit( - Context, RestrictAttr::GNU_malloc)); // 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. @@ -2210,10 +2439,6 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name, Alloc->addAttr(VisibilityAttr::CreateImplicit(Context, VisibilityAttr::Default)); - if (AddRestrictAttr) - Alloc->addAttr( - RestrictAttr::CreateImplicit(Context, RestrictAttr::GNU_malloc)); - ParmVarDecl *ParamDecls[2]; for (unsigned I = 0; I != NumParams; ++I) { ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(), @@ -2265,7 +2490,7 @@ FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc, "found an unexpected usual deallocation function"); } - if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) + if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); assert(Matches.size() == 1 && @@ -2299,7 +2524,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD, Matches.push_back(F.getPair()); } - if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) + if (getLangOpts().CUDA) EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches); // There's exactly one suitable operator; pick it. @@ -2765,30 +2990,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return ExprError(); } - // C++ [expr.delete]p3: - // In the first alternative (delete object), if the static type of the - // object to be deleted is different from its dynamic type, the static - // type shall be a base class of the dynamic type of the object to be - // deleted and the static type shall have a virtual destructor or the - // behavior is undefined. - // - // Note: a final class cannot be derived from, no issue there - if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) { - CXXDestructorDecl *dtor = PointeeRD->getDestructor(); - if (dtor && !dtor->isVirtual()) { - if (PointeeRD->isAbstract()) { - // If the class is abstract, we warn by default, because we're - // sure the code has undefined behavior. - Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor) - << PointeeElem; - } else if (!ArrayForm) { - // Otherwise, if this is not an array delete, it's a bit suspect, - // but not necessarily wrong. - Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem; - } - } - } - + CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc, + /*IsDelete=*/true, /*CallCanBeVirtual=*/true, + /*WarnOnNonAbstractTypes=*/!ArrayForm, + SourceLocation()); } if (!OperatorDelete) @@ -2817,11 +3022,61 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal, return Result; } +void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc, + bool IsDelete, bool CallCanBeVirtual, + bool WarnOnNonAbstractTypes, + SourceLocation DtorLoc) { + if (!dtor || dtor->isVirtual() || !CallCanBeVirtual) + return; + + // C++ [expr.delete]p3: + // In the first alternative (delete object), if the static type of the + // object to be deleted is different from its dynamic type, the static + // type shall be a base class of the dynamic type of the object to be + // deleted and the static type shall have a virtual destructor or the + // behavior is undefined. + // + const CXXRecordDecl *PointeeRD = dtor->getParent(); + // Note: a final class cannot be derived from, no issue there + if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>()) + return; + + QualType ClassType = dtor->getThisType(Context)->getPointeeType(); + if (PointeeRD->isAbstract()) { + // If the class is abstract, we warn by default, because we're + // sure the code has undefined behavior. + Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1) + << ClassType; + } else if (WarnOnNonAbstractTypes) { + // Otherwise, if this is not an array delete, it's a bit suspect, + // but not necessarily wrong. + Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1) + << ClassType; + } + if (!IsDelete) { + std::string TypeStr; + ClassType.getAsStringInternal(TypeStr, getPrintingPolicy()); + Diag(DtorLoc, diag::note_delete_non_virtual) + << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::"); + } +} + +Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar, + SourceLocation StmtLoc, + ConditionKind CK) { + ExprResult E = + CheckConditionVariable(cast<VarDecl>(ConditionVar), StmtLoc, CK); + if (E.isInvalid()) + return ConditionError(); + return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc), + CK == ConditionKind::ConstexprIf); +} + /// \brief Check the use of the given variable as a C++ condition in an if, /// while, do-while, or switch statement. ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, SourceLocation StmtLoc, - bool ConvertToBoolean) { + ConditionKind CK) { if (ConditionVar->isInvalidDecl()) return ExprError(); @@ -2845,17 +3100,22 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar, MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get())); - if (ConvertToBoolean) { - Condition = CheckBooleanCondition(Condition.get(), StmtLoc); - if (Condition.isInvalid()) - return ExprError(); + switch (CK) { + case ConditionKind::Boolean: + return CheckBooleanCondition(StmtLoc, Condition.get()); + + case ConditionKind::ConstexprIf: + return CheckBooleanCondition(StmtLoc, Condition.get(), true); + + case ConditionKind::Switch: + return CheckSwitchCondition(StmtLoc, Condition.get()); } - return Condition; + llvm_unreachable("unexpected condition kind"); } /// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid. -ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) { +ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) { // C++ 6.4p4: // The value of a condition that is an initialized declaration in a statement // other than a switch statement is the value of the declared variable @@ -2864,7 +3124,12 @@ ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) { // The value of a condition that is an expression is the value of the // expression, implicitly converted to bool. // - return PerformContextuallyConvertToBool(CondExpr); + // FIXME: Return this value to the caller so they don't need to recompute it. + llvm::APSInt Value(/*BitWidth*/1); + return (IsConstexpr && !CondExpr->isValueDependent()) + ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value, + CCEK_ConstexprIf) + : PerformContextuallyConvertToBool(CondExpr); } /// Helper function to determine whether this is the (deprecated) C++ @@ -2898,7 +3163,8 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) { return (ToPointeeType->getKind() == BuiltinType::Char_U || ToPointeeType->getKind() == BuiltinType::Char_S); case StringLiteral::Wide: - return ToPointeeType->isWideCharType(); + return Context.typesAreCompatible(Context.getWideCharType(), + QualType(ToPointeeType, 0)); } } } @@ -2927,14 +3193,13 @@ static ExprResult BuildCXXCastArgument(Sema &S, if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs)) return ExprError(); - S.CheckConstructorAccess(CastLoc, Constructor, - InitializedEntity::InitializeTemporary(Ty), - Constructor->getAccess()); + S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl, + InitializedEntity::InitializeTemporary(Ty)); if (S.DiagnoseUseOfDecl(Method, CastLoc)) return ExprError(); ExprResult Result = S.BuildCXXConstructExpr( - CastLoc, Ty, cast<CXXConstructorDecl>(Method), + CastLoc, Ty, FoundDecl, cast<CXXConstructorDecl>(Method), ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -3085,13 +3350,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType, ConstructorArgs)) return ExprError(); return BuildCXXConstructExpr( - /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor, + /*FIXME:ConstructLoc*/ SourceLocation(), ToType, + SCS.FoundCopyConstructor, SCS.CopyConstructor, ConstructorArgs, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); } return BuildCXXConstructExpr( - /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor, + /*FIXME:ConstructLoc*/ SourceLocation(), ToType, + SCS.FoundCopyConstructor, SCS.CopyConstructor, From, /*HadMultipleCandidates*/ false, /*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false, CXXConstructExpr::CK_Complete, SourceRange()); @@ -4314,6 +4581,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, return !Result.isInvalid() && !SFINAE.hasErrorOccurred(); } + case BTT_IsAssignable: case BTT_IsNothrowAssignable: case BTT_IsTriviallyAssignable: { // C++11 [meta.unary.prop]p3: @@ -4361,6 +4629,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT, if (Result.isInvalid() || SFINAE.hasErrorOccurred()) return false; + if (BTT == BTT_IsAssignable) + return true; + if (BTT == BTT_IsNothrowAssignable) return Self.canThrow(Result.get()) == CT_Cannot; @@ -4652,7 +4923,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS, return Result; } -/// \brief Try to convert a type to another according to C++0x 5.16p3. +/// \brief Try to convert a type to another according to C++11 5.16p3. /// /// This is part of the parameter validation for the ? operator. If either /// value operand is a class type, the two operands are attempted to be @@ -4668,17 +4939,21 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To, InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(), SourceLocation()); - // C++0x 5.16p3 + // C++11 5.16p3 // The process for determining whether an operand expression E1 of type T1 // can be converted to match an operand expression E2 of type T2 is defined // as follows: - // -- If E2 is an lvalue: - bool ToIsLvalue = To->isLValue(); - if (ToIsLvalue) { - // E1 can be converted to match E2 if E1 can be implicitly converted to - // type "lvalue reference to T2", subject to the constraint that in the - // conversion the reference must bind directly to E1. - QualType T = Self.Context.getLValueReferenceType(ToType); + // -- If E2 is an lvalue: E1 can be converted to match E2 if E1 can be + // implicitly converted to type "lvalue reference to T2", subject to the + // constraint that in the conversion the reference must bind directly to + // an lvalue. + // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be + // implicitly conveted to the type "rvalue reference to R2", subject to + // the constraint that the reference must bind directly. + if (To->isLValue() || To->isXValue()) { + QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType) + : Self.Context.getRValueReferenceType(ToType); + InitializedEntity Entity = InitializedEntity::InitializeTemporary(T); InitializationSequence InitSeq(Self, Entity, Kind, From); @@ -5029,6 +5304,12 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, QualType ResTy = UsualArithmeticConversions(LHS, RHS); if (LHS.isInvalid() || RHS.isInvalid()) return QualType(); + if (ResTy.isNull()) { + Diag(QuestionLoc, + diag::err_typecheck_cond_incompatible_operands) << LTy << RTy + << LHS.get()->getSourceRange() << RHS.get()->getSourceRange(); + return QualType(); + } LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy)); RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy)); @@ -5390,7 +5671,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType()) return E; - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject : CK_ARCReclaimReturnedObject); @@ -5443,7 +5724,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) { return E; // We need a cleanup, but we don't need to remember the temporary. - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); } CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor); @@ -5470,14 +5751,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) { unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects; assert(ExprCleanupObjects.size() >= FirstCleanup); - assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup); - if (!ExprNeedsCleanups) + assert(Cleanup.exprNeedsCleanups() || + ExprCleanupObjects.size() == FirstCleanup); + if (!Cleanup.exprNeedsCleanups()) return SubExpr; auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup, ExprCleanupObjects.size() - FirstCleanup); - Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups); + auto *E = ExprWithCleanups::Create( + Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups); DiscardCleanupsInEvaluationContext(); return E; @@ -5488,7 +5771,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) { CleanupVarDeclMarking(); - if (!ExprNeedsCleanups) + if (!Cleanup.exprNeedsCleanups()) return SubStmt; // FIXME: In order to attach the temporaries, wrap the statement into @@ -5594,7 +5877,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) { return ExprError(); // We need a cleanup, but we don't need to remember the temporary. - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); } // Possibly strip off the top CXXBindTemporaryExpr. @@ -5746,7 +6029,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base, MayBePseudoDestructor = true; return Base; } else if (!BaseType->isRecordType()) { - ObjectType = ParsedType(); + ObjectType = nullptr; MayBePseudoDestructor = true; return Base; } @@ -5789,7 +6072,7 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base, if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) { ObjectType = Ptr->getPointeeType(); } else if (!Base->isTypeDependent()) { - // The user wrote "p->" when she probably meant "p."; fix it. + // The user wrote "p->" when they probably meant "p."; fix it. S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion) << ObjectType << true << FixItHint::CreateReplacement(OpLoc, "."); @@ -6082,9 +6365,12 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl, // follows the normal lifetime rules for block literals instead of being // autoreleased. DiagnosticErrorTrap Trap(Diags); + PushExpressionEvaluationContext(PotentiallyEvaluated); ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(), E->getExprLoc(), Method, E); + PopExpressionEvaluationContext(); + if (Exp.isInvalid()) Diag(E->getExprLoc(), diag::note_lambda_to_block_conv); return Exp; @@ -6390,7 +6676,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( static ExprResult attemptRecovery(Sema &SemaRef, const TypoCorrectionConsumer &Consumer, - TypoCorrection TC) { + const TypoCorrection &TC) { LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(), Consumer.getLookupResult().getLookupKind()); const CXXScopeSpec *SS = Consumer.getSS(); @@ -6567,6 +6853,14 @@ public: ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); } + ExprResult TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) { + return Owned(E); + } + + ExprResult TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) { + return Owned(E); + } + ExprResult Transform(Expr *E) { ExprResult Res; while (true) { diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index 9c345f8a69a3..283621889f80 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp @@ -142,6 +142,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef, AbstractInstanceResult = IMA_Abstract; break; + case Sema::DiscardedStatement: case Sema::ConstantEvaluated: case Sema::PotentiallyEvaluated: case Sema::PotentiallyEvaluatedIfUsed: @@ -380,7 +381,8 @@ static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDe const Selector &Sel, ASTContext &Context) { if (Member) - if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member)) + if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) return PD; if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel)) return OMD; @@ -401,7 +403,8 @@ static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy, Decl *GDecl = nullptr; for (const auto *I : QIdTy->quals()) { if (Member) - if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) { + if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { GDecl = PD; break; } @@ -900,6 +903,32 @@ static bool IsInFnTryBlockHandler(const Scope *S) { return false; } +static VarDecl * +getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl, + const TemplateArgumentListInfo *TemplateArgs, + const DeclarationNameInfo &MemberNameInfo, + SourceLocation TemplateKWLoc) { + + if (!TemplateArgs) { + S.Diag(MemberNameInfo.getBeginLoc(), diag::err_template_decl_ref) + << /*Variable template*/ 1 << MemberNameInfo.getName() + << MemberNameInfo.getSourceRange(); + + S.Diag(VarTempl->getLocation(), diag::note_template_decl_here); + + return nullptr; + } + DeclResult VDecl = S.CheckVarTemplateId( + VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs); + if (VDecl.isInvalid()) + return nullptr; + VarDecl *Var = cast<VarDecl>(VDecl.get()); + if (!Var->getTemplateSpecializationKind()) + Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation, + MemberNameInfo.getLoc()); + return Var; +} + ExprResult Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, SourceLocation OpLoc, bool IsArrow, @@ -1067,9 +1096,23 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, // Handle the implicit-member-access case. if (!BaseExpr) { // If this is not an instance member, convert to a non-member access. - if (!MemberDecl->isCXXInstanceMember()) - return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl); - + if (!MemberDecl->isCXXInstanceMember()) { + // If this is a variable template, get the instantiated variable + // declaration corresponding to the supplied template arguments + // (while emitting diagnostics as necessary) that will be referenced + // by this expression. + assert((!TemplateArgs || isa<VarTemplateDecl>(MemberDecl)) && + "How did we get template arguments here sans a variable template"); + if (isa<VarTemplateDecl>(MemberDecl)) { + MemberDecl = getVarTemplateSpecialization( + *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs, + R.getLookupNameInfo(), TemplateKWLoc); + if (!MemberDecl) + return ExprError(); + } + return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl, + FoundDecl, TemplateArgs); + } SourceLocation Loc = R.getNameLoc(); if (SS.getRange().isValid()) Loc = SS.getRange().getBegin(); @@ -1125,6 +1168,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType, TemplateKWLoc, Enum, FoundDecl, MemberNameInfo, Enum->getType(), VK_RValue, OK_Ordinary); } + if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) { + if (VarDecl *Var = getVarTemplateSpecialization( + *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc)) + return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS, + TemplateKWLoc, Var, FoundDecl, MemberNameInfo, + Var->getType().getNonReferenceType(), VK_LValue, + OK_Ordinary); + return ExprError(); + } // We found something that we didn't expect. Complain. if (isa<TypeDecl>(MemberDecl)) @@ -1324,7 +1376,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, D = CAT->getClassInterface(); ClassDeclared = cast<ObjCInterfaceDecl>(D); } else { - if (IsArrow && IDecl->FindPropertyDeclaration(Member)) { + if (IsArrow && + IDecl->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { S.Diag(MemberLoc, diag::err_property_found_suggest) << Member << BaseExpr.get()->getType() << FixItHint::CreateReplacement(OpLoc, "."); @@ -1731,9 +1785,20 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow, FoundDecl, Field); if (Base.isInvalid()) return ExprError(); - return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS, - /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl, - MemberNameInfo, MemberType, VK, OK); + MemberExpr *ME = + BuildMemberExpr(S, S.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() && + isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) { + if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field)) + return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc); + } + return ME; } /// Builds an implicit member access expression. The current context diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp index c1fb906a5b19..8f0d4ff69576 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp @@ -1035,7 +1035,6 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR, HasPackExpansions = true; } - QualType Ty = Context.getObjCObjectPointerType( @@ -1778,7 +1777,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, MemberName, BaseRange)) return ExprError(); - if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) { + if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -1793,7 +1793,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, } // Check protocols on qualified interfaces. for (const auto *I : OPT->quals()) - if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) { + if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { // Check whether we can reference this property. if (DiagnoseUseOfDecl(PD, MemberLoc)) return ExprError(); @@ -1816,7 +1817,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, Selector Sel = PP.getSelectorTable().getNullarySelector(Member); ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Getter) Getter = LookupMethodInQualifiedType(Sel, OPT, true); @@ -1836,7 +1837,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, PP.getSelectorTable(), Member); ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel); - // May be founf in property's qualified list. + // May be found in property's qualified list. if (!Setter) Setter = LookupMethodInQualifiedType(SetterSel, OPT, true); @@ -1852,8 +1853,9 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, // Special warning if member name used in a property-dot for a setter accessor // does not use a property with same name; e.g. obj.X = ... for a property with // name 'x'. - if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() - && !IFace->FindPropertyDeclaration(Member)) { + if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() && + !IFace->FindPropertyDeclaration( + Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) { // Do not warn if user is using property-dot syntax to make call to // user named setter. @@ -1883,12 +1885,29 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, LookupOrdinaryName, nullptr, nullptr, llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(), CTK_ErrorRecovery, IFace, false, OPT)) { - diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) - << MemberName << QualType(OPT, 0)); DeclarationName TypoResult = Corrected.getCorrection(); - return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, - TypoResult, MemberLoc, - SuperLoc, SuperType, Super); + if (TypoResult.isIdentifier() && + TypoResult.getAsIdentifierInfo() == Member) { + // There is no need to try the correction if it is the same. + NamedDecl *ChosenDecl = + Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl(); + if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl)) + if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) { + // This is a class property, we should not use the instance to + // access it. + Diag(MemberLoc, diag::err_class_property_found) << MemberName + << OPT->getInterfaceDecl()->getName() + << FixItHint::CreateReplacement(BaseExpr->getSourceRange(), + OPT->getInterfaceDecl()->getName()); + return ExprError(); + } + } else { + diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest) + << MemberName << QualType(OPT, 0)); + return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc, + TypoResult, MemberLoc, + SuperLoc, SuperType, Super); + } } ObjCInterfaceDecl *ClassDeclared; if (ObjCIvarDecl *Ivar = @@ -1916,8 +1935,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT, return ExprError(); } - - ExprResult Sema:: ActOnClassPropertyRefExpr(IdentifierInfo &receiverName, IdentifierInfo &propertyName, @@ -2032,7 +2049,7 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback { } }; -} +} // end anonymous namespace Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, IdentifierInfo *Name, @@ -2040,7 +2057,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S, bool IsSuper, bool HasTrailingDot, ParsedType &ReceiverType) { - ReceiverType = ParsedType(); + ReceiverType = nullptr; // If the identifier is "super" and there is no trailing dot, we're // messaging super. If the identifier is "super" and there is a @@ -2183,7 +2200,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S, LBracLoc, SelectorLocs, RBracLoc, Args); } - ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, bool isSuperReceiver, SourceLocation Loc, @@ -2198,7 +2214,6 @@ ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType, /*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(), Sel, Method, Loc, Loc, Loc, Args, /*isImplicit=*/true); - } static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg, @@ -2465,7 +2480,6 @@ ExprResult Sema::ActOnClassMessage(Scope *S, if (ReceiverType.isNull()) return ExprError(); - if (!ReceiverTypeInfo) ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc); @@ -2621,29 +2635,28 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { // Handle messages to id and __kindof types (where we use the // global method pool). - // FIXME: The type bound is currently ignored by lookup in the - // global pool. const ObjCObjectType *typeBound = nullptr; bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context, typeBound); if (receiverIsIdLike || ReceiverType->isBlockPointerType() || (Receiver && Context.isObjCNSObjectType(Receiver->getType()))) { - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc), - receiverIsIdLike); - if (!Method) - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc,RBracLoc), - receiverIsIdLike); - if (Method) { + SmallVector<ObjCMethodDecl*, 4> Methods; + // If we have a type bound, further filter the methods. + CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/, + true/*CheckTheOther*/, typeBound); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try to + // select a better one. + Method = Methods[0]; + if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods)) Method = BestMethod; + if (!AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - receiverIsIdLike)) { - DiagnoseUseOfDecl(Method, SelLoc); - } + receiverIsIdLike, Methods)) + DiagnoseUseOfDecl(Method, SelLoc); } } else if (ReceiverType->isObjCClassOrClassKindOfType() || ReceiverType->isObjCQualifiedClassType()) { @@ -2681,25 +2694,32 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, if (!Method) { // If not messaging 'self', look for any factory method named 'Sel'. if (!Receiver || !isSelfExpr(Receiver)) { - Method = LookupFactoryMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (!Method) { - // If no class (factory) method was found, check if an _instance_ - // method of the same name exists in the root class only. - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method) - if (const ObjCInterfaceDecl *ID = - dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { - if (ID->getSuperClass()) - Diag(SelLoc, diag::warn_root_inst_method_not_found) - << Sel << SourceRange(LBracLoc, RBracLoc); - } + // If no class (factory) method was found, check if an _instance_ + // method of the same name exists in the root class only. + SmallVector<ObjCMethodDecl*, 4> Methods; + CollectMultipleMethodsInGlobalPool(Sel, Methods, + false/*InstanceFirst*/, + true/*CheckTheOther*/); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try + // to select a better one. + Method = Methods[0]; + + // If we find an instance method, emit waring. + if (Method->isInstanceMethod()) { + if (const ObjCInterfaceDecl *ID = + dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) { + if (ID->getSuperClass()) + Diag(SelLoc, diag::warn_root_inst_method_not_found) + << Sel << SourceRange(LBracLoc, RBracLoc); + } + } + + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), + Methods)) + Method = BestMethod; } - if (Method) - if (ObjCMethodDecl *BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) - Method = BestMethod; } } } @@ -2764,15 +2784,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver, // behavior isn't very desirable, however we need it for GCC // compatibility. FIXME: should we deviate?? if (OCIType->qual_empty()) { - Method = LookupInstanceMethodInGlobalPool(Sel, - SourceRange(LBracLoc, RBracLoc)); - if (Method) { - if (auto BestMethod = - SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod())) + SmallVector<ObjCMethodDecl*, 4> Methods; + CollectMultipleMethodsInGlobalPool(Sel, Methods, + true/*InstanceFirst*/, + false/*CheckTheOther*/); + if (!Methods.empty()) { + // We chose the first method as the initial condidate, then try + // to select a better one. + Method = Methods[0]; + + if (ObjCMethodDecl *BestMethod = + SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), + Methods)) Method = BestMethod; + AreMultipleMethodsInGlobalPool(Sel, Method, SourceRange(LBracLoc, RBracLoc), - true); + true/*receiverIdOrClass*/, + Methods); } if (Method && !forwardClass) Diag(SelLoc, diag::warn_maynot_respond) @@ -3052,11 +3081,13 @@ enum ARCConversionTypeClass { /// struct A* ACTC_coreFoundation }; + static bool isAnyRetainable(ARCConversionTypeClass ACTC) { return (ACTC == ACTC_retainable || ACTC == ACTC_coreFoundation || ACTC == ACTC_voidPtr); } + static bool isAnyCLike(ARCConversionTypeClass ACTC) { return ACTC == ACTC_none || ACTC == ACTC_voidPtr || @@ -3328,7 +3359,7 @@ namespace { } } }; -} +} // end anonymous namespace bool Sema::isKnownName(StringRef name) { if (name.empty()) @@ -3475,6 +3506,8 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange, return; QualType castExprType = castExpr->getType(); + // Defer emitting a diagnostic for bridge-related casts; that will be + // handled by CheckObjCBridgeRelatedConversions. TypedefNameDecl *TDNDecl = nullptr; if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable && ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) || @@ -3780,7 +3813,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) { else if (PRE->isImplicitProperty()) { if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter()) SrcType = Getter->getReturnType(); - } } @@ -3790,7 +3822,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) { return; CheckObjCBridgeRelatedConversions(castExpr->getLocStart(), castType, SrcType, castExpr); - return; } bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr, @@ -3919,16 +3950,16 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, << FixItHint::CreateInsertion(SrcExprEndLoc, "]"); Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - QualType receiverType = Context.getObjCInterfaceType(RelatedClass); - // Argument. - Expr *args[] = { SrcExpr }; - ExprResult msg = BuildClassMessageImplicit(receiverType, false, + QualType receiverType = Context.getObjCInterfaceType(RelatedClass); + // Argument. + Expr *args[] = { SrcExpr }; + ExprResult msg = BuildClassMessageImplicit(receiverType, false, ClassMethod->getLocation(), ClassMethod->getSelector(), ClassMethod, MultiExprArg(args, 1)); - SrcExpr = msg.get(); + SrcExpr = msg.get(); + } return true; } } @@ -3962,14 +3993,14 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc, } Diag(RelatedClass->getLocStart(), diag::note_declared_at); Diag(TDNDecl->getLocStart(), diag::note_declared_at); - } - ExprResult msg = - BuildInstanceMessageImplicit(SrcExpr, SrcType, - InstanceMethod->getLocation(), - InstanceMethod->getSelector(), - InstanceMethod, None); - SrcExpr = msg.get(); + ExprResult msg = + BuildInstanceMessageImplicit(SrcExpr, SrcType, + InstanceMethod->getLocation(), + InstanceMethod->getSelector(), + InstanceMethod, None); + SrcExpr = msg.get(); + } return true; } } @@ -3993,9 +4024,9 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType); ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType); if (exprACTC == castACTC) { - // check for viablity and report error if casting an rvalue to a + // Check for viability and report error if casting an rvalue to a // life-time qualifier. - if (Diagnose && castACTC == ACTC_retainable && + if (castACTC == ACTC_retainable && (CCK == CCK_CStyleCast || CCK == CCK_OtherCast) && castType != castExprType) { const Type *DT = castType.getTypePtr(); @@ -4011,10 +4042,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, QDT = AT->desugar(); if (QDT != castType && QDT.getObjCLifetime() != Qualifiers::OCL_None) { - SourceLocation loc = - (castRange.isValid() ? castRange.getBegin() - : castExpr->getExprLoc()); - Diag(loc, diag::err_arc_nolifetime_behavior); + if (Diagnose) { + SourceLocation loc = (castRange.isValid() ? castRange.getBegin() + : castExpr->getExprLoc()); + Diag(loc, diag::err_arc_nolifetime_behavior); + } + return ACR_error; } } return ACR_okay; @@ -4051,7 +4084,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(), CK_ARCConsumeObject, castExpr, nullptr, VK_RValue); - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); return ACR_okay; } @@ -4062,24 +4095,26 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType, CCK != CCK_ImplicitConversion) return ACR_unbridged; - // Do not issue bridge cast" diagnostic when implicit casting a cstring - // to 'NSString *'. Let caller issue a normal mismatched diagnostic with - // suitable fix-it. + // Issue a diagnostic about a missing @-sign when implicit casting a cstring + // to 'NSString *', instead of falling through to report a "bridge cast" + // diagnostic. if (castACTC == ACTC_retainable && exprACTC == ACTC_none && ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose)) - return ACR_okay; + return ACR_error; // Do not issue "bridge cast" diagnostic when implicit casting // a retainable object to a CF type parameter belonging to an audited // CF API function. Let caller issue a normal type mismatched diagnostic // instead. - if (Diagnose && - (!DiagnoseCFAudited || exprACTC != ACTC_retainable || - castACTC != ACTC_coreFoundation)) - if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && - (Opc == BO_NE || Opc == BO_EQ))) + if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable || + castACTC != ACTC_coreFoundation) && + !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable && + (Opc == BO_NE || Opc == BO_EQ))) { + if (Diagnose) diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr, castExpr, exprACTC, CCK); + return ACR_error; + } return ACR_okay; } @@ -4292,7 +4327,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc, TSInfo, SubExpr); if (MustConsume) { - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result, nullptr, VK_RValue); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp index c3a89463dc69..060ee3eef212 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp @@ -26,6 +26,7 @@ #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" #include <map> + using namespace clang; //===----------------------------------------------------------------------===// @@ -204,6 +205,8 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, // Semantic checking for initializer lists. //===----------------------------------------------------------------------===// +namespace { + /// @brief Semantic checking for initializer lists. /// /// The InitListChecker class contains a set of routines that each @@ -231,11 +234,11 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT, /// point. CheckDesignatedInitializer() recursively steps into the /// designated subobject and manages backing out the recursion to /// initialize the subobjects after the one designated. -namespace { class InitListChecker { Sema &SemaRef; bool hadError; bool VerifyOnly; // no diagnostics, no structure building + bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode. llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic; InitListExpr *FullyStructuredList; @@ -280,6 +283,7 @@ class InitListChecker { unsigned &StructuredIndex); void CheckStructUnionTypes(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, + CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field, bool SubobjectIsDesignatorContext, unsigned &Index, InitListExpr *StructuredList, @@ -317,7 +321,8 @@ class InitListChecker { static ExprResult PerformEmptyInit(Sema &SemaRef, SourceLocation Loc, const InitializedEntity &Entity, - bool VerifyOnly); + bool VerifyOnly, + bool TreatUnavailableAsInvalid); // Explanation on the "FillWithNoInit" mode: // @@ -338,6 +343,10 @@ class InitListChecker { // in the InitListExpr, the "holes" in Case#1 are filled not with empty // initializers but with special "NoInitExpr" place holders, which tells the // CodeGen not to generate any initializers for these parts. + void FillInEmptyInitForBase(unsigned Init, const CXXBaseSpecifier &Base, + const InitializedEntity &ParentEntity, + InitListExpr *ILE, bool &RequiresSecondPass, + bool FillWithNoInit); void FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, bool &RequiresSecondPass, @@ -353,19 +362,22 @@ class InitListChecker { public: InitListChecker(Sema &S, const InitializedEntity &Entity, - InitListExpr *IL, QualType &T, bool VerifyOnly); + InitListExpr *IL, QualType &T, bool VerifyOnly, + bool TreatUnavailableAsInvalid); bool HadError() { return hadError; } // @brief Retrieves the fully-structured initializer list used for // semantic analysis and code generation. InitListExpr *getFullyStructuredList() const { return FullyStructuredList; } }; + } // end anonymous namespace ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, SourceLocation Loc, const InitializedEntity &Entity, - bool VerifyOnly) { + bool VerifyOnly, + bool TreatUnavailableAsInvalid) { InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc, true); MultiExprArg SubInit; @@ -419,8 +431,6 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, if (CtorDecl->getMinRequiredArguments() == 0 && CtorDecl->isExplicit() && R->getDeclName() && SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) { - - bool IsInStd = false; for (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext()); ND && !IsInStd; ND = dyn_cast<NamespaceDecl>(ND->getParent())) { @@ -437,7 +447,8 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef, InitSeq.InitializeFrom( SemaRef, Entity, InitializationKind::CreateValue(Loc, Loc, Loc, true), - MultiExprArg(), /*TopLevelOfInitList=*/false); + MultiExprArg(), /*TopLevelOfInitList=*/false, + TreatUnavailableAsInvalid); // Emit a warning for this. System header warnings aren't shown // by default, but people working on system headers should see it. if (!VerifyOnly) { @@ -474,10 +485,43 @@ void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity, SourceLocation Loc) { assert(VerifyOnly && "CheckEmptyInitializable is only inteded for verification mode."); - if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true).isInvalid()) + if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true, + TreatUnavailableAsInvalid).isInvalid()) hadError = true; } +void InitListChecker::FillInEmptyInitForBase( + unsigned Init, const CXXBaseSpecifier &Base, + const InitializedEntity &ParentEntity, InitListExpr *ILE, + bool &RequiresSecondPass, bool FillWithNoInit) { + assert(Init < ILE->getNumInits() && "should have been expanded"); + + InitializedEntity BaseEntity = InitializedEntity::InitializeBase( + SemaRef.Context, &Base, false, &ParentEntity); + + if (!ILE->getInit(Init)) { + ExprResult BaseInit = + FillWithNoInit ? new (SemaRef.Context) NoInitExpr(Base.getType()) + : PerformEmptyInit(SemaRef, ILE->getLocEnd(), BaseEntity, + /*VerifyOnly*/ false, + TreatUnavailableAsInvalid); + if (BaseInit.isInvalid()) { + hadError = true; + return; + } + + ILE->setInit(Init, BaseInit.getAs<Expr>()); + } else if (InitListExpr *InnerILE = + dyn_cast<InitListExpr>(ILE->getInit(Init))) { + FillInEmptyInitializations(BaseEntity, InnerILE, + RequiresSecondPass, FillWithNoInit); + } else if (DesignatedInitUpdateExpr *InnerDIUE = + dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) { + FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(), + RequiresSecondPass, /*FillWithNoInit =*/true); + } +} + void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, const InitializedEntity &ParentEntity, InitListExpr *ILE, @@ -535,7 +579,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field, } ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity, - /*VerifyOnly*/false); + /*VerifyOnly*/false, + TreatUnavailableAsInvalid); if (MemberInit.isInvalid()) { hadError = true; return; @@ -592,14 +637,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, // The fields beyond ILE->getNumInits() are default initialized, so in // order to leave them uninitialized, the ILE is expanded and the extra // fields are then filled with NoInitExpr. - unsigned NumFields = 0; - for (auto *Field : RDecl->fields()) - if (!Field->isUnnamedBitfield()) - ++NumFields; - if (ILE->getNumInits() < NumFields) - ILE->resizeInits(SemaRef.Context, NumFields); + unsigned NumElems = numStructUnionElements(ILE->getType()); + if (RDecl->hasFlexibleArrayMember()) + ++NumElems; + if (ILE->getNumInits() < NumElems) + ILE->resizeInits(SemaRef.Context, NumElems); unsigned Init = 0; + + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RDecl)) { + for (auto &Base : CXXRD->bases()) { + if (hadError) + return; + + FillInEmptyInitForBase(Init, Base, Entity, ILE, RequiresSecondPass, + FillWithNoInit); + ++Init; + } + } + for (auto *Field : RDecl->fields()) { if (Field->isUnnamedBitfield()) continue; @@ -661,7 +717,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, else { ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(), ElementEntity, - /*VerifyOnly*/false); + /*VerifyOnly*/false, + TreatUnavailableAsInvalid); if (ElementInit.isInvalid()) { hadError = true; return; @@ -707,11 +764,12 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity, } } - InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity, InitListExpr *IL, QualType &T, - bool VerifyOnly) - : SemaRef(S), VerifyOnly(VerifyOnly) { + bool VerifyOnly, + bool TreatUnavailableAsInvalid) + : SemaRef(S), VerifyOnly(VerifyOnly), + TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) { // FIXME: Check that IL isn't already the semantic form of some other // InitListExpr. If it is, we'd create a broken AST. @@ -744,6 +802,8 @@ int InitListChecker::numArrayElements(QualType DeclType) { int InitListChecker::numStructUnionElements(QualType DeclType) { RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); int InitializableMembers = 0; + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl)) + InitializableMembers += CXXRD->getNumBases(); for (const auto *Field : structDecl->fields()) if (!Field->isUnnamedBitfield()) ++InitializableMembers; @@ -888,7 +948,6 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity, } } - /// Check whether the initializer \p IList (that was written with explicit /// braces) can be used to initialize an object of type \p T. /// @@ -992,10 +1051,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity, assert(DeclType->isAggregateType() && "non-aggregate records should be handed in CheckSubElementType"); RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); - CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(), - SubobjectIsDesignatorContext, Index, - StructuredList, StructuredIndex, - TopLevelObject); + auto Bases = + CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), + CXXRecordDecl::base_class_iterator()); + if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD)) + Bases = CXXRD->bases(); + CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(), + SubobjectIsDesignatorContext, Index, StructuredList, + StructuredIndex, TopLevelObject); } else if (DeclType->isArrayType()) { llvm::APSInt Zero( SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()), @@ -1130,8 +1193,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity, // Fall through for subaggregate initialization. } else { - assert((ElemType->isRecordType() || ElemType->isVectorType()) && - "Unexpected type"); + assert((ElemType->isRecordType() || ElemType->isVectorType() || + ElemType->isClkEventT()) && "Unexpected type"); // C99 6.7.8p13: // @@ -1220,7 +1283,6 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity, } } - void InitListChecker::CheckScalarType(const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, unsigned &Index, @@ -1672,16 +1734,13 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity, return FlexArrayDiag != diag::ext_flexible_array_init; } -void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, - InitListExpr *IList, - QualType DeclType, - RecordDecl::field_iterator Field, - bool SubobjectIsDesignatorContext, - unsigned &Index, - InitListExpr *StructuredList, - unsigned &StructuredIndex, - bool TopLevelObject) { - RecordDecl* structDecl = DeclType->getAs<RecordType>()->getDecl(); +void InitListChecker::CheckStructUnionTypes( + const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType, + CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field, + bool SubobjectIsDesignatorContext, unsigned &Index, + InitListExpr *StructuredList, unsigned &StructuredIndex, + bool TopLevelObject) { + RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl(); // If the record is invalid, some of it's members are invalid. To avoid // confusion, we forgo checking the intializer for the entire record. @@ -1726,13 +1785,35 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, return; } + bool InitializedSomething = false; + + // If we have any base classes, they are initialized prior to the fields. + for (auto &Base : Bases) { + Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr; + SourceLocation InitLoc = Init ? Init->getLocStart() : IList->getLocEnd(); + + // Designated inits always initialize fields, so if we see one, all + // remaining base classes have no explicit initializer. + if (Init && isa<DesignatedInitExpr>(Init)) + Init = nullptr; + + InitializedEntity BaseEntity = InitializedEntity::InitializeBase( + SemaRef.Context, &Base, false, &Entity); + if (Init) { + CheckSubElementType(BaseEntity, IList, Base.getType(), Index, + StructuredList, StructuredIndex); + InitializedSomething = true; + } else if (VerifyOnly) { + CheckEmptyInitializable(BaseEntity, InitLoc); + } + } + // If structDecl is a forward declaration, this loop won't do // anything except look at designated initializers; That's okay, // because an error should get printed out elsewhere. It might be // worthwhile to skip over the rest of the initializer, though. RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl(); RecordDecl::field_iterator FieldEnd = RD->field_end(); - bool InitializedSomething = false; bool CheckForMissingFields = true; while (Index < IList->getNumInits()) { Expr *Init = IList->getInit(Index); @@ -1782,7 +1863,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity, // Make sure we can use this declaration. bool InvalidUse; if (VerifyOnly) - InvalidUse = !SemaRef.CanUseDecl(*Field); + InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid); else InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, IList->getInit(Index)->getLocStart()); @@ -1895,8 +1976,8 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef, SmallVector<Expr*, 4> IndexExprs(NumIndexExprs); for (unsigned I = 0; I < NumIndexExprs; ++I) IndexExprs[I] = DIE->getSubExpr(I + 1); - return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(), - DIE->size(), IndexExprs, + return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators(), + IndexExprs, DIE->getEqualOrColonLoc(), DIE->usesGNUSyntax(), DIE->getInit()); } @@ -1919,7 +2000,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback { RecordDecl *Record; }; -} +} // end anonymous namespace /// @brief Check the well-formedness of a C99 designated initializer. /// @@ -2146,8 +2227,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, for (auto *FI : RT->getDecl()->fields()) { if (FI->isUnnamedBitfield()) continue; - if (KnownField == FI) + if (declaresSameEntity(KnownField, FI)) { + KnownField = FI; break; + } ++FieldIndex; } @@ -2160,11 +2243,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, FieldIndex = 0; if (!VerifyOnly) { FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion(); - if (CurrentField && CurrentField != *Field) { + if (CurrentField && !declaresSameEntity(CurrentField, *Field)) { assert(StructuredList->getNumInits() == 1 && "A union should never have more than one initializer!"); - // we're about to throw away an initializer, emit warning + // We're about to throw away an initializer, emit warning. SemaRef.Diag(D->getFieldLoc(), diag::warn_initializer_overrides) << D->getSourceRange(); @@ -2186,7 +2269,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Make sure we can use this declaration. bool InvalidUse; if (VerifyOnly) - InvalidUse = !SemaRef.CanUseDecl(*Field); + InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid); else InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc()); if (InvalidUse) { @@ -2276,7 +2359,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1, FieldType, nullptr, nullptr, Index, StructuredList, newStructuredIndex, - true, false)) + FinishSubobjectInit, false)) return true; } @@ -2304,8 +2387,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, // Check the remaining fields within this class/struct/union subobject. bool prevHadError = hadError; - CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index, - StructuredList, FieldIndex); + auto NoBases = + CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(), + CXXRecordDecl::base_class_iterator()); + CheckStructUnionTypes(Entity, IList, CurrentObjectType, NoBases, Field, + false, Index, StructuredList, FieldIndex); return hadError && !prevHadError; } @@ -2467,11 +2553,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity, Index = OldIndex; ElementEntity.setElementIndex(ElementIndex); - if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1, - ElementType, nullptr, nullptr, Index, - StructuredList, ElementIndex, - (DesignatedStartIndex == DesignatedEndIndex), - false)) + if (CheckDesignatedInitializer( + ElementEntity, IList, DIE, DesigIdx + 1, ElementType, nullptr, + nullptr, Index, StructuredList, ElementIndex, + FinishSubobjectInit && (DesignatedStartIndex == DesignatedEndIndex), + false)) return true; // Move to the next index in the array that we'll be initializing. @@ -2751,7 +2837,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig, DesignatedInitExpr *DIE = DesignatedInitExpr::Create(Context, - Designators.data(), Designators.size(), + Designators, InitExpressions, Loc, GNUSyntax, Init.getAs<Expr>()); @@ -2787,10 +2873,11 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index, InitializedEntity InitializedEntity::InitializeBase(ASTContext &Context, const CXXBaseSpecifier *Base, - bool IsInheritedVirtualBase) { + bool IsInheritedVirtualBase, + const InitializedEntity *Parent) { InitializedEntity Result; Result.Kind = EK_Base; - Result.Parent = nullptr; + Result.Parent = Parent; Result.Base = reinterpret_cast<uintptr_t>(Base); if (IsInheritedVirtualBase) Result.Base |= 0x01; @@ -2928,7 +3015,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const { return Depth + 1; } -void InitializedEntity::dump() const { +LLVM_DUMP_METHOD void InitializedEntity::dump() const { dumpImpl(llvm::errs()); } @@ -3137,13 +3224,9 @@ void InitializationSequence::AddListInitializationStep(QualType T) { Steps.push_back(S); } -void -InitializationSequence -::AddConstructorInitializationStep(CXXConstructorDecl *Constructor, - AccessSpecifier Access, - QualType T, - bool HadMultipleCandidates, - bool FromInitList, bool AsInitList) { +void InitializationSequence::AddConstructorInitializationStep( + DeclAccessPair FoundDecl, CXXConstructorDecl *Constructor, QualType T, + bool HadMultipleCandidates, bool FromInitList, bool AsInitList) { Step S; S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall : SK_ConstructorInitializationFromList @@ -3151,7 +3234,7 @@ InitializationSequence S.Type = T; S.Function.HadMultipleCandidates = HadMultipleCandidates; S.Function.Function = Constructor; - S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access); + S.Function.FoundDecl = FoundDecl; Steps.push_back(S); } @@ -3313,7 +3396,8 @@ static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, - InitializationSequence &Sequence); + InitializationSequence &Sequence, + bool TreatUnavailableAsInvalid); /// \brief When initializing from init list via constructor, handle /// initialization of an object of type std::initializer_list<T>. @@ -3323,7 +3407,8 @@ static void TryListInitialization(Sema &S, static bool TryInitializerListConstruction(Sema &S, InitListExpr *List, QualType DestType, - InitializationSequence &Sequence) { + InitializationSequence &Sequence, + bool TreatUnavailableAsInvalid) { QualType E; if (!S.isStdInitializerList(DestType, &E)) return false; @@ -3342,7 +3427,8 @@ static bool TryInitializerListConstruction(Sema &S, InitializedEntity::InitializeTemporary(ArrayType); InitializationKind Kind = InitializationKind::CreateDirectList(List->getExprLoc()); - TryListInitialization(S, HiddenArray, Kind, List, Sequence); + TryListInitialization(S, HiddenArray, Kind, List, Sequence, + TreatUnavailableAsInvalid); if (Sequence) Sequence.AddStdInitializerListConstructionStep(DestType); return true; @@ -3359,18 +3445,13 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, CandidateSet.clear(); for (NamedDecl *D : Ctors) { - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - bool SuppressUserConversions = false; + auto Info = getConstructorInfo(D); + if (!Info.Constructor) + continue; - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = nullptr; - FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - else { - Constructor = cast<CXXConstructorDecl>(D); + bool SuppressUserConversions = false; + if (!Info.ConstructorTmpl) { // C++11 [over.best.ics]p4: // ... and the constructor or user-defined conversion function is a // candidate by @@ -3387,15 +3468,15 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // parameter of a constructor of X. if ((CopyInitializing || (IsListInit && Args.size() == 1 && isa<InitListExpr>(Args[0]))) && - Constructor->isCopyOrMoveConstructor()) + Info.Constructor->isCopyOrMoveConstructor()) SuppressUserConversions = true; } - if (!Constructor->isInvalidDecl() && - (AllowExplicit || !Constructor->isExplicit()) && - (!OnlyListConstructors || S.isInitListConstructor(Constructor))) { - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + 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 { @@ -3407,9 +3488,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc, // are also considered. bool AllowExplicitConv = AllowExplicit && !CopyInitializing && Args.size() == 1 && - Constructor->isCopyOrMoveConstructor(); - S.AddOverloadCandidate(Constructor, FoundDecl, Args, CandidateSet, - SuppressUserConversions, + Info.Constructor->isCopyOrMoveConstructor(); + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args, + CandidateSet, SuppressUserConversions, /*PartialOverloading=*/false, /*AllowExplicit=*/AllowExplicitConv); } @@ -3517,18 +3598,23 @@ static void TryConstructorInitialization(Sema &S, // If a program calls for the default initialization of an object // of a const-qualified type T, T shall be a class type with a // user-provided default constructor. + // C++ core issue 253 proposal: + // If the implicit default constructor initializes all subobjects, no + // initializer should be required. + // The 253 proposal is for example needed to process libstdc++ headers in 5.x. + CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function); if (Kind.getKind() == InitializationKind::IK_Default && - Entity.getType().isConstQualified() && - !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) { - if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) - Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); - return; + Entity.getType().isConstQualified()) { + if (!CtorDecl->getParent()->allowConstDefaultInit()) { + if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity)) + Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst); + return; + } } // C++11 [over.match.list]p1: // In copy-list-initialization, if an explicit constructor is chosen, the // initializer is ill-formed. - CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function); if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) { Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor); return; @@ -3538,7 +3624,7 @@ static void TryConstructorInitialization(Sema &S, // subsumed by the initialization. bool HadMultipleCandidates = (CandidateSet.size() > 1); Sequence.AddConstructorInitializationStep( - CtorDecl, Best->FoundDecl.getAccess(), DestType, HadMultipleCandidates, + Best->FoundDecl, CtorDecl, DestType, HadMultipleCandidates, IsListInit | IsInitListCopy, AsInitializerList); } @@ -3591,7 +3677,8 @@ static void TryReferenceListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, - InitializationSequence &Sequence) { + InitializationSequence &Sequence, + bool TreatUnavailableAsInvalid) { // First, catch C++03 where this isn't possible. if (!S.getLangOpts().CPlusPlus11) { Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList); @@ -3647,7 +3734,8 @@ static void TryReferenceListInitialization(Sema &S, // Not reference-related. Create a temporary and bind to that. InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1); - TryListInitialization(S, TempEntity, Kind, InitList, Sequence); + TryListInitialization(S, TempEntity, Kind, InitList, Sequence, + TreatUnavailableAsInvalid); if (Sequence) { if (DestType->isRValueReferenceType() || (T1Quals.hasConst() && !T1Quals.hasVolatile())) @@ -3663,7 +3751,8 @@ static void TryListInitialization(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, InitListExpr *InitList, - InitializationSequence &Sequence) { + InitializationSequence &Sequence, + bool TreatUnavailableAsInvalid) { QualType DestType = Entity.getType(); // C++ doesn't allow scalar initialization with more than one argument. @@ -3674,7 +3763,8 @@ static void TryListInitialization(Sema &S, return; } if (DestType->isReferenceType()) { - TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence); + TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence, + TreatUnavailableAsInvalid); return; } @@ -3718,7 +3808,8 @@ static void TryListInitialization(Sema &S, InitList->getRBraceLoc()) : Kind; Sequence.InitializeFrom(S, Entity, SubKind, SubInit, - /*TopLevelOfInitList*/ true); + /*TopLevelOfInitList*/ true, + TreatUnavailableAsInvalid); // TryStringLiteralInitialization() (in InitializeFrom()) will fail if // the element is not an appropriately-typed string literal, in which @@ -3750,7 +3841,8 @@ static void TryListInitialization(Sema &S, // - Otherwise, if T is a specialization of std::initializer_list<E>, // an initializer_list object constructed [...] - if (TryInitializerListConstruction(S, InitList, DestType, Sequence)) + if (TryInitializerListConstruction(S, InitList, DestType, Sequence, + TreatUnavailableAsInvalid)) return; // - Otherwise, if T is a class type, constructors are considered. @@ -3763,8 +3855,48 @@ static void TryListInitialization(Sema &S, } if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() && - InitList->getNumInits() == 1 && - InitList->getInit(0)->getType()->isRecordType()) { + InitList->getNumInits() == 1) { + Expr *E = InitList->getInit(0); + + // - Otherwise, if T is an enumeration with a fixed underlying type, + // the initializer-list has a single element v, and the initialization + // is direct-list-initialization, the object is initialized with the + // value T(v); if a narrowing conversion is required to convert v to + // the underlying type of T, the program is ill-formed. + auto *ET = DestType->getAs<EnumType>(); + if (S.getLangOpts().CPlusPlus1z && + Kind.getKind() == InitializationKind::IK_DirectList && + ET && ET->getDecl()->isFixed() && + !S.Context.hasSameUnqualifiedType(E->getType(), DestType) && + (E->getType()->isIntegralOrEnumerationType() || + E->getType()->isFloatingType())) { + // There are two ways that T(v) can work when T is an enumeration type. + // If there is either an implicit conversion sequence from v to T or + // a conversion function that can convert from v to T, then we use that. + // Otherwise, if v is of integral, enumeration, or floating-point type, + // it is converted to the enumeration type via its underlying type. + // There is no overlap possible between these two cases (except when the + // source value is already of the destination type), and the first + // case is handled by the general case for single-element lists below. + ImplicitConversionSequence ICS; + ICS.setStandard(); + ICS.Standard.setAsIdentityConversion(); + // If E is of a floating-point type, then the conversion is ill-formed + // due to narrowing, but go through the motions in order to produce the + // right diagnostic. + ICS.Standard.Second = E->getType()->isFloatingType() + ? ICK_Floating_Integral + : ICK_Integral_Conversion; + ICS.Standard.setFromType(E->getType()); + ICS.Standard.setToType(0, E->getType()); + ICS.Standard.setToType(1, DestType); + ICS.Standard.setToType(2, DestType); + Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2), + /*TopLevelOfInitList*/true); + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } + // - Otherwise, if the initializer list has a single element of type E // [...references are handled above...], the object or reference is // initialized from that element (by copy-initialization for @@ -3778,22 +3910,25 @@ static void TryListInitialization(Sema &S, // copy-initialization. This only matters if we might use an 'explicit' // conversion operator, so we only need to handle the cases where the source // is of record type. - InitializationKind SubKind = - Kind.getKind() == InitializationKind::IK_DirectList - ? InitializationKind::CreateDirect(Kind.getLocation(), - InitList->getLBraceLoc(), - InitList->getRBraceLoc()) - : Kind; - Expr *SubInit[1] = { InitList->getInit(0) }; - Sequence.InitializeFrom(S, Entity, SubKind, SubInit, - /*TopLevelOfInitList*/true); - if (Sequence) - Sequence.RewrapReferenceInitList(Entity.getType(), InitList); - return; + if (InitList->getInit(0)->getType()->isRecordType()) { + InitializationKind SubKind = + Kind.getKind() == InitializationKind::IK_DirectList + ? InitializationKind::CreateDirect(Kind.getLocation(), + InitList->getLBraceLoc(), + InitList->getRBraceLoc()) + : Kind; + Expr *SubInit[1] = { InitList->getInit(0) }; + Sequence.InitializeFrom(S, Entity, SubKind, SubInit, + /*TopLevelOfInitList*/true, + TreatUnavailableAsInvalid); + if (Sequence) + Sequence.RewrapReferenceInitList(Entity.getType(), InitList); + return; + } } InitListChecker CheckInitList(S, Entity, InitList, - DestType, /*VerifyOnly=*/true); + DestType, /*VerifyOnly=*/true, TreatUnavailableAsInvalid); if (CheckInitList.HadError()) { Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed); return; @@ -3847,26 +3982,19 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S, CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl()); for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) { - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = nullptr; - FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); + auto Info = getConstructorInfo(D); + if (!Info.Constructor) + continue; - if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + if (!Info.Constructor->isInvalidDecl() && + Info.Constructor->isConvertingConstructor(AllowExplicit)) { + if (Info.ConstructorTmpl) + S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, Initializer, CandidateSet, /*SuppressUserConversions=*/true); else - S.AddOverloadCandidate(Constructor, FoundDecl, + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Initializer, CandidateSet, /*SuppressUserConversions=*/true); } @@ -4068,7 +4196,6 @@ convertQualifiersAndValueKindIfNecessary(Sema &S, return Initializer->getValueKind(); } - /// \brief Reference initialization without resolving overloaded functions. static void TryReferenceInitializationCore(Sema &S, const InitializedEntity &Entity, @@ -4303,7 +4430,6 @@ static void TryReferenceInitializationCore(Sema &S, } Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true); - return; } /// \brief Attempt character array initialization from a string literal @@ -4472,27 +4598,19 @@ static void TryUserDefinedConversion(Sema &S, Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end(); Con != ConEnd; ++Con) { NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = nullptr; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); + auto Info = getConstructorInfo(D); + if (!Info.Constructor) + continue; - if (!Constructor->isInvalidDecl() && - Constructor->isConvertingConstructor(AllowExplicit)) { - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, + if (!Info.Constructor->isInvalidDecl() && + Info.Constructor->isConvertingConstructor(AllowExplicit)) { + if (Info.ConstructorTmpl) + S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, /*ExplicitArgs*/ nullptr, Initializer, CandidateSet, /*SuppressUserConversions=*/true); else - S.AddOverloadCandidate(Constructor, FoundDecl, + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Initializer, CandidateSet, /*SuppressUserConversions=*/true); } @@ -4689,8 +4807,8 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) { // If isWeakAccess to true, there will be an implicit // load which requires a cleanup. if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess) - S.ExprNeedsCleanups = true; - + S.Cleanup.setExprNeedsCleanups(true); + if (iik == IIK_okay) return; S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback) @@ -4800,9 +4918,11 @@ InitializationSequence::InitializationSequence(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, - bool TopLevelOfInitList) + bool TopLevelOfInitList, + bool TreatUnavailableAsInvalid) : FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) { - InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList); + InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList, + TreatUnavailableAsInvalid); } /// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the @@ -4820,7 +4940,8 @@ void InitializationSequence::InitializeFrom(Sema &S, const InitializedEntity &Entity, const InitializationKind &Kind, MultiExprArg Args, - bool TopLevelOfInitList) { + bool TopLevelOfInitList, + bool TreatUnavailableAsInvalid) { ASTContext &Context = S.Context; // Eliminate non-overload placeholder types in the arguments. We @@ -4874,7 +4995,8 @@ void InitializationSequence::InitializeFrom(Sema &S, // object is list-initialized (8.5.4). if (Kind.getKind() != InitializationKind::IK_Direct) { if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) { - TryListInitialization(S, Entity, Kind, InitList, *this); + TryListInitialization(S, Entity, Kind, InitList, *this, + TreatUnavailableAsInvalid); return; } } @@ -4958,7 +5080,7 @@ void InitializationSequence::InitializeFrom(Sema &S, Entity.getKind() == InitializedEntity::EK_Member && Initializer && isa<InitListExpr>(Initializer)) { TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer), - *this); + *this, TreatUnavailableAsInvalid); AddParenthesizedArrayInitStep(DestType); } else if (DestAT->getElementType()->isCharType()) SetFailed(FK_ArrayNeedsInitListOrStringLiteral); @@ -5232,38 +5354,33 @@ static void LookupCopyAndMoveConstructors(Sema &S, for (SmallVectorImpl<NamedDecl *>::iterator CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) { NamedDecl *D = *CI; - CXXConstructorDecl *Constructor = nullptr; + auto Info = getConstructorInfo(D); + if (!Info.Constructor) + continue; - if ((Constructor = dyn_cast<CXXConstructorDecl>(D))) { - // Handle copy/moveconstructors, only. - if (!Constructor || Constructor->isInvalidDecl() || - !Constructor->isCopyOrMoveConstructor() || - !Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) + if (!Info.ConstructorTmpl) { + // Handle copy/move constructors, only. + if (Info.Constructor->isInvalidDecl() || + !Info.Constructor->isCopyOrMoveConstructor() || + !Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) continue; - DeclAccessPair FoundDecl - = DeclAccessPair::make(Constructor, Constructor->getAccess()); - S.AddOverloadCandidate(Constructor, FoundDecl, + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, CurInitExpr, CandidateSet); continue; } // Handle constructor templates. - FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl->isInvalidDecl()) + if (Info.ConstructorTmpl->isInvalidDecl()) continue; - Constructor = cast<CXXConstructorDecl>( - ConstructorTmpl->getTemplatedDecl()); - if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) + if (!Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true)) continue; // FIXME: Do we need to limit this to copy-constructor-like // candidates? - DeclAccessPair FoundDecl - = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess()); - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, nullptr, - CurInitExpr, CandidateSet, true); + S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, + nullptr, CurInitExpr, CandidateSet, true); } } @@ -5402,8 +5519,8 @@ static ExprResult CopyObject(Sema &S, SmallVector<Expr*, 8> ConstructorArgs; CurInit.get(); // Ownership transferred into MultiExprArg, below. - S.CheckConstructorAccess(Loc, Constructor, Entity, - Best->FoundDecl.getAccess(), IsExtraneousCopy); + S.CheckConstructorAccess(Loc, Constructor, Best->FoundDecl, Entity, + IsExtraneousCopy); if (IsExtraneousCopy) { // If this is a totally extraneous copy for C++03 reference @@ -5438,7 +5555,8 @@ static ExprResult CopyObject(Sema &S, return ExprError(); // Actually perform the constructor call. - CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable, + CurInit = S.BuildCXXConstructExpr(Loc, T, Best->FoundDecl, Constructor, + Elidable, ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, @@ -5485,7 +5603,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S, switch (OR) { case OR_Success: S.CheckConstructorAccess(Loc, cast<CXXConstructorDecl>(Best->Function), - Entity, Best->FoundDecl.getAccess(), Diag); + Best->FoundDecl, Entity, Diag); // FIXME: Check default arguments as far as that's possible. break; @@ -5611,7 +5729,6 @@ PerformConstructorInitialization(Sema &S, if (isExplicitTemporary(Entity, Kind, NumArgs)) { // An explicitly-constructed temporary, e.g., X(1, 2). - S.MarkFunctionReferenced(Loc, Constructor); if (S.DiagnoseUseOfDecl(Constructor, Loc)) return ExprError(); @@ -5623,10 +5740,19 @@ PerformConstructorInitialization(Sema &S, ? SourceRange(LBraceLoc, RBraceLoc) : Kind.getParenRange(); + if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>( + Step.Function.FoundDecl.getDecl())) { + Constructor = S.findInheritingConstructor(Loc, Constructor, Shadow); + if (S.DiagnoseUseOfDecl(Constructor, Loc)) + return ExprError(); + } + S.MarkFunctionReferenced(Loc, Constructor); + CurInit = new (S.Context) CXXTemporaryObjectExpr( - S.Context, Constructor, TSInfo, ConstructorArgs, ParenOrBraceRange, - HadMultipleCandidates, IsListInitialization, - IsStdInitListInitialization, ConstructorInitRequiresZeroInit); + S.Context, Constructor, TSInfo, + ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates, + IsListInitialization, IsStdInitListInitialization, + ConstructorInitRequiresZeroInit); } else { CXXConstructExpr::ConstructionKind ConstructKind = CXXConstructExpr::CK_Complete; @@ -5651,6 +5777,7 @@ PerformConstructorInitialization(Sema &S, // unconditionally. if (Entity.allowsNRVO()) CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Step.Function.FoundDecl, Constructor, /*Elidable=*/true, ConstructorArgs, HadMultipleCandidates, @@ -5661,6 +5788,7 @@ PerformConstructorInitialization(Sema &S, ParenOrBraceRange); else CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(), + Step.Function.FoundDecl, Constructor, ConstructorArgs, HadMultipleCandidates, @@ -5674,8 +5802,7 @@ PerformConstructorInitialization(Sema &S, return ExprError(); // Only check access if all of that succeeded. - S.CheckConstructorAccess(Loc, Constructor, Entity, - Step.Function.FoundDecl.getAccess()); + S.CheckConstructorAccess(Loc, Constructor, Step.Function.FoundDecl, Entity); if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc)) return ExprError(); @@ -5777,6 +5904,11 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension( FallbackDecl); case InitializedEntity::EK_Base: + // For subobjects, we look at the complete object. + if (Entity->getParent()) + return getEntityForTemporaryLifetimeExtension(Entity->getParent(), + Entity); + // Fall through. case InitializedEntity::EK_Delegating: // We can reach this case for aggregate initialization in a constructor: // struct A { int &&r; }; @@ -6042,6 +6174,36 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr, << FixItHint::CreateRemoval(SourceRange(RParen, RParen)); } +static void CheckForNullPointerDereference(Sema &S, const Expr *E) { + // Check to see if we are dereferencing a null pointer. If so, this is + // undefined behavior, so warn about it. This only handles the pattern + // "*null", which is a very syntactic check. + if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts())) + if (UO->getOpcode() == UO_Deref && + UO->getSubExpr()->IgnoreParenCasts()-> + isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) { + S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO, + S.PDiag(diag::warn_binding_null_to_reference) + << UO->getSubExpr()->getSourceRange()); + } +} + +MaterializeTemporaryExpr * +Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary, + bool BoundToLvalueReference) { + auto MTE = new (Context) + MaterializeTemporaryExpr(T, Temporary, BoundToLvalueReference); + + // Order an ExprWithCleanups for lifetime marks. + // + // TODO: It'll be good to have a single place to check the access of the + // destructor and generate ExprWithCleanups for various uses. Currently these + // are done in both CreateMaterializeTemporaryExpr and MaybeBindToTemporary, + // but there may be a chance to merge them. + Cleanup.setExprNeedsCleanups(false); + return MTE; +} + ExprResult InitializationSequence::Perform(Sema &S, const InitializedEntity &Entity, @@ -6294,6 +6456,7 @@ InitializationSequence::Perform(Sema &S, /*IsInitializerList=*/false, ExtendingEntity->getDecl()); + CheckForNullPointerDereference(S, CurInit.get()); break; case SK_BindReferenceToTemporary: { @@ -6305,7 +6468,7 @@ InitializationSequence::Perform(Sema &S, return ExprError(); // Materialize the temporary into memory. - MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr( + MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr( Entity.getType().getNonReferenceType(), CurInit.get(), Entity.getType()->isLValueReferenceType()); @@ -6325,7 +6488,7 @@ InitializationSequence::Perform(Sema &S, MTE->getType()->isObjCLifetimeType()) || (MTE->getStorageDuration() == SD_Automatic && MTE->getType().isDestructedType())) - S.ExprNeedsCleanups = true; + S.Cleanup.setExprNeedsCleanups(true); CurInit = MTE; break; @@ -6360,7 +6523,8 @@ InitializationSequence::Perform(Sema &S, return ExprError(); // Build an expression that constructs a temporary. - CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor, + CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, + FoundFn, Constructor, ConstructorArgs, HadMultipleCandidates, /*ListInit*/ false, @@ -6371,8 +6535,8 @@ InitializationSequence::Perform(Sema &S, if (CurInit.isInvalid()) return ExprError(); - S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity, - FoundFn.getAccess()); + S.CheckConstructorAccess(Kind.getLocation(), Constructor, FoundFn, + Entity); if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation())) return ExprError(); @@ -6499,7 +6663,8 @@ InitializationSequence::Perform(Sema &S, InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty); InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity; InitListChecker PerformInitList(S, InitEntity, - InitList, Ty, /*VerifyOnly=*/false); + InitList, Ty, /*VerifyOnly=*/false, + /*TreatUnavailableAsInvalid=*/false); if (PerformInitList.HadError()) return ExprError(); @@ -6715,9 +6880,9 @@ InitializationSequence::Perform(Sema &S, << CurInit.get()->getSourceRange(); // Materialize the temporary into memory. - MaterializeTemporaryExpr *MTE = new (S.Context) - MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(), - /*BoundToLvalueReference=*/false); + MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr( + CurInit.get()->getType(), CurInit.get(), + /*BoundToLvalueReference=*/false); // Maybe lifetime-extend the array temporary's subobjects to match the // entity's lifetime. @@ -6870,7 +7035,8 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity, } InitListChecker DiagnoseInitList(S, Entity, InitList, DestType, - /*VerifyOnly=*/false); + /*VerifyOnly=*/false, + /*TreatUnavailableAsInvalid=*/false); assert(DiagnoseInitList.HadError() && "Inconsistent init list check result."); } @@ -7132,17 +7298,20 @@ bool InitializationSequence::Diagnose(Sema &S, isa<CXXConstructorDecl>(S.CurContext)) { // This is implicit default initialization of a member or // base within a constructor. If no viable function was - // found, notify the user that she needs to explicitly + // found, notify the user that they need to explicitly // initialize this base/member. CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(S.CurContext); + const CXXRecordDecl *InheritedFrom = nullptr; + if (auto Inherited = Constructor->getInheritedConstructor()) + InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass(); if (Entity.getKind() == InitializedEntity::EK_Base) { S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) - << (Constructor->getInheritedConstructor() ? 2 : - Constructor->isImplicit() ? 1 : 0) + << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0) << S.Context.getTypeDeclType(Constructor->getParent()) << /*base=*/0 - << Entity.getType(); + << Entity.getType() + << InheritedFrom; RecordDecl *BaseDecl = Entity.getBaseSpecifier()->getType()->getAs<RecordType>() @@ -7151,11 +7320,11 @@ bool InitializationSequence::Diagnose(Sema &S, << S.Context.getTagDeclType(BaseDecl); } else { S.Diag(Kind.getLocation(), diag::err_missing_default_ctor) - << (Constructor->getInheritedConstructor() ? 2 : - Constructor->isImplicit() ? 1 : 0) + << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0) << S.Context.getTypeDeclType(Constructor->getParent()) << /*member=*/1 - << Entity.getName(); + << Entity.getName() + << InheritedFrom; S.Diag(Entity.getDecl()->getLocation(), diag::note_member_declared_at); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp index 884add26e43a..1b8410d7f4b9 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp @@ -355,7 +355,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); @@ -392,7 +393,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, MethodType, MethodTypeInfo, SC_None, /*isInline=*/true, - /*isConstExpr=*/false, + IsConstexprSpecified, EndLoc); Method->setAccess(AS_public); @@ -414,11 +415,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class, // Add parameters. if (!Params.empty()) { Method->setParams(Params); - CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()), - const_cast<ParmVarDecl **>(Params.end()), + CheckParmsForFunctionDef(Params, /*CheckParameterNames=*/false); - - for (auto P : Method->params()) + + for (auto P : Method->parameters()) P->setOwningFunction(Method); } @@ -617,6 +617,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) { assert(CSI.HasImplicitReturnType); // If it was ever a placeholder, it had to been deduced to DependentTy. assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType()); + assert((!isa<LambdaScopeInfo>(CSI) || !getLangOpts().CPlusPlus14) && + "lambda expressions use auto deduction in C++14 onwards"); // C++ core issue 975: // If a lambda-expression does not include a trailing-return-type, @@ -807,19 +809,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, bool KnownDependent = false; LambdaScopeInfo *const LSI = getCurLambda(); assert(LSI && "LambdaScopeInfo should be on stack!"); - TemplateParameterList *TemplateParams = - getGenericLambdaTemplateParameterList(LSI, *this); - - if (Scope *TmplScope = CurScope->getTemplateParamParent()) { - // Since we have our own TemplateParams, so check if an outer scope - // has template params, only then are we in a dependent scope. - if (TemplateParams) { - TmplScope = TmplScope->getParent(); - TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : nullptr; - } - if (TmplScope && !TmplScope->decl_empty()) - KnownDependent = true; - } + + // The lambda-expression's closure type might be dependent even if its + // semantic context isn't, if it appears within a default argument of a + // function template. + if (CurScope->getTemplateParamParent()) + KnownDependent = true; + // Determine the signature of the call operator. TypeSourceInfo *MethodTyInfo; bool ExplicitParams = true; @@ -882,8 +878,9 @@ 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); @@ -922,7 +919,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, = Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc; for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E; PrevCaptureLoc = C->Loc, ++C) { - if (C->Kind == LCK_This) { + if (C->Kind == LCK_This || C->Kind == LCK_StarThis) { + if (C->Kind == LCK_StarThis) + Diag(C->Loc, !getLangOpts().CPlusPlus1z + ? diag::ext_star_this_lambda_capture_cxx1z + : diag::warn_cxx14_compat_star_this_lambda_capture); + // C++11 [expr.prim.lambda]p8: // An identifier or this shall not appear more than once in a // lambda-capture. @@ -934,10 +936,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - // C++11 [expr.prim.lambda]p8: - // If a lambda-capture includes a capture-default that is =, the - // lambda-capture shall not contain this [...]. - if (Intro.Default == LCD_ByCopy) { + // C++1z [expr.prim.lambda]p8: + // If a lambda-capture includes a capture-default that is =, each + // simple-capture of that lambda-capture shall be of the form "& + // identifier" or "* this". [ Note: The form [&,this] is redundant but + // accepted for compatibility with ISO C++14. --end note ] + if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) { Diag(C->Loc, diag::err_this_capture_with_copy_default) << FixItHint::CreateRemoval( SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc)); @@ -953,7 +957,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro, continue; } - CheckCXXThisCapture(C->Loc, /*Explicit=*/true); + CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true, + /*FunctionScopeIndexToStopAtPtr*/ nullptr, + C->Kind == LCK_StarThis); continue; } @@ -1144,8 +1150,8 @@ static void addFunctionPointerConversion(Sema &S, CXXMethodDecl *CallOperator) { // This conversion is explicitly disabled if the lambda's function has // pass_object_size attributes on any of its parameters. - if (std::any_of(CallOperator->param_begin(), CallOperator->param_end(), - std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>))) + if (llvm::any_of(CallOperator->parameters(), + std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>))) return; // Add the conversion to function pointer. @@ -1493,7 +1499,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, SourceRange IntroducerRange; bool ExplicitParams; bool ExplicitResultType; - bool LambdaExprNeedsCleanups; + CleanupInfo LambdaCleanup; bool ContainsUnexpandedParameterPack; SmallVector<VarDecl *, 4> ArrayIndexVars; SmallVector<unsigned, 4> ArrayIndexStarts; @@ -1503,7 +1509,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, IntroducerRange = LSI->IntroducerRange; ExplicitParams = LSI->ExplicitParams; ExplicitResultType = !LSI->HasImplicitReturnType; - LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups; + LambdaCleanup = LSI->Cleanup; ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack; CallOperator->setLexicalDeclContext(Class); @@ -1527,10 +1533,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, // Handle 'this' capture. if (From.isThisCapture()) { Captures.push_back( - LambdaCapture(From.getLocation(), IsImplicit, LCK_This)); - CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(), - getCurrentThisType(), - /*isImplicit=*/true)); + LambdaCapture(From.getLocation(), IsImplicit, + From.isCopyCapture() ? LCK_StarThis : LCK_This)); + CaptureInits.push_back(From.getInitExpr()); ArrayIndexStarts.push_back(ArrayIndexVars.size()); continue; } @@ -1585,9 +1590,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CheckCompletedCXXClass(Class); } - if (LambdaExprNeedsCleanups) - ExprNeedsCleanups = true; - + Cleanup.mergeFrom(LambdaCleanup); + LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange, CaptureDefault, CaptureDefaultLoc, Captures, @@ -1595,6 +1599,17 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, CaptureInits, ArrayIndexVars, ArrayIndexStarts, 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())); + } if (!CurContext->isDependentContext()) { switch (ExprEvalContexts.back().Context) { @@ -1619,6 +1634,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ExprEvalContexts.back().Lambdas.push_back(Lambda); break; + case DiscardedStatement: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; @@ -1697,7 +1713,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation, // Create the block literal expression. Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType()); ExprCleanupObjects.push_back(Block); - ExprNeedsCleanups = true; + Cleanup.setExprNeedsCleanups(true); return BuildBlock; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp index 45dc2e33da93..e2550824fb69 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp @@ -29,7 +29,6 @@ #include "clang/Lex/ModuleLoader.h" #include "clang/Lex/Preprocessor.h" #include "clang/Sema/DeclSpec.h" -#include "clang/Sema/ExternalSemaSource.h" #include "clang/Sema/Overload.h" #include "clang/Sema/Scope.h" #include "clang/Sema/ScopeInfo.h" @@ -280,6 +279,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind, IDNS = Decl::IDNS_ObjCProtocol; break; + case Sema::LookupOMPReductionName: + IDNS = Decl::IDNS_OMPReduction; + break; + case Sema::LookupAnyName: IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member | Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol @@ -419,6 +422,18 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, } } + // VarDecl can have incomplete array types, prefer the one with more complete + // array type. + if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) { + VarDecl *EVD = cast<VarDecl>(EUnderlying); + if (EVD->getType()->isIncompleteType() && + !DVD->getType()->isIncompleteType()) { + // Prefer the decl with a more complete type if visible. + return S.isVisible(DVD); + } + return false; // Avoid picking up a newer decl, just because it was newer. + } + // For most kinds of declaration, it doesn't really matter which one we pick. if (!isa<FunctionDecl>(DUnderlying) && !isa<VarDecl>(DUnderlying)) { // If the existing declaration is hidden, prefer the new one. Otherwise, @@ -432,10 +447,6 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind, if (Prev == EUnderlying) return true; return false; - - // If the existing declaration is hidden, prefer the new one. Otherwise, - // keep what we've got. - return !S.isVisible(Existing); } /// Determine whether \p D can hide a tag declaration. @@ -669,24 +680,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) { NameKind == Sema::LookupRedeclarationWithLinkage) { IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo(); if (II) { - if (S.getLangOpts().CPlusPlus11 && S.getLangOpts().GNUMode && - II == S.getFloat128Identifier()) { - // libstdc++4.7's type_traits expects type __float128 to exist, so - // insert a dummy type to make that header build in gnu++11 mode. - R.addDecl(S.getASTContext().getFloat128StubType()); - return true; - } - if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName && - II == S.getASTContext().getMakeIntegerSeqName()) { - R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); - return true; + if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) { + if (II == S.getASTContext().getMakeIntegerSeqName()) { + R.addDecl(S.getASTContext().getMakeIntegerSeqDecl()); + return true; + } else if (II == S.getASTContext().getTypePackElementName()) { + R.addDecl(S.getASTContext().getTypePackElementDecl()); + return true; + } } // If this is a builtin on this (or all) targets, create the decl. if (unsigned BuiltinID = II->getBuiltinID()) { - // In C++, we don't have any predefined library functions like - // 'malloc'. Instead, we'll just error. - if (S.getLangOpts().CPlusPlus && + // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined + // library functions like 'malloc'. Instead, we'll just error. + if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) && S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID)) return false; @@ -734,11 +742,11 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) { if (getLangOpts().CPlusPlus11) { // If the move constructor has not yet been declared, do so now. if (Class->needsImplicitMoveConstructor()) - DeclareImplicitMoveConstructor(Class); // might not actually do it + DeclareImplicitMoveConstructor(Class); // If the move assignment operator has not yet been declared, do so now. if (Class->needsImplicitMoveAssignment()) - DeclareImplicitMoveAssignment(Class); // might not actually do it + DeclareImplicitMoveAssignment(Class); } // If the destructor has not yet been declared, do so now. @@ -1074,32 +1082,35 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) { for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) { DeclContext *Ctx = S->getEntity(); - + bool SearchNamespaceScope = true; // Check whether the IdResolver has anything in this scope. - bool Found = false; for (; I != IEnd && S->isDeclScope(*I); ++I) { if (NamedDecl *ND = R.getAcceptableDecl(*I)) { - if (NameKind == LookupRedeclarationWithLinkage) { + if (NameKind == LookupRedeclarationWithLinkage && + !(*I)->isTemplateParameter()) { + // If it's a template parameter, we still find it, so we can diagnose + // the invalid redeclaration. + // Determine whether this (or a previous) declaration is // out-of-scope. if (!LeftStartingScope && !Initial->isDeclScope(*I)) LeftStartingScope = true; // If we found something outside of our starting scope that - // does not have linkage, skip it. If it's a template parameter, - // we still find it, so we can diagnose the invalid redeclaration. - if (LeftStartingScope && !((*I)->hasLinkage()) && - !(*I)->isTemplateParameter()) { + // does not have linkage, skip it. + if (LeftStartingScope && !((*I)->hasLinkage())) { R.setShadowed(); continue; } + } else { + // We found something in this scope, we should not look at the + // namespace scope + SearchNamespaceScope = false; } - - Found = true; R.addDecl(ND); } } - if (Found) { + if (!SearchNamespaceScope) { R.resolveKind(); if (S->isClassScope()) if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx)) @@ -1470,6 +1481,35 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D, Modules); } +bool Sema::hasVisibleMemberSpecialization( + const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) { + assert(isa<CXXRecordDecl>(D->getDeclContext()) && + "not a member specialization"); + for (auto *Redecl : D->redecls()) { + // If the specialization is declared at namespace scope, then it's a member + // specialization declaration. If it's lexically inside the class + // definition then it was instantiated. + // + // FIXME: This is a hack. There should be a better way to determine this. + // FIXME: What about MS-style explicit specializations declared within a + // class definition? + if (Redecl->getLexicalDeclContext()->isFileContext()) { + auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl)); + + if (isVisible(NonConstR)) + return true; + + if (Modules) { + Modules->push_back(getOwningModule(NonConstR)); + const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + } + } + + return false; +} + /// \brief Determine whether a declaration is visible to name lookup. /// /// This routine determines whether the declaration D is visible in the current @@ -1570,19 +1610,58 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) { assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case"); for (auto RD : D->redecls()) { - if (auto ND = dyn_cast<NamedDecl>(RD)) { - // FIXME: This is wrong in the case where the previous declaration is not - // visible in the same scope as D. This needs to be done much more - // carefully. - if (LookupResult::isVisible(SemaRef, ND)) - return ND; - } + // Don't bother with extra checks if we already know this one isn't visible. + if (RD == D) + continue; + + auto ND = cast<NamedDecl>(RD); + // FIXME: This is wrong in the case where the previous declaration is not + // visible in the same scope as D. This needs to be done much more + // carefully. + if (LookupResult::isVisible(SemaRef, ND)) + return ND; } return nullptr; } +bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D, + llvm::SmallVectorImpl<Module *> *Modules) { + assert(!isVisible(D) && "not in slow case"); + + for (auto *Redecl : D->redecls()) { + auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl)); + if (isVisible(NonConstR)) + return true; + + if (Modules) { + Modules->push_back(getOwningModule(NonConstR)); + const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR); + Modules->insert(Modules->end(), Merged.begin(), Merged.end()); + } + } + + return false; +} + NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const { + if (auto *ND = dyn_cast<NamespaceDecl>(D)) { + // Namespaces are a bit of a special case: we expect there to be a lot of + // redeclarations of some namespaces, all declarations of a namespace are + // essentially interchangeable, all declarations are found by name lookup + // if any is, and namespaces are never looked up during template + // instantiation. So we benefit from caching the check in this case, and + // it is correct to do so. + auto *Key = ND->getCanonicalDecl(); + if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key)) + return Acceptable; + auto *Acceptable = + isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key); + if (Acceptable) + getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable)); + return Acceptable; + } + return findAcceptableDecl(getSema(), D); } @@ -1986,6 +2065,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx, BaseCallback = &LookupAnyMember; break; + case LookupOMPReductionName: + BaseCallback = &CXXRecordDecl::FindOMPReductionMember; + break; + case LookupUsingDeclName: // This lookup is for redeclarations only. @@ -2409,7 +2492,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, // FIXME: That's not correct, we may have added this class only because it // was the enclosing class of another class, and in that case we won't have // added its base classes yet. - if (!Result.Classes.insert(Class).second) + if (!Result.Classes.insert(Class)) return; // -- If T is a template-id, its associated namespaces and classes are @@ -2459,7 +2542,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, if (!BaseType) continue; CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl()); - if (Result.Classes.insert(BaseDecl).second) { + if (Result.Classes.insert(BaseDecl)) { // Find the associated namespace for this base class. DeclContext *BaseCtx = BaseDecl->getDeclContext(); CollectEnclosingNamespace(Result.Namespaces, BaseCtx); @@ -2864,42 +2947,38 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD, // from an external source and invalidate lookup_result. SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end()); - for (auto *Cand : Candidates) { - if (Cand->isInvalidDecl()) + for (NamedDecl *CandDecl : Candidates) { + if (CandDecl->isInvalidDecl()) continue; - if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) { - // FIXME: [namespace.udecl]p15 says that we should only consider a - // using declaration here if it does not match a declaration in the - // derived class. We do not implement this correctly in other cases - // either. - Cand = U->getTargetDecl(); - - if (Cand->isInvalidDecl()) - continue; - } - - if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) { + DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public); + auto CtorInfo = getConstructorInfo(Cand); + if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) - AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy, - Classification, llvm::makeArrayRef(&Arg, NumArgs), - OCS, true); - else - AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public), + AddMethodCandidate(M, Cand, RD, ThisTy, Classification, + llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + else if (CtorInfo) + AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + else + AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS, + true); } else if (FunctionTemplateDecl *Tmpl = - dyn_cast<FunctionTemplateDecl>(Cand)) { + dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) { if (SM == CXXCopyAssignment || SM == CXXMoveAssignment) - AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), - RD, nullptr, ThisTy, Classification, - llvm::makeArrayRef(&Arg, NumArgs), - OCS, true); + AddMethodTemplateCandidate( + Tmpl, Cand, RD, nullptr, ThisTy, Classification, + llvm::makeArrayRef(&Arg, NumArgs), OCS, true); + else if (CtorInfo) + AddTemplateOverloadCandidate( + CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr, + llvm::makeArrayRef(&Arg, NumArgs), OCS, true); else - AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public), - nullptr, llvm::makeArrayRef(&Arg, NumArgs), - OCS, true); + AddTemplateOverloadCandidate( + Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true); } else { - assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl"); + assert(isa<UsingDecl>(Cand.getDecl()) && + "illegal Kind of operator = Decl"); } } @@ -3119,7 +3198,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R, if (FoundRaw && FoundTemplate) { Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName(); for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) - NoteOverloadCandidate((*I)->getUnderlyingDecl()->getAsFunction()); + NoteOverloadCandidate(*I, (*I)->getUnderlyingDecl()->getAsFunction()); return LOLR_Error; } @@ -3984,8 +4063,8 @@ retry_lookup: void TypoCorrectionConsumer::performQualifiedLookups() { unsigned TypoLen = Typo->getName().size(); - for (auto QR : QualifiedResults) { - for (auto NSI : Namespaces) { + for (const TypoCorrection &QR : QualifiedResults) { + for (const auto &NSI : Namespaces) { DeclContext *Ctx = NSI.DeclCtx; const Type *NSType = NSI.NameSpecifier->getAsType(); @@ -4073,10 +4152,8 @@ TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet( // Build the list of identifiers that would be used for an absolute // (from the global context) NestedNameSpecifier referring to the current // context. - for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), - CEnd = CurContextChain.rend(); - C != CEnd; ++C) { - if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) + for (DeclContext *C : llvm::reverse(CurContextChain)) { + if (auto *ND = dyn_cast_or_null<NamespaceDecl>(C)) CurContextIdentifiers.push_back(ND->getIdentifier()); } @@ -4104,13 +4181,11 @@ unsigned TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier( DeclContextList &DeclChain, NestedNameSpecifier *&NNS) { unsigned NumSpecifiers = 0; - for (DeclContextList::reverse_iterator C = DeclChain.rbegin(), - CEnd = DeclChain.rend(); - C != CEnd; ++C) { - if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) { + for (DeclContext *C : llvm::reverse(DeclChain)) { + if (auto *ND = dyn_cast_or_null<NamespaceDecl>(C)) { NNS = NestedNameSpecifier::Create(Context, NNS, ND); ++NumSpecifiers; - } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) { + } else if (auto *RD = dyn_cast_or_null<RecordDecl>(C)) { NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(), RD->getTypeForDecl()); ++NumSpecifiers; @@ -4127,10 +4202,9 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier( DeclContextList FullNamespaceDeclChain(NamespaceDeclChain); // Eliminate common elements from the two DeclContext chains. - for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(), - CEnd = CurContextChain.rend(); - C != CEnd && !NamespaceDeclChain.empty() && - NamespaceDeclChain.back() == *C; ++C) { + for (DeclContext *C : llvm::reverse(CurContextChain)) { + if (NamespaceDeclChain.empty() || NamespaceDeclChain.back() != C) + break; NamespaceDeclChain.pop_back(); } @@ -4207,7 +4281,8 @@ static void LookupPotentialTypoResult(Sema &SemaRef, } } - if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) { + if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration( + Name, ObjCPropertyQueryKind::OBJC_PR_query_instance)) { Res.addDecl(Prop); Res.resolveKind(); return; @@ -4704,11 +4779,20 @@ TypoExpr *Sema::CorrectTypoDelayed( const ObjCObjectPointerType *OPT) { assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); - TypoCorrection Empty; auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, Mode == CTK_ErrorRecovery); + // Give the external sema source a chance to correct the typo. + TypoCorrection ExternalTypo; + if (ExternalSource && Consumer) { + ExternalTypo = ExternalSource->CorrectTypo( + TypoName, LookupKind, S, SS, *Consumer->getCorrectionValidator(), + MemberContext, EnteringContext, OPT); + if (ExternalTypo) + Consumer->addCorrection(ExternalTypo); + } + if (!Consumer || Consumer->empty()) return nullptr; @@ -4716,7 +4800,7 @@ TypoExpr *Sema::CorrectTypoDelayed( // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); - if (ED > 0 && Typo->getName().size() / ED < 3) + if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; ExprEvalContexts.back().NumTypos++; @@ -4852,8 +4936,8 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, static NamedDecl *getDefinitionToImport(NamedDecl *D) { if (VarDecl *VD = dyn_cast<VarDecl>(D)) return VD->getDefinition(); - if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) - return FD->isDefined(FD) ? const_cast<FunctionDecl*>(FD) : nullptr; + if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) + return FD->getDefinition(); if (TagDecl *TD = dyn_cast<TagDecl>(D)) return TD->getDefinition(); if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D)) @@ -4866,7 +4950,7 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) { } void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, - bool NeedDefinition, bool Recover) { + MissingImportKind MIK, bool Recover) { assert(!isVisible(Decl) && "missing import for non-hidden decl?"); // Suggest importing a module providing the definition of this entity, if @@ -4875,8 +4959,6 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, if (!Def) Def = Decl; - // FIXME: Add a Fix-It that imports the corresponding module or includes - // the header. Module *Owner = getOwningModule(Decl); assert(Owner && "definition of hidden declaration is not in a module"); @@ -4885,12 +4967,20 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl, auto Merged = Context.getModulesWithMergedDefinition(Decl); OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end()); - diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, - NeedDefinition ? MissingImportKind::Definition - : MissingImportKind::Declaration, + diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK, Recover); } +/// \brief Get a "quoted.h" or <angled.h> include path to use in a diagnostic +/// suggesting the addition of a #include of the specified file. +static std::string getIncludeStringForHeader(Preprocessor &PP, + const FileEntry *E) { + bool IsSystem; + auto Path = + PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(E, &IsSystem); + return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"'); +} + void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, SourceLocation DeclLoc, ArrayRef<Module *> Modules, @@ -4911,7 +5001,18 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, Diag(UseLoc, diag::err_module_unimported_use_multiple) << (int)MIK << Decl << ModuleList; + } else if (const FileEntry *E = + PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) { + // The right way to make the declaration visible is to include a header; + // suggest doing so. + // + // FIXME: Find a smart place to suggest inserting a #include, and add + // a FixItHint there. + Diag(UseLoc, diag::err_module_unimported_use_header) + << (int)MIK << Decl << Modules[0]->getFullModuleName() + << getIncludeStringForHeader(PP, E); } else { + // FIXME: Add a FixItHint that imports the corresponding module. Diag(UseLoc, diag::err_module_unimported_use) << (int)MIK << Decl << Modules[0]->getFullModuleName(); } @@ -4927,6 +5028,12 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl, case MissingImportKind::DefaultArgument: DiagID = diag::note_default_argument_declared_here; break; + case MissingImportKind::ExplicitSpecialization: + DiagID = diag::note_explicit_specialization_declared_here; + break; + case MissingImportKind::PartialSpecialization: + DiagID = diag::note_partial_specialization_declared_here; + break; } Diag(DeclLoc, DiagID); @@ -4962,7 +5069,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction, assert(Decl && "import required but no declaration to import"); diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl, - /*NeedDefinition*/ false, ErrorRecovery); + MissingImportKind::Declaration, ErrorRecovery); return; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp index 1cb84e448067..5e38751f44a5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp @@ -303,6 +303,8 @@ makePropertyAttributesAsWritten(unsigned Attributes) { attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic; if (Attributes & ObjCDeclSpec::DQ_PR_atomic) attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic; + if (Attributes & ObjCDeclSpec::DQ_PR_class) + attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class; return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten; } @@ -334,7 +336,6 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName, } } while (Tok.isNot(tok::r_paren)); return false; - } /// Check for a mismatch in the atomicity of the given properties. @@ -431,10 +432,13 @@ Sema::HandlePropertyInClassExtension(Scope *S, return nullptr; } + bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) || + (Attributes & ObjCDeclSpec::DQ_PR_class); + // Find the property in the extended class's primary class or // extensions. - ObjCPropertyDecl *PIDecl = - CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId); + ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass( + PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty)); // If we found a property in an extension, complain. if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) { @@ -612,8 +616,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, PropertyId, AtLoc, LParenLoc, T, TInfo); - if (ObjCPropertyDecl *prevDecl = - ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) { + bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) || + (Attributes & ObjCDeclSpec::DQ_PR_class); + // Class property and instance property can have the same name. + if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl( + DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) { Diag(PDecl->getLocation(), diag::err_duplicate_property); Diag(prevDecl->getLocation(), diag::note_property_declare); PDecl->setInvalidDecl(); @@ -691,6 +698,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S, if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable) PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable); + if (Attributes & ObjCDeclSpec::DQ_PR_class) + PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class); + return PDecl; } @@ -794,7 +804,6 @@ static void setImpliedPropertyAttributeForReadOnlyProperty( property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong); else if (ivarLifetime == Qualifiers::OCL_Weak) property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak); - return; } /// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared @@ -847,7 +856,8 @@ DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc, } /// Determine whether any storage attributes were written on the property. -static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop) { +static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop, + ObjCPropertyQueryKind QueryKind) { if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true; // If this is a readwrite property in a class extension that refines @@ -870,8 +880,8 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop) { // Look through all of the protocols. for (const auto *Proto : OrigClass->all_referenced_protocols()) { - if (ObjCPropertyDecl *OrigProp = - Proto->FindPropertyDeclaration(Prop->getIdentifier())) + if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration( + Prop->getIdentifier(), QueryKind)) return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask; } @@ -888,7 +898,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, bool Synthesize, IdentifierInfo *PropertyId, IdentifierInfo *PropertyIvar, - SourceLocation PropertyIvarLoc) { + SourceLocation PropertyIvarLoc, + ObjCPropertyQueryKind QueryKind) { ObjCContainerDecl *ClassImpDecl = dyn_cast<ObjCContainerDecl>(CurContext); // Make sure we have a context for the property implementation declaration. @@ -915,11 +926,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, "ActOnPropertyImplDecl - @implementation without @interface"); // Look for this property declaration in the @implementation's @interface - property = IDecl->FindPropertyDeclaration(PropertyId); + property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind); if (!property) { Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName(); return nullptr; } + if (property->isClassProperty() && Synthesize) { + Diag(PropertyLoc, diag::error_synthesize_on_class_property) << PropertyId; + return nullptr; + } unsigned PIkind = property->getPropertyAttributesAsWritten(); if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic | ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) { @@ -993,7 +1008,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, if (!Category) return nullptr; // Look for this property declaration in @implementation's category - property = Category->FindPropertyDeclaration(PropertyId); + property = Category->FindPropertyDeclaration(PropertyId, QueryKind); if (!property) { Diag(PropertyLoc, diag::error_bad_category_property_decl) << Category->getDeclName(); @@ -1105,7 +1120,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, // It's an error if we have to do this and the user didn't // explicitly write an ownership attribute on the property. - if (!hasWrittenStorageAttribute(property) && + if (!hasWrittenStorageAttribute(property, QueryKind) && !(kind & ObjCPropertyDecl::OBJC_PR_strong)) { Diag(PropertyDiagLoc, diag::err_arc_objc_property_default_assign_on_object); @@ -1340,7 +1355,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } if (ObjCPropertyImplDecl *PPIDecl - = IC->FindPropertyImplDecl(PropertyId)) { + = IC->FindPropertyImplDecl(PropertyId, QueryKind)) { Diag(PropertyLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return nullptr; @@ -1379,7 +1394,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S, } if (ObjCPropertyImplDecl *PPIDecl = - CatImplClass->FindPropertyImplDecl(PropertyId)) { + CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) { Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId; Diag(PPIDecl->getLocation(), diag::note_previous_declaration); return nullptr; @@ -1478,24 +1493,26 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, if (!GetterMethod) return false; QualType GetterType = GetterMethod->getReturnType().getNonReferenceType(); - QualType PropertyIvarType = property->getType().getNonReferenceType(); - bool compat = Context.hasSameType(PropertyIvarType, GetterType); + QualType PropertyRValueType = + property->getType().getNonReferenceType().getAtomicUnqualifiedType(); + bool compat = Context.hasSameType(PropertyRValueType, GetterType); if (!compat) { const ObjCObjectPointerType *propertyObjCPtr = nullptr; const ObjCObjectPointerType *getterObjCPtr = nullptr; - if ((propertyObjCPtr = PropertyIvarType->getAs<ObjCObjectPointerType>()) && + if ((propertyObjCPtr = + PropertyRValueType->getAs<ObjCObjectPointerType>()) && (getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>())) compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr); - else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType) + else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType) != Compatible) { Diag(Loc, diag::error_property_accessor_type) - << property->getDeclName() << PropertyIvarType + << property->getDeclName() << PropertyRValueType << GetterMethod->getSelector() << GetterType; Diag(GetterMethod->getLocation(), diag::note_declared_at); return true; } else { compat = true; - QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType(); + QualType lhsType = Context.getCanonicalType(PropertyRValueType); QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType(); if (lhsType != rhsType && lhsType->isArithmeticType()) compat = false; @@ -1515,49 +1532,68 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property, /// CollectImmediateProperties - This routine collects all properties in /// the class and its conforming protocols; but not those in its super class. -static void CollectImmediateProperties(ObjCContainerDecl *CDecl, - ObjCContainerDecl::PropertyMap &PropMap, - ObjCContainerDecl::PropertyMap &SuperPropMap, - bool IncludeProtocols = true) { - +static void +CollectImmediateProperties(ObjCContainerDecl *CDecl, + ObjCContainerDecl::PropertyMap &PropMap, + ObjCContainerDecl::PropertyMap &SuperPropMap, + bool CollectClassPropsOnly = false, + bool IncludeProtocols = true) { if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) { - for (auto *Prop : IDecl->properties()) - PropMap[Prop->getIdentifier()] = Prop; + for (auto *Prop : IDecl->properties()) { + if (CollectClassPropsOnly && !Prop->isClassProperty()) + continue; + PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = + Prop; + } // Collect the properties from visible extensions. for (auto *Ext : IDecl->visible_extensions()) - CollectImmediateProperties(Ext, PropMap, SuperPropMap, IncludeProtocols); + CollectImmediateProperties(Ext, PropMap, SuperPropMap, + CollectClassPropsOnly, IncludeProtocols); if (IncludeProtocols) { // Scan through class's protocols. for (auto *PI : IDecl->all_referenced_protocols()) - CollectImmediateProperties(PI, PropMap, SuperPropMap); + CollectImmediateProperties(PI, PropMap, SuperPropMap, + CollectClassPropsOnly); } } if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) { - for (auto *Prop : CATDecl->properties()) - PropMap[Prop->getIdentifier()] = Prop; + for (auto *Prop : CATDecl->properties()) { + if (CollectClassPropsOnly && !Prop->isClassProperty()) + continue; + PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = + Prop; + } if (IncludeProtocols) { // Scan through class's protocols. for (auto *PI : CATDecl->protocols()) - CollectImmediateProperties(PI, PropMap, SuperPropMap); + CollectImmediateProperties(PI, PropMap, SuperPropMap, + CollectClassPropsOnly); } } else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) { for (auto *Prop : PDecl->properties()) { - ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()]; + if (CollectClassPropsOnly && !Prop->isClassProperty()) + continue; + ObjCPropertyDecl *PropertyFromSuper = + SuperPropMap[std::make_pair(Prop->getIdentifier(), + Prop->isClassProperty())]; // Exclude property for protocols which conform to class's super-class, // as super-class has to implement the property. if (!PropertyFromSuper || PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) { - ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()]; + ObjCPropertyDecl *&PropEntry = + PropMap[std::make_pair(Prop->getIdentifier(), + Prop->isClassProperty())]; if (!PropEntry) PropEntry = Prop; } } - // scan through protocol's protocols. + // Scan through protocol's protocols. for (auto *PI : PDecl->protocols()) - CollectImmediateProperties(PI, PropMap, SuperPropMap); + CollectImmediateProperties(PI, PropMap, SuperPropMap, + CollectClassPropsOnly); } } @@ -1590,7 +1626,7 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, // look up a property declaration whose one of its accessors is implemented // by this method. - for (const auto *Property : IFace->properties()) { + for (const auto *Property : IFace->instance_properties()) { if ((Property->getGetterName() == IMD->getSelector() || Property->getSetterName() == IMD->getSelector()) && (Property->getPropertyIvarDecl() == IV)) @@ -1599,7 +1635,7 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace, // Also look up property declaration in class extension whose one of its // accessors is implemented by this method. for (const auto *Ext : IFace->known_extensions()) - for (const auto *Property : Ext->properties()) + for (const auto *Property : Ext->instance_properties()) if ((Property->getGetterName() == IMD->getSelector() || Property->getSetterName() == IMD->getSelector()) && (Property->getPropertyIvarDecl() == IV)) @@ -1632,7 +1668,6 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl, /// in class's \@implementation. void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCInterfaceDecl *IDecl) { - ObjCInterfaceDecl::PropertyMap PropMap; ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder; IDecl->collectPropertiesToImplement(PropMap, PropertyOrder); @@ -1645,10 +1680,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCPropertyDecl *Prop = PropertyOrder[i]; // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || + Prop->isClassProperty() || Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional) continue; // Property may have been synthesized by user. - if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier())) + if (IMPDecl->FindPropertyImplDecl( + Prop->getIdentifier(), Prop->getQueryKind())) continue; if (IMPDecl->getInstanceMethod(Prop->getGetterName())) { if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly) @@ -1664,7 +1701,9 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, Diag(PID->getLocation(), diag::note_property_synthesize); continue; } - ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()]; + ObjCPropertyDecl *PropInSuperClass = + SuperPropMap[std::make_pair(Prop->getIdentifier(), + Prop->isClassProperty())]; if (ObjCProtocolDecl *Proto = dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) { // We won't auto-synthesize properties declared in protocols. @@ -1707,7 +1746,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl, true, /* property = */ Prop->getIdentifier(), /* ivar = */ Prop->getDefaultSynthIvarName(Context), - Prop->getLocation())); + Prop->getLocation(), Prop->getQueryKind())); if (PIDecl) { Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis); Diag(IMPDecl->getLocation(), diag::note_while_in_implementation); @@ -1726,34 +1765,42 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) { DefaultSynthesizeProperties(S, IC, IDecl); } -static void DiagnoseUnimplementedAccessor(Sema &S, - ObjCInterfaceDecl *PrimaryClass, - Selector Method, - ObjCImplDecl* IMPDecl, - ObjCContainerDecl *CDecl, - ObjCCategoryDecl *C, - ObjCPropertyDecl *Prop, - Sema::SelectorSet &SMap) { +static void DiagnoseUnimplementedAccessor( + Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method, + ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C, + ObjCPropertyDecl *Prop, + llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) { + // Check to see if we have a corresponding selector in SMap and with the + // right method type. + auto I = std::find_if(SMap.begin(), SMap.end(), + [&](const ObjCMethodDecl *x) { + return x->getSelector() == Method && + x->isClassMethod() == Prop->isClassProperty(); + }); // When reporting on missing property setter/getter implementation in // categories, do not report when they are declared in primary class, // class's protocol, or one of it super classes. This is because, // the class is going to implement them. - if (!SMap.count(Method) && + if (I == SMap.end() && (PrimaryClass == nullptr || - !PrimaryClass->lookupPropertyAccessor(Method, C))) { - S.Diag(IMPDecl->getLocation(), - isa<ObjCCategoryDecl>(CDecl) ? - diag::warn_setter_getter_impl_required_in_category : - diag::warn_setter_getter_impl_required) - << Prop->getDeclName() << Method; - S.Diag(Prop->getLocation(), - diag::note_property_declare); - if (S.LangOpts.ObjCDefaultSynthProperties && - S.LangOpts.ObjCRuntime.isNonFragile()) - if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) - if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) - S.Diag(RID->getLocation(), diag::note_suppressed_class_declare); - } + !PrimaryClass->lookupPropertyAccessor(Method, C, + Prop->isClassProperty()))) { + unsigned diag = + isa<ObjCCategoryDecl>(CDecl) + ? (Prop->isClassProperty() + ? diag::warn_impl_required_in_category_for_class_property + : diag::warn_setter_getter_impl_required_in_category) + : (Prop->isClassProperty() + ? diag::warn_impl_required_for_class_property + : diag::warn_setter_getter_impl_required); + S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method; + S.Diag(Prop->getLocation(), diag::note_property_declare); + if (S.LangOpts.ObjCDefaultSynthProperties && + S.LangOpts.ObjCRuntime.isNonFragile()) + if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl)) + if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs()) + S.Diag(RID->getLocation(), diag::note_suppressed_class_declare); + } } void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, @@ -1762,25 +1809,27 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl::PropertyMap PropMap; ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl); - if (!SynthesizeProperties) { - ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; - // Gather properties which need not be implemented in this class - // or category. - if (!IDecl) - if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { - // For categories, no need to implement properties declared in - // its primary class (and its super classes) if property is - // declared in one of those containers. - if ((IDecl = C->getClassInterface())) { - ObjCInterfaceDecl::PropertyDeclOrder PO; - IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO); - } + // Since we don't synthesize class properties, we should emit diagnose even + // if SynthesizeProperties is true. + ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; + // Gather properties which need not be implemented in this class + // or category. + if (!IDecl) + if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) { + // For categories, no need to implement properties declared in + // its primary class (and its super classes) if property is + // declared in one of those containers. + if ((IDecl = C->getClassInterface())) { + ObjCInterfaceDecl::PropertyDeclOrder PO; + IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO); } - if (IDecl) - CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap); + } + if (IDecl) + CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap); - CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap); - } + // When SynthesizeProperties is true, we only check class properties. + CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap, + SynthesizeProperties/*CollectClassPropsOnly*/); // Scan the @interface to see if any of the protocols it adopts // require an explicit implementation, via attribute @@ -1802,14 +1851,17 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, ObjCContainerDecl::PropertyMap NoNeedToImplPropMap; LazyMap.reset(new ObjCContainerDecl::PropertyMap()); CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap, + /* CollectClassPropsOnly */ false, /* IncludeProtocols */ false); } // Add the properties of 'PDecl' to the list of properties that // need to be implemented. for (auto *PropDecl : PDecl->properties()) { - if ((*LazyMap)[PropDecl->getIdentifier()]) + if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(), + PropDecl->isClassProperty())]) continue; - PropMap[PropDecl->getIdentifier()] = PropDecl; + PropMap[std::make_pair(PropDecl->getIdentifier(), + PropDecl->isClassProperty())] = PropDecl; } } } @@ -1821,10 +1873,10 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, for (const auto *I : IMPDecl->property_impls()) PropImplMap.insert(I->getPropertyDecl()); - SelectorSet InsMap; + llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap; // Collect property accessors implemented in current implementation. - for (const auto *I : IMPDecl->instance_methods()) - InsMap.insert(I->getSelector()); + for (const auto *I : IMPDecl->methods()) + InsMap.insert(I); ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl); ObjCInterfaceDecl *PrimaryClass = nullptr; @@ -1835,14 +1887,14 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl, // When reporting on missing setter/getters, do not report when // setter/getter is implemented in category's primary class // implementation. - for (const auto *I : IMP->instance_methods()) - InsMap.insert(I->getSelector()); + for (const auto *I : IMP->methods()) + InsMap.insert(I); } for (ObjCContainerDecl::PropertyMap::iterator P = PropMap.begin(), E = PropMap.end(); P != E; ++P) { ObjCPropertyDecl *Prop = P->second; - // Is there a matching propery synthesize/dynamic? + // Is there a matching property synthesize/dynamic? if (Prop->isInvalidDecl() || Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional || PropImplMap.count(Prop) || @@ -1894,13 +1946,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, return; ObjCContainerDecl::PropertyMap PM; for (auto *Prop : IDecl->properties()) - PM[Prop->getIdentifier()] = Prop; + PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop; for (const auto *Ext : IDecl->known_extensions()) for (auto *Prop : Ext->properties()) - PM[Prop->getIdentifier()] = Prop; + PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop; - for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end(); - I != E; ++I) { + for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end(); + I != E; ++I) { const ObjCPropertyDecl *Property = I->second; ObjCMethodDecl *GetterMethod = nullptr; ObjCMethodDecl *SetterMethod = nullptr; @@ -1911,8 +1963,12 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) && !(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) { - GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); - SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); + GetterMethod = Property->isClassProperty() ? + IMPDecl->getClassMethod(Property->getGetterName()) : + IMPDecl->getInstanceMethod(Property->getGetterName()); + SetterMethod = Property->isClassProperty() ? + IMPDecl->getClassMethod(Property->getSetterName()) : + IMPDecl->getInstanceMethod(Property->getSetterName()); LookedUpGetterSetter = true; if (GetterMethod) { Diag(GetterMethod->getLocation(), @@ -1932,13 +1988,17 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl, if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) || !(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite)) continue; - if (const ObjCPropertyImplDecl *PIDecl - = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) { + if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl( + Property->getIdentifier(), Property->getQueryKind())) { if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) continue; if (!LookedUpGetterSetter) { - GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName()); - SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName()); + GetterMethod = Property->isClassProperty() ? + IMPDecl->getClassMethod(Property->getGetterName()) : + IMPDecl->getInstanceMethod(Property->getGetterName()); + SetterMethod = Property->isClassProperty() ? + IMPDecl->getClassMethod(Property->getSetterName()) : + IMPDecl->getInstanceMethod(Property->getSetterName()); } if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) { SourceLocation MethodLoc = @@ -1981,6 +2041,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D for (const auto *PID : D->property_impls()) { const ObjCPropertyDecl *PD = PID->getPropertyDecl(); if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() && + !PD->isClassProperty() && !D->getInstanceMethod(PD->getGetterName())) { ObjCMethodDecl *method = PD->getGetterMethodDecl(); if (!method) @@ -2086,20 +2147,30 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { if (CD->isInvalidDecl()) return; - GetterMethod = CD->getInstanceMethod(property->getGetterName()); + bool IsClassProperty = property->isClassProperty(); + GetterMethod = IsClassProperty ? + CD->getClassMethod(property->getGetterName()) : + CD->getInstanceMethod(property->getGetterName()); + // if setter or getter is not found in class extension, it might be // in the primary class. if (!GetterMethod) if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) if (CatDecl->IsClassExtension()) - GetterMethod = CatDecl->getClassInterface()-> + GetterMethod = IsClassProperty ? CatDecl->getClassInterface()-> + getClassMethod(property->getGetterName()) : + CatDecl->getClassInterface()-> getInstanceMethod(property->getGetterName()); - SetterMethod = CD->getInstanceMethod(property->getSetterName()); + SetterMethod = IsClassProperty ? + CD->getClassMethod(property->getSetterName()) : + CD->getInstanceMethod(property->getSetterName()); if (!SetterMethod) if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD)) if (CatDecl->IsClassExtension()) - SetterMethod = CatDecl->getClassInterface()-> + SetterMethod = IsClassProperty ? CatDecl->getClassInterface()-> + getClassMethod(property->getSetterName()) : + CatDecl->getClassInterface()-> getInstanceMethod(property->getSetterName()); DiagnosePropertyAccessorMismatch(property, GetterMethod, property->getLocation()); @@ -2130,13 +2201,16 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // (which is odd, but allowed). Sema should be typechecking that the // declarations jive in that situation (which it is not currently). if (!GetterMethod) { - // No instance method of same name as property getter name was found. + // No instance/class method of same name as property getter name was found. // Declare a getter method and add it to the list of methods // for this class. SourceLocation Loc = property->getLocation(); + // The getter returns the declared property type with all qualifiers + // removed. + QualType resultTy = property->getType().getAtomicUnqualifiedType(); + // If the property is null_resettable, the getter returns nonnull. - QualType resultTy = property->getType(); if (property->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_null_resettable) { QualType modifiedTy = resultTy; @@ -2150,7 +2224,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getGetterName(), resultTy, nullptr, CD, - /*isInstance=*/true, /*isVariadic=*/false, + !IsClassProperty, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, /*isDefined=*/false, (property->getPropertyImplementation() == @@ -2186,7 +2260,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { if (!property->isReadOnly()) { // Find the default setter and if one not found, add one. if (!SetterMethod) { - // No instance method of same name as property setter name was found. + // No instance/class method of same name as property setter name was + // found. // Declare a setter method and add it to the list of methods // for this class. SourceLocation Loc = property->getLocation(); @@ -2194,7 +2269,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { SetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc, property->getSetterName(), Context.VoidTy, - nullptr, CD, /*isInstance=*/true, + nullptr, CD, !IsClassProperty, /*isVariadic=*/false, /*isPropertyAccessor=*/true, /*isImplicitlyDeclared=*/true, @@ -2204,9 +2279,12 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { ObjCMethodDecl::Optional : ObjCMethodDecl::Required); + // Remove all qualifiers from the setter's parameter type. + QualType paramTy = + property->getType().getUnqualifiedType().getAtomicUnqualifiedType(); + // If the property is null_resettable, the setter accepts a // nullable value. - QualType paramTy = property->getType().getUnqualifiedType(); if (property->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_null_resettable) { QualType modifiedTy = paramTy; @@ -2257,10 +2335,17 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) { // double bar = [foo bar]; // } // - if (GetterMethod) - AddInstanceMethodToGlobalPool(GetterMethod); - if (SetterMethod) - AddInstanceMethodToGlobalPool(SetterMethod); + if (!IsClassProperty) { + if (GetterMethod) + AddInstanceMethodToGlobalPool(GetterMethod); + if (SetterMethod) + AddInstanceMethodToGlobalPool(SetterMethod); + } else { + if (GetterMethod) + AddFactoryMethodToGlobalPool(GetterMethod); + if (SetterMethod) + AddFactoryMethodToGlobalPool(SetterMethod); + } ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD); if (!CurrentClass) { @@ -2447,5 +2532,4 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl, if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) && (Attributes & ObjCDeclSpec::DQ_PR_setter)) Diag(Loc, diag::warn_objc_readonly_property_has_setter); - } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp index 0d51ee11d109..3c8554893b43 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp @@ -15,12 +15,14 @@ #include "TreeTransform.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" #include "clang/AST/DeclOpenMP.h" #include "clang/AST/StmtCXX.h" #include "clang/AST/StmtOpenMP.h" #include "clang/AST/StmtVisitor.h" +#include "clang/AST/TypeOrdering.h" #include "clang/Basic/OpenMPKinds.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -43,111 +45,91 @@ enum DefaultDataSharingAttributes { DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'. }; -template <class T> struct MatchesAny { - explicit MatchesAny(ArrayRef<T> Arr) : Arr(std::move(Arr)) {} - bool operator()(T Kind) { - for (auto KindEl : Arr) - if (KindEl == Kind) - return true; - return false; - } - -private: - ArrayRef<T> Arr; -}; -struct MatchesAlways { - MatchesAlways() {} - template <class T> bool operator()(T) { return true; } -}; - -typedef MatchesAny<OpenMPClauseKind> MatchesAnyClause; -typedef MatchesAny<OpenMPDirectiveKind> MatchesAnyDirective; - /// \brief Stack for tracking declarations used in OpenMP directives and /// clauses and their data-sharing attributes. -class DSAStackTy { +class DSAStackTy final { public: - struct DSAVarData { - OpenMPDirectiveKind DKind; - OpenMPClauseKind CKind; - DeclRefExpr *RefExpr; + struct DSAVarData final { + OpenMPDirectiveKind DKind = OMPD_unknown; + OpenMPClauseKind CKind = OMPC_unknown; + Expr *RefExpr = nullptr; + DeclRefExpr *PrivateCopy = nullptr; SourceLocation ImplicitDSALoc; - DSAVarData() - : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr), - ImplicitDSALoc() {} - }; - -public: - struct MapInfo { - Expr *RefExpr; + DSAVarData() {} }; + typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4> + OperatorOffsetTy; private: - struct DSAInfo { - OpenMPClauseKind Attributes; - DeclRefExpr *RefExpr; + struct DSAInfo final { + OpenMPClauseKind Attributes = OMPC_unknown; + /// Pointer to a reference expression and a flag which shows that the + /// variable is marked as lastprivate(true) or not (false). + llvm::PointerIntPair<Expr *, 1, bool> RefExpr; + DeclRefExpr *PrivateCopy = nullptr; }; - typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy; - typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy; - typedef llvm::DenseMap<VarDecl *, unsigned> LoopControlVariablesMapTy; - typedef llvm::SmallDenseMap<VarDecl *, MapInfo, 64> MappedDeclsTy; + typedef llvm::DenseMap<ValueDecl *, DSAInfo> DeclSAMapTy; + typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy; + typedef std::pair<unsigned, VarDecl *> LCDeclInfo; + typedef llvm::DenseMap<ValueDecl *, LCDeclInfo> LoopControlVariablesMapTy; + typedef llvm::DenseMap< + ValueDecl *, OMPClauseMappableExprCommon::MappableExprComponentLists> + MappedExprComponentsTy; typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>> CriticalsWithHintsTy; + typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy> + DoacrossDependMapTy; - struct SharingMapTy { + struct SharingMapTy final { DeclSAMapTy SharingMap; AlignedMapTy AlignedMap; - MappedDeclsTy MappedDecls; + MappedExprComponentsTy MappedExprComponents; LoopControlVariablesMapTy LCVMap; - DefaultDataSharingAttributes DefaultAttr; + DefaultDataSharingAttributes DefaultAttr = DSA_unspecified; SourceLocation DefaultAttrLoc; - OpenMPDirectiveKind Directive; + OpenMPDirectiveKind Directive = OMPD_unknown; DeclarationNameInfo DirectiveName; - Scope *CurScope; + Scope *CurScope = nullptr; SourceLocation ConstructLoc; + /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to + /// get the data (loop counters etc.) about enclosing loop-based construct. + /// This data is required during codegen. + DoacrossDependMapTy DoacrossDepends; /// \brief first argument (Expr *) contains optional argument of the /// 'ordered' clause, the second one is true if the regions has 'ordered' /// clause, false otherwise. llvm::PointerIntPair<Expr *, 1, bool> OrderedRegion; - bool NowaitRegion; - bool CancelRegion; - unsigned AssociatedLoops; + bool NowaitRegion = false; + bool CancelRegion = false; + unsigned AssociatedLoops = 1; SourceLocation InnerTeamsRegionLoc; SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name, Scope *CurScope, SourceLocation Loc) - : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), - Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope), - ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false), - CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} - SharingMapTy() - : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified), - Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr), - ConstructLoc(), OrderedRegion(), NowaitRegion(false), - CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {} + : Directive(DKind), DirectiveName(Name), CurScope(CurScope), + ConstructLoc(Loc) {} + SharingMapTy() {} }; - typedef SmallVector<SharingMapTy, 64> StackTy; + typedef SmallVector<SharingMapTy, 4> StackTy; /// \brief Stack of used declaration and their data-sharing attributes. StackTy Stack; /// \brief true, if check for DSA must be from parent directive, false, if /// from current directive. - OpenMPClauseKind ClauseKindMode; + OpenMPClauseKind ClauseKindMode = OMPC_unknown; Sema &SemaRef; - bool ForceCapturing; + bool ForceCapturing = false; CriticalsWithHintsTy Criticals; typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator; - DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *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); public: - explicit DSAStackTy(Sema &S) - : Stack(1), ClauseKindMode(OMPC_unknown), SemaRef(S), - ForceCapturing(false) {} + explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {} bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; } void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; } @@ -179,51 +161,54 @@ public: /// \brief If 'aligned' declaration for given variable \a D was not seen yet, /// add it and return NULL; otherwise return previous occurrence's expression /// for diagnostics. - DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE); + Expr *addUniqueAligned(ValueDecl *D, Expr *NewDE); /// \brief Register specified variable as loop control variable. - void addLoopControlVariable(VarDecl *D); + void addLoopControlVariable(ValueDecl *D, VarDecl *Capture); /// \brief Check if the specified variable is a loop control variable for /// current region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - unsigned isLoopControlVariable(VarDecl *D); + LCDeclInfo isLoopControlVariable(ValueDecl *D); /// \brief Check if the specified variable is a loop control variable for /// parent region. /// \return The index of the loop control variable in the list of associated /// for-loops (from outer to inner). - unsigned isParentLoopControlVariable(VarDecl *D); + LCDeclInfo isParentLoopControlVariable(ValueDecl *D); /// \brief Get the loop control variable for the I-th loop (or nullptr) in /// parent directive. - VarDecl *getParentLoopControlVariable(unsigned I); + ValueDecl *getParentLoopControlVariable(unsigned I); /// \brief Adds explicit data sharing attribute to the specified declaration. - void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A); + void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy = nullptr); /// \brief Returns data sharing attributes from top of the stack for the /// specified declaration. - DSAVarData getTopDSA(VarDecl *D, bool FromParent); + DSAVarData getTopDSA(ValueDecl *D, bool FromParent); /// \brief Returns data-sharing attributes for the specified declaration. - DSAVarData getImplicitDSA(VarDecl *D, bool FromParent); + DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any directive which matches \a DPred /// predicate. - template <class ClausesPredicate, class DirectivesPredicate> - DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, bool FromParent); + DSAVarData hasDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent); /// \brief Checks if the specified variables has data-sharing attributes which /// match specified \a CPred predicate in any innermost directive which /// matches \a DPred predicate. - template <class ClausesPredicate, class DirectivesPredicate> - DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, - bool FromParent); + DSAVarData + hasInnermostDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent); /// \brief Checks if the specified variables has explicit data-sharing /// attributes which match specified \a CPred predicate at the specified /// OpenMP region. - bool hasExplicitDSA(VarDecl *D, + bool hasExplicitDSA(ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level); + unsigned Level, bool NotLastprivate = false); /// \brief Returns true if the directive at level \Level matches in the /// specified \a DPred predicate. @@ -232,8 +217,10 @@ public: unsigned Level); /// \brief Finds a directive which matches specified \a DPred predicate. - template <class NamedDirectivesPredicate> - bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent); + bool hasDirective(const llvm::function_ref<bool(OpenMPDirectiveKind, + const DeclarationNameInfo &, + SourceLocation)> &DPred, + bool FromParent); /// \brief Returns currently analyzed directive. OpenMPDirectiveKind getCurrentDirective() const { @@ -245,8 +232,6 @@ public: return Stack[Stack.size() - 2].Directive; return OMPD_unknown; } - /// \brief Return the directive associated with the provided scope. - OpenMPDirectiveKind getDirectiveForScope(const Scope *S) const; /// \brief Set default data sharing attribute to none. void setDefaultDSANone(SourceLocation Loc) { @@ -338,42 +323,92 @@ public: Scope *getCurScope() { return Stack.back().CurScope; } SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; } - MapInfo getMapInfoForVar(VarDecl *VD) { - MapInfo VarMI = {0}; - for (auto Cnt = Stack.size() - 1; Cnt > 0; --Cnt) { - if (Stack[Cnt].MappedDecls.count(VD)) { - VarMI = Stack[Cnt].MappedDecls[VD]; - break; - } + // 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) { + auto SI = Stack.rbegin(); + auto SE = Stack.rend(); + + if (SI == SE) + return false; + + if (CurrentRegionOnly) { + SE = std::next(SI); + } else { + ++SI; } - return VarMI; - } - void addMapInfoForVar(VarDecl *VD, MapInfo MI) { - if (Stack.size() > 1) { - Stack.back().MappedDecls[VD] = MI; + for (; SI != SE; ++SI) { + auto MI = SI->MappedExprComponents.find(VD); + if (MI != SI->MappedExprComponents.end()) + for (auto &L : MI->second) + if (Check(L)) + return true; } + return false; } - MapInfo IsMappedInCurrentRegion(VarDecl *VD) { - assert(Stack.size() > 1 && "Target level is 0"); - MapInfo VarMI = {0}; - if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) { - VarMI = Stack.back().MappedDecls[VD]; + // 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) { + 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()); + } + + unsigned getNestingLevel() const { + assert(Stack.size() > 1); + return Stack.size() - 2; + } + void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) { + assert(Stack.size() > 2); + assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive)); + Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs}); + } + llvm::iterator_range<DoacrossDependMapTy::const_iterator> + getDoacrossDependClauses() const { + assert(Stack.size() > 1); + if (isOpenMPWorksharingDirective(Stack[Stack.size() - 1].Directive)) { + auto &Ref = Stack[Stack.size() - 1].DoacrossDepends; + return llvm::make_range(Ref.begin(), Ref.end()); } - return VarMI; + return llvm::make_range(Stack[0].DoacrossDepends.end(), + Stack[0].DoacrossDepends.end()); } }; bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) { - return isOpenMPParallelDirective(DKind) || DKind == OMPD_task || - isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown || - isOpenMPTaskLoopDirective(DKind); + return isOpenMPParallelDirective(DKind) || isOpenMPTaskingDirective(DKind) || + isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown; } } // namespace -DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, - VarDecl *D) { - D = D->getCanonicalDecl(); +static ValueDecl *getCanonicalDecl(ValueDecl *D) { + auto *VD = dyn_cast<VarDecl>(D); + auto *FD = dyn_cast<FieldDecl>(D); + if (VD != nullptr) { + VD = VD->getCanonicalDecl(); + D = VD; + } else { + assert(FD); + FD = FD->getCanonicalDecl(); + D = FD; + } + return D; +} + +DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator& Iter, + ValueDecl *D) { + D = getCanonicalDecl(D); + auto *VD = dyn_cast<VarDecl>(D); + auto *FD = dyn_cast<FieldDecl>(D); DSAVarData DVar; if (Iter == std::prev(Stack.rend())) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -381,14 +416,18 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // File-scope or namespace-scope variables referenced in called routines // in the region are shared unless they appear in a threadprivate // directive. - if (!D->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) + if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D)) DVar.CKind = OMPC_shared; // OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced // in a region but not in construct] // Variables with static storage duration that are declared in called // routines in the region are shared. - if (D->hasGlobalStorage()) + if (VD && VD->hasGlobalStorage()) + DVar.CKind = OMPC_shared; + + // Non-static data members are shared by default. + if (FD) DVar.CKind = OMPC_shared; return DVar; @@ -399,8 +438,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // in a Construct, C/C++, predetermined, p.1] // Variables with automatic storage duration that are declared in a scope // inside the construct are private. - if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() && - (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) { + if (VD && isOpenMPLocal(VD, Iter) && VD->isLocalVarDecl() && + (VD->getStorageClass() == SC_Auto || VD->getStorageClass() == SC_None)) { DVar.CKind = OMPC_private; return DVar; } @@ -408,7 +447,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // Explicitly specified attributes and local variables with predetermined // attributes. if (Iter->SharingMap.count(D)) { - DVar.RefExpr = Iter->SharingMap[D].RefExpr; + DVar.RefExpr = Iter->SharingMap[D].RefExpr.getPointer(); + DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy; DVar.CKind = Iter->SharingMap[D].Attributes; DVar.ImplicitDSALoc = Iter->DefaultAttrLoc; return DVar; @@ -442,27 +482,24 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // In a task construct, if no default clause is present, a variable that in // the enclosing context is determined to be shared by all implicit tasks // bound to the current team is shared. - if (DVar.DKind == OMPD_task) { + if (isOpenMPTaskingDirective(DVar.DKind)) { DSAVarData DVarTemp; for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend(); I != EE; ++I) { // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables - // Referenced - // in a Construct, implicitly determined, p.6] + // Referenced in a Construct, implicitly determined, p.6] // In a task construct, if no default clause is present, a variable // whose data-sharing attribute is not determined by the rules above is // firstprivate. DVarTemp = getDSA(I, D); if (DVarTemp.CKind != OMPC_shared) { DVar.RefExpr = nullptr; - DVar.DKind = OMPD_task; DVar.CKind = OMPC_firstprivate; return DVar; } if (isParallelOrTaskRegion(I->Directive)) break; } - DVar.DKind = OMPD_task; DVar.CKind = (DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared; return DVar; @@ -473,12 +510,12 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter, // For constructs other than task, if no default clause is present, these // variables inherit their data-sharing attributes from the enclosing // context. - return getDSA(std::next(Iter), D); + return getDSA(++Iter, D); } -DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { +Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) { assert(Stack.size() > 1 && "Data sharing attributes stack is empty"); - D = D->getCanonicalDecl(); + D = getCanonicalDecl(D); auto It = Stack.back().AlignedMap.find(D); if (It == Stack.back().AlignedMap.end()) { assert(NewDE && "Unexpected nullptr expr to be added into aligned map"); @@ -491,46 +528,69 @@ DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) { return nullptr; } -void DSAStackTy::addLoopControlVariable(VarDecl *D) { +void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); - Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1)); + D = getCanonicalDecl(D); + Stack.back().LCVMap.insert( + std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture))); } -unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); - return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0; + D = getCanonicalDecl(D); + return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] + : LCDeclInfo(0, nullptr); } -unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) { +DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); - D = D->getCanonicalDecl(); + D = getCanonicalDecl(D); return Stack[Stack.size() - 2].LCVMap.count(D) > 0 ? Stack[Stack.size() - 2].LCVMap[D] - : 0; + : LCDeclInfo(0, nullptr); } -VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { +ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) { assert(Stack.size() > 2 && "Data-sharing attributes stack is empty"); if (Stack[Stack.size() - 2].LCVMap.size() < I) return nullptr; for (auto &Pair : Stack[Stack.size() - 2].LCVMap) { - if (Pair.second == I) + if (Pair.second.first == I) return Pair.first; } return nullptr; } -void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) { - D = D->getCanonicalDecl(); +void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A, + DeclRefExpr *PrivateCopy) { + D = getCanonicalDecl(D); if (A == OMPC_threadprivate) { - Stack[0].SharingMap[D].Attributes = A; - Stack[0].SharingMap[D].RefExpr = E; + auto &Data = Stack[0].SharingMap[D]; + Data.Attributes = A; + Data.RefExpr.setPointer(E); + Data.PrivateCopy = nullptr; } else { assert(Stack.size() > 1 && "Data-sharing attributes stack is empty"); - Stack.back().SharingMap[D].Attributes = A; - Stack.back().SharingMap[D].RefExpr = E; + auto &Data = Stack.back().SharingMap[D]; + assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) || + (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) || + (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) || + (isLoopControlVariable(D).first && A == OMPC_private)); + if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) { + Data.RefExpr.setInt(/*IntVal=*/true); + return; + } + const bool IsLastprivate = + A == OMPC_lastprivate || Data.Attributes == OMPC_lastprivate; + Data.Attributes = A; + Data.RefExpr.setPointerAndInt(E, IsLastprivate); + Data.PrivateCopy = PrivateCopy; + if (PrivateCopy) { + auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()]; + Data.Attributes = A; + Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate); + Data.PrivateCopy = nullptr; + } } } @@ -581,29 +641,35 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty, VK_LValue); } -DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) { + D = getCanonicalDecl(D); DSAVarData DVar; // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.1] // Variables appearing in threadprivate directives are threadprivate. - if ((D->getTLSKind() != VarDecl::TLS_None && - !(D->hasAttr<OMPThreadPrivateDeclAttr>() && + auto *VD = dyn_cast<VarDecl>(D); + if ((VD && VD->getTLSKind() != VarDecl::TLS_None && + !(VD->hasAttr<OMPThreadPrivateDeclAttr>() && SemaRef.getLangOpts().OpenMPUseTLS && SemaRef.getASTContext().getTargetInfo().isTLSSupported())) || - (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() && - !D->isLocalVarDecl())) { - addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(), + (VD && VD->getStorageClass() == SC_Register && + VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) { + addDSA(D, buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(), D->getLocation()), OMPC_threadprivate); } if (Stack[0].SharingMap.count(D)) { - DVar.RefExpr = Stack[0].SharingMap[D].RefExpr; + DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer(); DVar.CKind = OMPC_threadprivate; return DVar; } + if (Stack.size() == 1) { + // Not in OpenMP execution region and top scope was already checked. + return DVar; + } + // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct, C/C++, predetermined, p.4] // Static data members are shared. @@ -611,9 +677,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { // in a Construct, C/C++, predetermined, p.7] // Variables with static storage duration that are declared in a scope // inside the construct are shared. - if (D->isStaticDataMember()) { - DSAVarData DVarTemp = - hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent); + auto &&MatchesAlways = [](OpenMPDirectiveKind) -> bool { return true; }; + if (VD && VD->isStaticDataMember()) { + DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent); if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr) return DVar; @@ -638,8 +704,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { RD->hasMutableFields())) { // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate), - MatchesAlways(), FromParent); + DSAVarData DVarTemp = hasDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_firstprivate; }, + MatchesAlways, FromParent); if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr) return DVar; @@ -656,7 +723,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { } auto I = std::prev(StartI); if (I->SharingMap.count(D)) { - DVar.RefExpr = I->SharingMap[D].RefExpr; + DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer(); + DVar.PrivateCopy = I->SharingMap[D].PrivateCopy; DVar.CKind = I->SharingMap[D].Attributes; DVar.ImplicitDSALoc = I->DefaultAttrLoc; } @@ -664,8 +732,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) { return DVar; } -DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = Stack.rbegin(); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -674,13 +743,14 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) { return getDSA(StartI, D); } -template <class ClausesPredicate, class DirectivesPredicate> -DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, - bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData +DSAStackTy::hasDSA(ValueDecl *D, + const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); + auto EndI = Stack.rend(); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } @@ -694,13 +764,13 @@ DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred, return DSAVarData(); } -template <class ClausesPredicate, class DirectivesPredicate> -DSAStackTy::DSAVarData -DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, - DirectivesPredicate DPred, bool FromParent) { - D = D->getCanonicalDecl(); +DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA( + ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, + bool FromParent) { + D = getCanonicalDecl(D); auto StartI = std::next(Stack.rbegin()); - auto EndI = std::prev(Stack.rend()); + auto EndI = Stack.rend(); if (FromParent && StartI != EndI) { StartI = std::next(StartI); } @@ -716,37 +786,41 @@ DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred, } bool DSAStackTy::hasExplicitDSA( - VarDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, - unsigned Level) { + ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred, + unsigned Level, bool NotLastprivate) { if (CPred(ClauseKindMode)) return true; - if (isClauseParsingMode()) - ++Level; - D = D->getCanonicalDecl(); - auto StartI = Stack.rbegin(); - auto EndI = std::prev(Stack.rend()); + D = getCanonicalDecl(D); + auto StartI = std::next(Stack.begin()); + auto EndI = Stack.end(); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); - return (StartI->SharingMap.count(D) > 0) && StartI->SharingMap[D].RefExpr && - CPred(StartI->SharingMap[D].Attributes); + return (StartI->SharingMap.count(D) > 0) && + StartI->SharingMap[D].RefExpr.getPointer() && + CPred(StartI->SharingMap[D].Attributes) && + (!NotLastprivate || !StartI->SharingMap[D].RefExpr.getInt()); } bool DSAStackTy::hasExplicitDirective( const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred, unsigned Level) { - if (isClauseParsingMode()) - ++Level; - auto StartI = Stack.rbegin(); - auto EndI = std::prev(Stack.rend()); + auto StartI = std::next(Stack.begin()); + auto EndI = Stack.end(); if (std::distance(StartI, EndI) <= (int)Level) return false; std::advance(StartI, Level); return DPred(StartI->Directive); } -template <class NamedDirectivesPredicate> -bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { +bool DSAStackTy::hasDirective( + const llvm::function_ref<bool(OpenMPDirectiveKind, + const DeclarationNameInfo &, SourceLocation)> + &DPred, + bool FromParent) { + // We look only in the enclosing region. + if (Stack.size() < 2) + return false; auto StartI = std::next(Stack.rbegin()); auto EndI = std::prev(Stack.rend()); if (FromParent && StartI != EndI) { @@ -759,31 +833,22 @@ bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) { return false; } -OpenMPDirectiveKind DSAStackTy::getDirectiveForScope(const Scope *S) const { - for (auto I = Stack.rbegin(), EE = Stack.rend(); I != EE; ++I) - if (I->CurScope == S) - return I->Directive; - return OMPD_unknown; -} - void Sema::InitDataSharingAttributesStack() { VarDataSharingAttributesStack = new DSAStackTy(*this); } #define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack) -bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, - const CapturedRegionScopeInfo *RSI) { +bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); auto &Ctx = getASTContext(); bool IsByRef = true; // Find the directive that is associated with the provided scope. - auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope); - auto Ty = VD->getType(); + auto Ty = D->getType(); - if (isOpenMPTargetDirective(DKind)) { + if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) { // This table summarizes how a given variable should be passed to the device // given its type and the clauses where it appears. This table is based on // the description in OpenMP 4.5 [2.10.4, target Construct] and @@ -838,31 +903,83 @@ bool Sema::IsOpenMPCapturedByRef(VarDecl *VD, // array section, the runtime library may pass the NULL value to the // device instead of the value passed to it by the compiler. - // FIXME: Right now, only implicit maps are implemented. Properly mapping - // values requires having the map, private, and firstprivate clauses SEMA - // and parsing in place, which we don't yet. if (Ty->isReferenceType()) Ty = Ty->castAs<ReferenceType>()->getPointeeType(); - IsByRef = !Ty->isScalarType(); + + // Locate map clauses and see if the variable being captured is referred to + // in any of those clauses. Here we only care about variables, not fields, + // because fields are part of aggregates. + bool IsVariableUsedInMapClause = false; + bool IsVariableAssociatedWithSection = false; + + DSAStack->checkMappableExprComponentListsForDecl( + D, /*CurrentRegionOnly=*/true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + MapExprComponents) { + + auto EI = MapExprComponents.rbegin(); + auto EE = MapExprComponents.rend(); + + assert(EI != EE && "Invalid map expression!"); + + if (isa<DeclRefExpr>(EI->getAssociatedExpression())) + IsVariableUsedInMapClause |= EI->getAssociatedDeclaration() == D; + + ++EI; + if (EI == EE) + return false; + + if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) || + isa<MemberExpr>(EI->getAssociatedExpression())) { + IsVariableAssociatedWithSection = true; + // There is nothing more we need to know about this variable. + return true; + } + + // Keep looking for more map info. + return false; + }); + + if (IsVariableUsedInMapClause) { + // If variable is identified in a map clause it is always captured by + // reference except if it is a pointer that is dereferenced somehow. + IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection); + } else { + // By default, all the data that has a scalar type is mapped by copy. + IsByRef = !Ty->isScalarType(); + } } - // When passing data by value, we need to make sure it fits the uintptr size + if (IsByRef && Ty.getNonReferenceType()->isScalarType()) { + IsByRef = !DSAStack->hasExplicitDSA( + D, [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; }, + Level, /*NotLastprivate=*/true); + } + + // When passing data by copy, we need to make sure it fits the uintptr size // and alignment, because the runtime library only deals with uintptr types. // If it does not fit the uintptr size, we need to pass the data by reference // instead. if (!IsByRef && (Ctx.getTypeSizeInChars(Ty) > Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) || - Ctx.getDeclAlign(VD) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) + Ctx.getDeclAlign(D) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) { IsByRef = true; + } return IsByRef; } -bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { +unsigned Sema::getOpenMPNestingLevel() const { + assert(getLangOpts().OpenMP); + return DSAStack->getNestingLevel(); +} + +VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); - VD = VD->getCanonicalDecl(); + D = getCanonicalDecl(D); // If we are attempting to capture a global variable in a directive with // 'target' we return true so that this global is also mapped to the device. @@ -871,52 +988,55 @@ bool Sema::IsOpenMPCapturedVar(VarDecl *VD) { // then it should not be captured. Therefore, an extra check has to be // inserted here once support for 'declare target' is added. // - if (!VD->hasLocalStorage()) { + auto *VD = dyn_cast<VarDecl>(D); + if (VD && !VD->hasLocalStorage()) { if (DSAStack->getCurrentDirective() == OMPD_target && - !DSAStack->isClauseParsingMode()) { - return true; - } - if (DSAStack->getCurScope() && - DSAStack->hasDirective( - [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI, - SourceLocation Loc) -> bool { - return isOpenMPTargetDirective(K); + !DSAStack->isClauseParsingMode()) + return VD; + if (DSAStack->hasDirective( + [](OpenMPDirectiveKind K, const DeclarationNameInfo &, + SourceLocation) -> bool { + return isOpenMPTargetExecutionDirective(K); }, - false)) { - return true; - } + false)) + return VD; } if (DSAStack->getCurrentDirective() != OMPD_unknown && (!DSAStack->isClauseParsingMode() || DSAStack->getParentDirective() != OMPD_unknown)) { - if (DSAStack->isLoopControlVariable(VD) || - (VD->hasLocalStorage() && + auto &&Info = DSAStack->isLoopControlVariable(D); + if (Info.first || + (VD && VD->hasLocalStorage() && isParallelOrTaskRegion(DSAStack->getCurrentDirective())) || - DSAStack->isForceVarCapturing()) - return true; - auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode()); + (VD && DSAStack->isForceVarCapturing())) + return VD ? VD : Info.second; + auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode()); if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind)) - return true; - DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), - DSAStack->isClauseParsingMode()); - return DVarPrivate.CKind != OMPC_unknown; + return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); + DVarPrivate = DSAStack->hasDSA( + D, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, + DSAStack->isClauseParsingMode()); + if (DVarPrivate.CKind != OMPC_unknown) + return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl()); } - return false; + return nullptr; } -bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) { +bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); return DSAStack->hasExplicitDSA( - VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); + D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level); } -bool Sema::isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level) { +bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) { assert(LangOpts.OpenMP && "OpenMP is not allowed"); // Return true if the current level is no longer enclosed in a target region. - return !VD->hasLocalStorage() && - DSAStack->hasExplicitDirective(isOpenMPTargetDirective, Level); + auto *VD = dyn_cast<VarDecl>(D); + return VD && !VD->hasLocalStorage() && + DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, + Level); } void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; } @@ -951,7 +1071,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { PrivateCopies.push_back(nullptr); continue; } - auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl()); + auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens()); + VarDecl *VD = cast<VarDecl>(DRE->getDecl()); QualType Type = VD->getType().getNonReferenceType(); auto DVar = DSAStack->getTopDSA(VD, false); if (DVar.CKind == OMPC_lastprivate) { @@ -975,9 +1096,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { } } // Set initializers to private copies if no errors were found. - if (PrivateCopies.size() == Clause->varlist_size()) { + if (PrivateCopies.size() == Clause->varlist_size()) Clause->setPrivateCopies(PrivateCopies); - } } } } @@ -989,7 +1109,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) { static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, - Scope *S); + Scope *S, DSAStackTy *Stack); namespace { @@ -1009,6 +1129,23 @@ public: return false; } }; + +class VarOrFuncDeclFilterCCC : public CorrectionCandidateCallback { +private: + Sema &SemaRef; + +public: + explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {} + bool ValidateCandidate(const TypoCorrection &Candidate) override { + NamedDecl *ND = Candidate.getCorrectionDecl(); + if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(), + SemaRef.getCurScope()); + } + return false; + } +}; + } // namespace ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, @@ -1131,8 +1268,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope, } QualType ExprType = VD->getType().getNonReferenceType(); - ExprResult DE = buildDeclRefExpr(*this, VD, ExprType, Id.getLoc()); - return DE; + return DeclRefExpr::Create(Context, NestedNameSpecifierLoc(), + SourceLocation(), VD, + /*RefersToEnclosingVariableOrCapture=*/false, + Id.getLoc(), ExprType, VK_LValue); } Sema::DeclGroupPtrTy @@ -1142,7 +1281,7 @@ Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc, CurContext->addDecl(D); return DeclGroupPtrTy::make(DeclGroupRef(D)); } - return DeclGroupPtrTy(); + return nullptr; } namespace { @@ -1182,6 +1321,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { VarDecl *VD = cast<VarDecl>(DE->getDecl()); SourceLocation ILoc = DE->getExprLoc(); + // Mark variable as used. + VD->setReferenced(); + VD->markUsed(Context); + QualType QType = VD->getType(); if (QType->isDependentType() || QType->isInstantiationDependentType()) { // It will be analyzed later. @@ -1252,7 +1395,7 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) { } static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, - const VarDecl *VD, DSAStackTy::DSAVarData DVar, + const ValueDecl *D, DSAStackTy::DSAVarData DVar, bool IsLoopIterVar = false) { if (DVar.RefExpr) { SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa) @@ -1272,7 +1415,8 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, PDSA_Implicit } Reason = PDSA_Implicit; bool ReportHint = false; - auto ReportLoc = VD->getLocation(); + auto ReportLoc = D->getLocation(); + auto *VD = dyn_cast<VarDecl>(D); if (IsLoopIterVar) { if (DVar.CKind == OMPC_private) Reason = PDSA_LoopIterVarPrivate; @@ -1280,18 +1424,19 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack, Reason = PDSA_LoopIterVarLastprivate; else Reason = PDSA_LoopIterVarLinear; - } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) { + } else if (isOpenMPTaskingDirective(DVar.DKind) && + DVar.CKind == OMPC_firstprivate) { Reason = PDSA_TaskVarFirstprivate; ReportLoc = DVar.ImplicitDSALoc; - } else if (VD->isStaticLocal()) + } else if (VD && VD->isStaticLocal()) Reason = PDSA_StaticLocalVarShared; - else if (VD->isStaticDataMember()) + else if (VD && VD->isStaticDataMember()) Reason = PDSA_StaticMemberShared; - else if (VD->isFileVarDecl()) + else if (VD && VD->isFileVarDecl()) Reason = PDSA_GlobalVarShared; - else if (VD->getType().isConstant(SemaRef.getASTContext())) + else if (D->getType().isConstant(SemaRef.getASTContext())) Reason = PDSA_ConstVarShared; - else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { + else if (VD && VD->isLocalVarDecl() && DVar.CKind == OMPC_private) { ReportHint = true; Reason = PDSA_LocalVarPrivate; } @@ -1312,10 +1457,13 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> { bool ErrorFound; CapturedStmt *CS; llvm::SmallVector<Expr *, 8> ImplicitFirstprivate; - llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; + llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; public: void VisitDeclRefExpr(DeclRefExpr *E) { + if (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) + return; if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) { // Skip internally declared variables. if (VD->isLocalVarDecl() && !CS->capturesVariable(VD)) @@ -1342,14 +1490,14 @@ public: // A list item that appears in a reduction clause of the innermost // enclosing worksharing or parallel construct may not be accessed in an // explicit task. - DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K) || - isOpenMPTeamsDirective(K); - }, - false); - if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) { + DVar = Stack->hasInnermostDSA( + VD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K); + }, + false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { ErrorFound = true; SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); ReportOriginalDSA(SemaRef, Stack, VD, DVar); @@ -1358,10 +1506,52 @@ public: // Define implicit data-sharing attributes for task. DVar = Stack->getImplicitDSA(VD, false); - if (DKind == OMPD_task && DVar.CKind != OMPC_shared) + if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + !Stack->isLoopControlVariable(VD).first) ImplicitFirstprivate.push_back(E); } } + void VisitMemberExpr(MemberExpr *E) { + if (E->isTypeDependent() || E->isValueDependent() || + E->containsUnexpandedParameterPack() || E->isInstantiationDependent()) + return; + if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) { + if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) { + auto DVar = Stack->getTopDSA(FD, false); + // Check if the variable has explicit DSA set and stop analysis if it + // so. + if (DVar.RefExpr) + return; + + auto ELoc = E->getExprLoc(); + auto DKind = Stack->getCurrentDirective(); + // OpenMP [2.9.3.6, Restrictions, p.2] + // A list item that appears in a reduction clause of the innermost + // enclosing worksharing or parallel construct may not be accessed in + // an explicit task. + DVar = Stack->hasInnermostDSA( + FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K) || + isOpenMPTeamsDirective(K); + }, + false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) { + ErrorFound = true; + SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task); + ReportOriginalDSA(SemaRef, Stack, FD, DVar); + return; + } + + // Define implicit data-sharing attributes for task. + DVar = Stack->getImplicitDSA(FD, false); + if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared && + !Stack->isLoopControlVariable(FD).first) + ImplicitFirstprivate.push_back(E); + } + } + } void VisitOMPExecutableDirective(OMPExecutableDirective *S) { for (auto *C : S->clauses()) { // Skip analysis of arguments of implicitly defined firstprivate clause @@ -1382,7 +1572,7 @@ public: bool isErrorFound() { return ErrorFound; } ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; } - llvm::DenseMap<VarDecl *, Expr *> &getVarsWithInheritedDSA() { + llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() { return VarsWithInheritedDSA; } @@ -1393,84 +1583,11 @@ public: void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { switch (DKind) { - case OMPD_parallel: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); - Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_simd: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_for: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_for_simd: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_sections: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_section: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_single: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_master: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_critical: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_parallel_for: { + case OMPD_parallel: + case OMPD_parallel_for: + case OMPD_parallel_for_simd: + case OMPD_parallel_sections: + case OMPD_teams: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); @@ -1483,46 +1600,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Params); break; } - case OMPD_parallel_for_simd: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + case OMPD_simd: + case OMPD_for: + case OMPD_for_simd: + case OMPD_sections: + case OMPD_section: + case OMPD_single: + case OMPD_master: + case OMPD_critical: + case OMPD_taskgroup: + case OMPD_distribute: + case OMPD_ordered: + case OMPD_atomic: + case OMPD_target_data: + case OMPD_target: + case OMPD_target_parallel: + case OMPD_target_parallel_for: + case OMPD_target_parallel_for_simd: { Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); break; } - case OMPD_parallel_sections: { + case OMPD_task: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); - QualType KmpInt32PtrTy = - Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); + QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; + FunctionProtoType::ExtProtoInfo EPI; + EPI.Variadic = true; + QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { - std::make_pair(".global_tid.", KmpInt32PtrTy), - std::make_pair(".bound_tid.", KmpInt32PtrTy), + std::make_pair(".global_tid.", KmpInt32Ty), + std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), + std::make_pair(".privates.", Context.VoidPtrTy.withConst()), + std::make_pair(".copy_fn.", + Context.getPointerType(CopyFnType).withConst()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, Params); + // Mark this captured region as inlined, because we don't use outlined + // function directly. + getCurCapturedRegion()->TheCapturedDecl->addAttr( + AlwaysInlineAttr::CreateImplicit( + Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } - case OMPD_task: { - QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); + case OMPD_taskloop: + case OMPD_taskloop_simd: { + QualType KmpInt32Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1); + QualType KmpUInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0); + QualType KmpInt64Ty = + Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1); QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()}; FunctionProtoType::ExtProtoInfo EPI; EPI.Variadic = true; QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32Ty), - std::make_pair(".part_id.", KmpInt32Ty), + std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)), std::make_pair(".privates.", Context.VoidPtrTy.withConst().withRestrict()), std::make_pair( ".copy_fn.", Context.getPointerType(CopyFnType).withConst().withRestrict()), + std::make_pair(".task_t.", Context.VoidPtrTy.withConst()), + std::make_pair(".lb.", KmpUInt64Ty), + std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty), + std::make_pair(".liter.", KmpInt32Ty), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1534,70 +1683,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange())); break; } - case OMPD_ordered: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_atomic: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_target_data: - case OMPD_target: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_teams: { + case OMPD_distribute_parallel_for_simd: + case OMPD_distribute_simd: + case OMPD_distribute_parallel_for: { QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1); QualType KmpInt32PtrTy = Context.getPointerType(KmpInt32Ty).withConst().withRestrict(); Sema::CapturedParamNameType Params[] = { std::make_pair(".global_tid.", KmpInt32PtrTy), std::make_pair(".bound_tid.", KmpInt32PtrTy), - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_taskgroup: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_taskloop: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_taskloop_simd: { - Sema::CapturedParamNameType Params[] = { - std::make_pair(StringRef(), QualType()) // __context with shared vars - }; - ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, - Params); - break; - } - case OMPD_distribute: { - Sema::CapturedParamNameType Params[] = { + std::make_pair(".previous.lb.", Context.getSizeType()), + std::make_pair(".previous.ub.", Context.getSizeType()), std::make_pair(StringRef(), QualType()) // __context with shared vars }; ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP, @@ -1611,12 +1707,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) { case OMPD_cancellation_point: case OMPD_cancel: case OMPD_flush: + case OMPD_target_enter_data: + case OMPD_target_exit_data: + case OMPD_declare_reduction: + case OMPD_declare_simd: + case OMPD_declare_target: + case OMPD_end_declare_target: + case OMPD_target_update: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); } } +static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id, + Expr *CaptureExpr, bool WithInit, + bool AsExpression) { + assert(CaptureExpr); + ASTContext &C = S.getASTContext(); + Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts(); + QualType Ty = Init->getType(); + if (CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue()) { + if (S.getLangOpts().CPlusPlus) + Ty = C.getLValueReferenceType(Ty); + else { + Ty = C.getPointerType(Ty); + ExprResult Res = + S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init); + if (!Res.isUsable()) + return nullptr; + Init = Res.get(); + } + WithInit = true; + } + auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty); + if (!WithInit) + CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange())); + S.CurContext->addHiddenDecl(CED); + S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false, + /*TypeMayContainAuto=*/true); + return CED; +} + +static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr, + bool WithInit) { + OMPCapturedExprDecl *CD; + if (auto *VD = S.IsOpenMPCapturedDecl(D)) + CD = cast<OMPCapturedExprDecl>(VD); + else + CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit, + /*AsExpression=*/false); + return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), + CaptureExpr->getExprLoc()); +} + +static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) { + if (!Ref) { + auto *CD = + buildCaptureDecl(S, &S.getASTContext().Idents.get(".capture_expr."), + CaptureExpr, /*WithInit=*/true, /*AsExpression=*/true); + Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(), + CaptureExpr->getExprLoc()); + } + ExprResult Res = Ref; + if (!S.getLangOpts().CPlusPlus && + CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue() && + Ref->getType()->isPointerType()) + Res = S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_Deref, Ref); + if (!Res.isUsable()) + return ExprError(); + return CaptureExpr->isGLValue() ? Res : S.DefaultLvalueConversion(Res.get()); +} + StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, ArrayRef<OMPClause *> Clauses) { if (!S.isUsable()) { @@ -1642,14 +1804,20 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S, } } DSAStack->setForceVarCapturing(/*V=*/false); - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && - Clause->getClauseKind() == OMPC_schedule) { + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { // Mark all variables in private list clauses as used in inner region. // Required for proper codegen of combined directives. // TODO: add processing for other clauses. - if (auto *E = cast_or_null<Expr>( - cast<OMPScheduleClause>(Clause)->getHelperChunkSize())) - MarkDeclarationsReferencedInExpr(E); + if (auto *C = OMPClauseWithPreInit::get(Clause)) { + if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) { + for (auto *D : DS->decls()) + MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D)); + } + } + if (auto *C = OMPClauseWithPostUpdate::get(Clause)) { + if (auto *E = C->getPostUpdateExpr()) + MarkDeclarationsReferencedInExpr(E); + } } if (Clause->getClauseKind() == OMPC_schedule) SC = cast<OMPScheduleClause>(Clause); @@ -1725,13 +1893,25 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | distribute | + | + // | | parallel for | | + // | parallel | distribute | + | + // | |parallel for simd| | + // | parallel | distribute simd | + | // +------------------+-----------------+------------------------------------+ // | for | parallel | * | // | for | for | + | @@ -1754,13 +1934,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | for | distribute | + | + // | | parallel for | | + // | for | distribute | + | + // | |parallel for simd| | + // | for | distribute simd | + | + // | for | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | master | parallel | * | // | master | for | + | @@ -1783,13 +1977,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | master | distribute | + | + // | | parallel for | | + // | master | distribute | + | + // | |parallel for simd| | + // | master | distribute simd | + | + // | master | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | critical | parallel | * | // | critical | for | + | @@ -1811,20 +2019,34 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | 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 | simd | * | // | simd | sections | | // | simd | section | | // | simd | single | | @@ -1840,6 +2062,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -1847,13 +2076,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | simd | * | // | for simd | sections | | // | for simd | section | | // | for simd | single | | @@ -1869,6 +2105,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -1876,13 +2119,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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| simd | * | // | parallel for simd| sections | | // | parallel for simd| section | | // | parallel for simd| single | | @@ -1898,6 +2148,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -1905,6 +2162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | @@ -1927,13 +2190,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | sections | distribute | + | + // | | parallel for | | + // | sections | distribute | + | + // | |parallel for simd| | + // | sections | distribute simd | + | + // | sections | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | section | parallel | * | // | section | for | + | @@ -1956,13 +2233,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | section | distribute | + | + // | | parallel for | | + // | section | distribute | + | + // | |parallel for simd| | + // | section | distribute simd | + | + // | section | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | single | parallel | * | // | single | for | + | @@ -1985,13 +2276,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | single | distribute | + | + // | | parallel for | | + // | single | distribute | + | + // | |parallel for simd| | + // | single | distribute simd | + | + // | single | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | parallel for | parallel | * | // | parallel for | for | + | @@ -2014,13 +2319,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | 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 | + | @@ -2043,13 +2362,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 sections| distribute | + | + // | | parallel for | | + // | parallel sections| distribute | + | + // | |parallel for simd| | + // | parallel sections| distribute simd | + | + // | parallel sections| target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | task | parallel | * | // | task | for | + | @@ -2072,13 +2405,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | task | distribute | + | + // | | parallel for | | + // | task | distribute | + | + // | |parallel for simd| | + // | task | distribute simd | + | + // | task | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | ordered | parallel | * | // | ordered | for | + | @@ -2101,13 +2448,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | ordered | distribute | + | + // | | parallel for | | + // | ordered | distribute | + | + // | |parallel for simd| | + // | ordered | distribute simd | + | + // | ordered | target parallel | + | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | atomic | parallel | | // | atomic | for | | @@ -2130,13 +2491,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | + // | atomic | distribute | | + // | | parallel for | | + // | atomic | distribute | | + // | |parallel for simd| | + // | atomic | distribute simd | | + // | atomic | target parallel | | + // | | for simd | | // +------------------+-----------------+------------------------------------+ // | target | parallel | * | // | target | for | * | @@ -2158,14 +2533,142 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | target | flush | * | // | target | ordered | * | // | target | atomic | * | - // | target | target | * | + // | 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 | + | + // | 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 | + | @@ -2188,6 +2691,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -2195,6 +2705,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | @@ -2217,19 +2734,33 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | + | + // | 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 | simd | * | // | taskloop simd | sections | | // | taskloop simd | section | | // | taskloop simd | single | | @@ -2245,6 +2776,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -2252,6 +2790,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | * | @@ -2274,6 +2819,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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 | | @@ -2281,9 +2833,274 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // | 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; enum { @@ -2297,10 +3114,15 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // OpenMP constructs may not be nested inside a simd region. // 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. - SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd); - return true; + // 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 + // extension. The OpenMP 4.5 spec does not allow it. Issue a warning + // message. + SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd) + ? diag::err_omp_prohibited_region_simd + : diag::warn_omp_nesting_simd); + return CurrentRegion != OMPD_simd; } if (ParentRegion == OMPD_atomic) { // OpenMP [2.16, Nesting of Regions] @@ -2340,9 +3162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP construct that matches the type specified in // construct-type-clause. NestingProhibited = - !((CancelRegion == OMPD_parallel && ParentRegion == OMPD_parallel) || + !((CancelRegion == OMPD_parallel && + (ParentRegion == OMPD_parallel || + ParentRegion == OMPD_target_parallel)) || (CancelRegion == OMPD_for && - (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for)) || + (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for || + ParentRegion == OMPD_target_parallel_for)) || (CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) || (CancelRegion == OMPD_sections && (ParentRegion == OMPD_section || ParentRegion == OMPD_sections || @@ -2352,8 +3177,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // A master region may not be closely nested inside a worksharing, // atomic, or explicit task region. NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || - isOpenMPTaskLoopDirective(ParentRegion); + isOpenMPTaskingDirective(ParentRegion); } else if (CurrentRegion == OMPD_critical && CurrentName.getName()) { // OpenMP [2.16, Nesting of Regions] // A critical region may not be nested (closely or otherwise) inside a @@ -2387,21 +3211,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // OpenMP [2.16, Nesting of Regions] // A barrier region may not be closely nested inside a worksharing, // explicit task, critical, ordered, atomic, or master region. - NestingProhibited = - isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || - isOpenMPTaskLoopDirective(ParentRegion); + NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || + ParentRegion == OMPD_ordered; } else if (isOpenMPWorksharingDirective(CurrentRegion) && !isOpenMPParallelDirective(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. - NestingProhibited = - isOpenMPWorksharingDirective(ParentRegion) || - ParentRegion == OMPD_task || ParentRegion == OMPD_master || - ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered || - isOpenMPTaskLoopDirective(ParentRegion); + NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || + ParentRegion == OMPD_master || + ParentRegion == OMPD_critical || + ParentRegion == OMPD_ordered; Recommend = ShouldBeInParallelRegion; } else if (CurrentRegion == OMPD_ordered) { // OpenMP [2.16, Nesting of Regions] @@ -2413,8 +3237,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, // An ordered construct with the simd clause is the only OpenMP construct // that can appear in the simd region. NestingProhibited = ParentRegion == OMPD_critical || - ParentRegion == OMPD_task || - isOpenMPTaskLoopDirective(ParentRegion) || + isOpenMPTaskingDirective(ParentRegion) || !(isOpenMPSimdDirective(ParentRegion) || Stack->isParentOrderedRegion()); Recommend = ShouldBeInOrderedRegion; @@ -2442,10 +3265,29 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack, NestingProhibited = !isOpenMPTeamsDirective(ParentRegion); Recommend = ShouldBeInTeamsRegion; } + if (!NestingProhibited && + (isOpenMPTargetExecutionDirective(CurrentRegion) || + isOpenMPTargetDataManagementDirective(CurrentRegion))) { + // OpenMP 4.5 [2.17 Nesting of Regions] + // If a target, target update, target data, target enter data, or + // target exit data construct is encountered during execution of a + // target region, the behavior is unspecified. + NestingProhibited = Stack->hasDirective( + [&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &, + SourceLocation) -> bool { + if (isOpenMPTargetExecutionDirective(K)) { + OffendingRegion = K; + return true; + } else + return false; + }, + false /* don't skip top directive */); + CloseNesting = false; + } if (NestingProhibited) { SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region) - << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend - << getOpenMPDirectiveName(CurrentRegion); + << CloseNesting << getOpenMPDirectiveName(OffendingRegion) + << Recommend << getOpenMPDirectiveName(CurrentRegion); return true; } } @@ -2544,7 +3386,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( return StmtError(); llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit; - llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA; + llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA; bool ErrorFound = false; ClausesWithImplicit.append(Clauses.begin(), Clauses.end()); if (AStmt) { @@ -2679,6 +3521,18 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc); AllowedNameModifiers.push_back(OMPD_target); break; + case OMPD_target_parallel: + Res = ActOnOpenMPTargetParallelDirective(ClausesWithImplicit, AStmt, + StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_target_parallel_for: + Res = ActOnOpenMPTargetParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_target); + AllowedNameModifiers.push_back(OMPD_parallel); + break; case OMPD_cancellation_point: assert(ClausesWithImplicit.empty() && "No clauses are allowed for 'omp cancellation point' directive"); @@ -2698,6 +3552,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( EndLoc); AllowedNameModifiers.push_back(OMPD_target_data); break; + case OMPD_target_enter_data: + Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target_enter_data); + break; + case OMPD_target_exit_data: + Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc, + EndLoc); + AllowedNameModifiers.push_back(OMPD_target_exit_data); + break; case OMPD_taskloop: Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); @@ -2712,7 +3576,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); break; + case OMPD_target_update: + assert(!AStmt && "Statement is not allowed for target update"); + Res = + ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc); + AllowedNameModifiers.push_back(OMPD_target_update); + break; + case OMPD_distribute_parallel_for: + Res = ActOnOpenMPDistributeParallelForDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_distribute_parallel_for_simd: + Res = ActOnOpenMPDistributeParallelForSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + AllowedNameModifiers.push_back(OMPD_parallel); + break; + case OMPD_distribute_simd: + Res = ActOnOpenMPDistributeSimdDirective( + ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA); + break; + case OMPD_target_parallel_for_simd: + Res = ActOnOpenMPTargetParallelForSimdDirective( + 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: + case OMPD_declare_reduction: + case OMPD_declare_simd: llvm_unreachable("OpenMP Directive is not allowed"); case OMPD_unknown: llvm_unreachable("Unknown OpenMP directive"); @@ -2733,6 +3627,252 @@ StmtResult Sema::ActOnOpenMPExecutableDirective( return Res; } +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective( + DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen, + ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds, + ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears, + ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) { + assert(Aligneds.size() == Alignments.size()); + assert(Linears.size() == LinModifiers.size()); + assert(Linears.size() == Steps.size()); + if (!DG || DG.get().isNull()) + return DeclGroupPtrTy(); + + if (!DG.get().isSingleDecl()) { + Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd); + return DG; + } + auto *ADecl = DG.get().getSingleDecl(); + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl)) + ADecl = FTD->getTemplatedDecl(); + + auto *FD = dyn_cast<FunctionDecl>(ADecl); + if (!FD) { + Diag(ADecl->getLocation(), diag::err_omp_function_expected); + return DeclGroupPtrTy(); + } + + // OpenMP [2.8.2, declare simd construct, Description] + // The parameter of the simdlen clause must be a constant positive integer + // expression. + ExprResult SL; + if (Simdlen) + SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen); + // OpenMP [2.8.2, declare simd construct, Description] + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // The uniform clause declares one or more arguments to have an invariant + // value for all concurrent invocations of the function in the execution of a + // single SIMD loop. + llvm::DenseMap<Decl *, Expr *> UniformedArgs; + Expr *UniformedLinearThis = nullptr; + for (auto *E : Uniforms) { + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == PVD->getCanonicalDecl()) { + UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E)); + continue; + } + if (isa<CXXThisExpr>(E)) { + UniformedLinearThis = E; + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + // OpenMP [2.8.2, declare simd construct, Description] + // The aligned clause declares that the object to which each list item points + // is aligned to the number of bytes expressed in the optional parameter of + // the aligned clause. + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // The type of list items appearing in the aligned clause must be array, + // pointer, reference to array, or reference to pointer. + llvm::DenseMap<Decl *, Expr *> AlignedArgs; + Expr *AlignedThis = nullptr; + for (auto *E : Aligneds) { + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // OpenMP [2.8.1, simd construct, Restrictions] + // A list-item cannot appear in more than one aligned clause. + if (AlignedArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_aligned_twice) + << 1 << E->getSourceRange(); + Diag(AlignedArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_aligned); + continue; + } + AlignedArgs[CanonPVD] = E; + QualType QTy = PVD->getType() + .getNonReferenceType() + .getUnqualifiedType() + .getCanonicalType(); + const Type *Ty = QTy.getTypePtrOrNull(); + if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) { + Diag(E->getExprLoc(), diag::err_omp_aligned_expected_array_or_ptr) + << QTy << getLangOpts().CPlusPlus << E->getSourceRange(); + Diag(PVD->getLocation(), diag::note_previous_decl) << PVD; + } + continue; + } + } + if (isa<CXXThisExpr>(E)) { + if (AlignedThis) { + Diag(E->getExprLoc(), diag::err_omp_aligned_twice) + << 2 << E->getSourceRange(); + Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_aligned); + } + AlignedThis = E; + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + // The optional parameter of the aligned clause, alignment, must be a constant + // positive integer expression. If no optional parameter is specified, + // implementation-defined default alignments for SIMD instructions on the + // target platforms are assumed. + SmallVector<Expr *, 4> NewAligns; + for (auto *E : Alignments) { + ExprResult Align; + if (E) + Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned); + NewAligns.push_back(Align.get()); + } + // OpenMP [2.8.2, declare simd construct, Description] + // The linear clause declares one or more list items to be private to a SIMD + // lane and to have a linear relationship with respect to the iteration space + // of a loop. + // The special this pointer can be used as if was one of the arguments to the + // function in any of the linear, aligned, or uniform clauses. + // When a linear-step expression is specified in a linear clause it must be + // either a constant integer expression or an integer-typed parameter that is + // specified in a uniform clause on the directive. + llvm::DenseMap<Decl *, Expr *> LinearArgs; + const bool IsUniformedThis = UniformedLinearThis != nullptr; + auto MI = LinModifiers.begin(); + for (auto *E : Linears) { + auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI); + ++MI; + E = E->IgnoreParenImpCasts(); + if (auto *DRE = dyn_cast<DeclRefExpr>(E)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (FD->getNumParams() > PVD->getFunctionScopeIndex() && + FD->getParamDecl(PVD->getFunctionScopeIndex()) + ->getCanonicalDecl() == CanonPVD) { + // OpenMP [2.15.3.7, linear Clause, Restrictions] + // A list-item cannot appear in more than one linear clause. + if (LinearArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(OMPC_linear) << E->getSourceRange(); + Diag(LinearArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_linear); + continue; + } + // Each argument can appear in at most one uniform or linear clause. + if (UniformedArgs.count(CanonPVD) > 0) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(OMPC_uniform) << E->getSourceRange(); + Diag(UniformedArgs[CanonPVD]->getExprLoc(), + diag::note_omp_explicit_dsa) + << getOpenMPClauseName(OMPC_uniform); + continue; + } + LinearArgs[CanonPVD] = E; + if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || + E->containsUnexpandedParameterPack()) + continue; + (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind, + PVD->getOriginalType()); + continue; + } + } + if (isa<CXXThisExpr>(E)) { + if (UniformedLinearThis) { + Diag(E->getExprLoc(), diag::err_omp_wrong_dsa) + << getOpenMPClauseName(OMPC_linear) + << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear) + << E->getSourceRange(); + Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa) + << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform + : OMPC_linear); + continue; + } + UniformedLinearThis = E; + if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || E->containsUnexpandedParameterPack()) + continue; + (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind, + E->getType()); + continue; + } + Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause) + << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0); + } + Expr *Step = nullptr; + Expr *NewStep = nullptr; + SmallVector<Expr *, 4> NewSteps; + for (auto *E : Steps) { + // Skip the same step expression, it was checked already. + if (Step == E || !E) { + NewSteps.push_back(E ? NewStep : nullptr); + continue; + } + Step = E; + if (auto *DRE = dyn_cast<DeclRefExpr>(Step)) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + auto *CanonPVD = PVD->getCanonicalDecl(); + if (UniformedArgs.count(CanonPVD) == 0) { + Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param) + << Step->getSourceRange(); + } else if (E->isValueDependent() || E->isTypeDependent() || + E->isInstantiationDependent() || + E->containsUnexpandedParameterPack() || + CanonPVD->getType()->hasIntegerRepresentation()) + NewSteps.push_back(Step); + else { + Diag(Step->getExprLoc(), diag::err_omp_expected_int_param) + << Step->getSourceRange(); + } + continue; + } + NewStep = Step; + if (Step && !Step->isValueDependent() && !Step->isTypeDependent() && + !Step->isInstantiationDependent() && + !Step->containsUnexpandedParameterPack()) { + NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step) + .get(); + if (NewStep) + NewStep = VerifyIntegerConstantExpression(NewStep).get(); + } + NewSteps.push_back(NewStep); + } + auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit( + Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()), + Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(), + const_cast<Expr **>(NewAligns.data()), NewAligns.size(), + const_cast<Expr **>(Linears.data()), Linears.size(), + const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(), + NewSteps.data(), NewSteps.size(), SR); + ADecl->addAttr(NewAttr); + return ConvertDeclToDeclGroup(ADecl); +} + StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -2772,33 +3912,29 @@ class OpenMPIterationSpaceChecker { /// \brief A source location for referring to increment later. SourceRange IncrementSrcRange; /// \brief Loop variable. - VarDecl *Var; + ValueDecl *LCDecl = nullptr; /// \brief Reference to loop variable. - DeclRefExpr *VarRef; + Expr *LCRef = nullptr; /// \brief Lower bound (initializer for the var). - Expr *LB; + Expr *LB = nullptr; /// \brief Upper bound. - Expr *UB; + Expr *UB = nullptr; /// \brief Loop step (increment). - Expr *Step; + Expr *Step = nullptr; /// \brief This flag is true when condition is one of: /// Var < UB /// Var <= UB /// UB > Var /// UB >= Var - bool TestIsLessOp; + bool TestIsLessOp = false; /// \brief This flag is true when condition is strict ( < or > ). - bool TestIsStrictOp; + bool TestIsStrictOp = false; /// \brief This flag is true when step is subtracted on each iteration. - bool SubtractStep; + bool SubtractStep = false; public: OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc) - : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc), - InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()), - IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr), - LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false), - TestIsStrictOp(false), SubtractStep(false) {} + : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {} /// \brief Check init-expr for canonical loop form and save loop counter /// variable - #Var and its initialization value - #LB. bool CheckInit(Stmt *S, bool EmitDiags = true); @@ -2809,9 +3945,9 @@ public: /// does not conform, otherwise save loop step (#Step). bool CheckInc(Expr *S); /// \brief Return the loop counter variable. - VarDecl *GetLoopVar() const { return Var; } + ValueDecl *GetLoopDecl() const { return LCDecl; } /// \brief Return the reference expression to loop counter variable. - DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; } + Expr *GetLoopDeclRefExpr() const { return LCRef; } /// \brief Source range of the loop init. SourceRange GetInitSrcRange() const { return InitSrcRange; } /// \brief Source range of the loop condition. @@ -2821,11 +3957,15 @@ public: /// \brief True if the step should be subtracted. bool ShouldSubtractStep() const { return SubtractStep; } /// \brief Build the expression to calculate the number of iterations. - Expr *BuildNumIterations(Scope *S, const bool LimitedType) const; + Expr * + BuildNumIterations(Scope *S, const bool LimitedType, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; /// \brief Build the precondition expression for the loops. - Expr *BuildPreCond(Scope *S, Expr *Cond) const; + Expr *BuildPreCond(Scope *S, Expr *Cond, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const; /// \brief Build reference expression to the counter be used for codegen. - Expr *BuildCounterVar() const; + DeclRefExpr *BuildCounterVar(llvm::MapVector<Expr *, DeclRefExpr *> &Captures, + DSAStackTy &DSA) const; /// \brief Build reference expression to the private counter be used for /// codegen. Expr *BuildPrivateCounterVar() const; @@ -2841,7 +3981,7 @@ private: /// expression. bool CheckIncRHS(Expr *RHS); /// \brief Helper to set loop counter variable and its initializer. - bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB); + bool SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB); /// \brief Helper to set upper bound. bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL); @@ -2850,16 +3990,16 @@ private: }; bool OpenMPIterationSpaceChecker::Dependent() const { - if (!Var) { + if (!LCDecl) { assert(!LB && !UB && !Step); return false; } - return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) || - (UB && UB->isValueDependent()) || (Step && Step->isValueDependent()); + return LCDecl->getType()->isDependentType() || + (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) || + (Step && Step->isValueDependent()); } -template <typename T> -static T *getExprAsWritten(T *E) { +static Expr *getExprAsWritten(Expr *E) { if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E)) E = ExprTemp->getSubExpr(); @@ -2874,16 +4014,16 @@ static T *getExprAsWritten(T *E) { return E->IgnoreParens(); } -bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, - DeclRefExpr *NewVarRefExpr, - Expr *NewLB) { +bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl, + Expr *NewLCRefExpr, + Expr *NewLB) { // State consistency checking to ensure correct usage. - assert(Var == nullptr && LB == nullptr && VarRef == nullptr && + assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr && UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp); - if (!NewVar || !NewLB) + if (!NewLCDecl || !NewLB) return true; - Var = NewVar; - VarRef = NewVarRefExpr; + LCDecl = getCanonicalDecl(NewLCDecl); + LCRef = NewLCRefExpr; if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(NewLB)) if (const CXXConstructorDecl *Ctor = CE->getConstructor()) if ((Ctor->isCopyOrMoveConstructor() || @@ -2897,8 +4037,8 @@ bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar, bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR, SourceLocation SL) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr && - !TestIsLessOp && !TestIsStrictOp); + assert(LCDecl != nullptr && LB != nullptr && UB == nullptr && + Step == nullptr && !TestIsLessOp && !TestIsStrictOp); if (!NewUB) return true; UB = NewUB; @@ -2911,7 +4051,7 @@ bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp, bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { // State consistency checking to ensure correct usage. - assert(Var != nullptr && LB != nullptr && Step == nullptr); + assert(LCDecl != nullptr && LB != nullptr && Step == nullptr); if (!NewStep) return true; if (!NewStep->isValueDependent()) { @@ -2947,7 +4087,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) { : (IsConstPos || (IsUnsigned && !Subtract))))) { SemaRef.Diag(NewStep->getExprLoc(), diag::err_omp_loop_incr_not_compatible) - << Var << TestIsLessOp << NewStep->getSourceRange(); + << LCDecl << TestIsLessOp << NewStep->getSourceRange(); SemaRef.Diag(ConditionLoc, diag::note_omp_loop_cond_requres_compatible_incr) << TestIsLessOp << ConditionSrcRange; @@ -2980,14 +4120,28 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { } return true; } + if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S)) + if (!ExprTemp->cleanupsHaveSideEffects()) + S = ExprTemp->getSubExpr(); + InitSrcRange = S->getSourceRange(); if (Expr *E = dyn_cast<Expr>(S)) S = E->IgnoreParens(); if (auto BO = dyn_cast<BinaryOperator>(S)) { - if (BO->getOpcode() == BO_Assign) - if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens())) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, - BO->getRHS()); + if (BO->getOpcode() == BO_Assign) { + auto *LHS = BO->getLHS()->IgnoreParens(); + 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()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS()); + } + if (auto *ME = dyn_cast<MemberExpr>(LHS)) { + if (ME->isArrow() && + isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } } else if (auto DS = dyn_cast<DeclStmt>(S)) { if (DS->isSingleDecl()) { if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) { @@ -2997,16 +4151,29 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::ext_omp_loop_not_canonical_init) << S->getSourceRange(); - return SetVarAndLB(Var, nullptr, Var->getInit()); + return SetLCDeclAndLB(Var, nullptr, Var->getInit()); } } } - } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) - if (CE->getOperator() == OO_Equal) - if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0))) - return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE, - CE->getArg(1)); + } 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 *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl())) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + return SetLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1)); + } + if (auto *ME = dyn_cast<MemberExpr>(LHS)) { + if (ME->isArrow() && + isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS()); + } + } + } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; if (EmitDiags) { SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init) << S->getSourceRange(); @@ -3016,7 +4183,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) { /// \brief Ignore parenthesizes, implicit casts, copy constructor and return the /// variable (which may be the loop variable) if possible. -static const VarDecl *GetInitVarDecl(const Expr *E) { +static const ValueDecl *GetInitLCDecl(Expr *E) { if (!E) return nullptr; E = getExprAsWritten(E); @@ -3026,10 +4193,18 @@ static const VarDecl *GetInitVarDecl(const Expr *E) { Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) && CE->getNumArgs() > 0 && CE->getArg(0) != nullptr) E = CE->getArg(0)->IgnoreParenImpCasts(); - auto DRE = dyn_cast_or_null<DeclRefExpr>(E); - if (!DRE) - return nullptr; - return dyn_cast<VarDecl>(DRE->getDecl()); + if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) { + if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) { + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD)) + if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit()))) + return getCanonicalDecl(ME->getMemberDecl()); + return getCanonicalDecl(VD); + } + } + if (auto *ME = dyn_cast_or_null<MemberExpr>(E)) + if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts())) + return getCanonicalDecl(ME->getMemberDecl()); + return nullptr; } bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { @@ -3040,19 +4215,19 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { // b relational-op var // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl; return true; } S = getExprAsWritten(S); SourceLocation CondLoc = S->getLocStart(); if (auto BO = dyn_cast<BinaryOperator>(S)) { if (BO->isRelationalOp()) { - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetUB(BO->getRHS(), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), BO->getSourceRange(), BO->getOperatorLoc()); - if (GetInitVarDecl(BO->getRHS()) == Var) + if (GetInitLCDecl(BO->getRHS()) == LCDecl) return SetUB(BO->getLHS(), (BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE), (BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT), @@ -3066,11 +4241,11 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { case OO_GreaterEqual: case OO_Less: case OO_LessEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); - if (GetInitVarDecl(CE->getArg(1)) == Var) + if (GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual, Op == OO_Less || Op == OO_Greater, CE->getSourceRange(), CE->getOperatorLoc()); @@ -3080,8 +4255,10 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) { } } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } @@ -3095,22 +4272,24 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) { if (auto BO = dyn_cast<BinaryOperator>(RHS)) { if (BO->isAdditiveOp()) { bool IsAdd = BO->getOpcode() == BO_Add; - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), !IsAdd); - if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var) + if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl) return SetStep(BO->getLHS(), false); } } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) { bool IsAdd = CE->getOperator() == OO_Plus; if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) { - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), !IsAdd); - if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var) + if (IsAdd && GetInitLCDecl(CE->getArg(1)) == LCDecl) return SetStep(CE->getArg(0), false); } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << RHS->getSourceRange() << Var; + << RHS->getSourceRange() << LCDecl; return true; } @@ -3129,13 +4308,18 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { // var = var - incr // if (!S) { - SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var; + SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << LCDecl; return true; } + if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S)) + if (!ExprTemp->cleanupsHaveSideEffects()) + S = ExprTemp->getSubExpr(); + IncrementSrcRange = S->getSourceRange(); S = S->IgnoreParens(); if (auto UO = dyn_cast<UnaryOperator>(S)) { - if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var) + if (UO->isIncrementDecrementOp() && + GetInitLCDecl(UO->getSubExpr()) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant(UO->getLocStart(), (UO->isDecrementOp() ? -1 : 1)).get(), @@ -3144,11 +4328,11 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (BO->getOpcode()) { case BO_AddAssign: case BO_SubAssign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign); break; case BO_Assign: - if (GetInitVarDecl(BO->getLHS()) == Var) + if (GetInitLCDecl(BO->getLHS()) == LCDecl) return CheckIncRHS(BO->getRHS()); break; default: @@ -3158,7 +4342,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { switch (CE->getOperator()) { case OO_PlusPlus: case OO_MinusMinus: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep( SemaRef.ActOnIntegerConstant( CE->getLocStart(), @@ -3167,103 +4351,55 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) { break; case OO_PlusEqual: case OO_MinusEqual: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual); break; case OO_Equal: - if (GetInitVarDecl(CE->getArg(0)) == Var) + if (GetInitLCDecl(CE->getArg(0)) == LCDecl) return CheckIncRHS(CE->getArg(1)); break; default: break; } } + if (Dependent() || SemaRef.CurContext->isDependentContext()) + return false; SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr) - << S->getSourceRange() << Var; + << S->getSourceRange() << LCDecl; return true; } -namespace { -// Transform variables declared in GNU statement expressions to new ones to -// avoid crash on codegen. -class TransformToNewDefs : public TreeTransform<TransformToNewDefs> { - typedef TreeTransform<TransformToNewDefs> BaseTransform; - -public: - TransformToNewDefs(Sema &SemaRef) : BaseTransform(SemaRef) {} - - Decl *TransformDefinition(SourceLocation Loc, Decl *D) { - if (auto *VD = cast<VarDecl>(D)) - if (!isa<ParmVarDecl>(D) && !isa<VarTemplateSpecializationDecl>(D) && - !isa<ImplicitParamDecl>(D)) { - auto *NewVD = VarDecl::Create( - SemaRef.Context, VD->getDeclContext(), VD->getLocStart(), - VD->getLocation(), VD->getIdentifier(), VD->getType(), - VD->getTypeSourceInfo(), VD->getStorageClass()); - NewVD->setTSCSpec(VD->getTSCSpec()); - NewVD->setInit(VD->getInit()); - NewVD->setInitStyle(VD->getInitStyle()); - NewVD->setExceptionVariable(VD->isExceptionVariable()); - NewVD->setNRVOVariable(VD->isNRVOVariable()); - NewVD->setCXXForRangeDecl(VD->isCXXForRangeDecl()); - NewVD->setConstexpr(VD->isConstexpr()); - NewVD->setInitCapture(VD->isInitCapture()); - NewVD->setPreviousDeclInSameBlockScope( - VD->isPreviousDeclInSameBlockScope()); - VD->getDeclContext()->addHiddenDecl(NewVD); - if (VD->hasAttrs()) - NewVD->setAttrs(VD->getAttrs()); - transformedLocalDecl(VD, NewVD); - return NewVD; - } - return BaseTransform::TransformDefinition(Loc, D); - } - - ExprResult TransformDeclRefExpr(DeclRefExpr *E) { - if (auto *NewD = TransformDecl(E->getExprLoc(), E->getDecl())) - if (E->getDecl() != NewD) { - NewD->setReferenced(); - NewD->markUsed(SemaRef.Context); - return DeclRefExpr::Create( - SemaRef.Context, E->getQualifierLoc(), E->getTemplateKeywordLoc(), - cast<ValueDecl>(NewD), E->refersToEnclosingVariableOrCapture(), - E->getNameInfo(), E->getType(), E->getValueKind()); - } - return BaseTransform::TransformDeclRefExpr(E); - } -}; +static ExprResult +tryBuildCapture(Sema &SemaRef, Expr *Capture, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + if (SemaRef.CurContext->isDependentContext()) + return ExprResult(Capture); + if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects)) + return SemaRef.PerformImplicitConversion( + Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting, + /*AllowExplicit=*/true); + auto I = Captures.find(Capture); + if (I != Captures.end()) + return buildCapture(SemaRef, Capture, I->second); + DeclRefExpr *Ref = nullptr; + ExprResult Res = buildCapture(SemaRef, Capture, Ref); + Captures[Capture] = Ref; + return Res; } /// \brief Build the expression to calculate the number of iterations. -Expr * -OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, - const bool LimitedType) const { - TransformToNewDefs Transform(SemaRef); +Expr *OpenMPIterationSpaceChecker::BuildNumIterations( + Scope *S, const bool LimitedType, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { ExprResult Diff; - auto VarType = Var->getType().getNonReferenceType(); + auto VarType = LCDecl->getType().getNonReferenceType(); if (VarType->isIntegerType() || VarType->isPointerType() || SemaRef.getLangOpts().CPlusPlus) { // Upper - Lower auto *UBExpr = TestIsLessOp ? UB : LB; auto *LBExpr = TestIsLessOp ? LB : UB; - Expr *Upper = Transform.TransformExpr(UBExpr).get(); - Expr *Lower = Transform.TransformExpr(LBExpr).get(); - if (!Upper || !Lower) - return nullptr; - if (!SemaRef.Context.hasSameType(Upper->getType(), UBExpr->getType())) { - Upper = SemaRef - .PerformImplicitConversion(Upper, UBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); - } - if (!SemaRef.Context.hasSameType(Lower->getType(), LBExpr->getType())) { - Lower = SemaRef - .PerformImplicitConversion(Lower, LBExpr->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true) - .get(); - } + Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get(); + Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get(); if (!Upper || !Lower) return nullptr; @@ -3290,18 +4426,9 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return nullptr; // Upper - Lower [- 1] + Step - auto *StepNoImp = Step->IgnoreImplicit(); - auto NewStep = Transform.TransformExpr(StepNoImp); - if (NewStep.isInvalid()) + auto NewStep = tryBuildCapture(SemaRef, Step, Captures); + if (!NewStep.isUsable()) return nullptr; - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; - } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; @@ -3312,17 +4439,6 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return nullptr; // (Upper - Lower [- 1] + Step) / Step - NewStep = Transform.TransformExpr(StepNoImp); - if (NewStep.isInvalid()) - return nullptr; - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return nullptr; - } Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get()); if (!Diff.isUsable()) return nullptr; @@ -3368,35 +4484,25 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S, return Diff.get(); } -Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { +Expr *OpenMPIterationSpaceChecker::BuildPreCond( + Scope *S, Expr *Cond, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const { // Try to build LB <op> UB, where <op> is <, >, <=, or >=. bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); - TransformToNewDefs Transform(SemaRef); - - auto NewLB = Transform.TransformExpr(LB); - auto NewUB = Transform.TransformExpr(UB); - if (NewLB.isInvalid() || NewUB.isInvalid()) - return Cond; - if (!SemaRef.Context.hasSameType(NewLB.get()->getType(), LB->getType())) { - NewLB = SemaRef.PerformImplicitConversion(NewLB.get(), LB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - } - if (!SemaRef.Context.hasSameType(NewUB.get()->getType(), UB->getType())) { - NewUB = SemaRef.PerformImplicitConversion(NewUB.get(), UB->getType(), - Sema::AA_Converting, - /*AllowExplicit=*/true); - } - if (NewLB.isInvalid() || NewUB.isInvalid()) - return Cond; + + auto NewLB = tryBuildCapture(SemaRef, LB, Captures); + auto NewUB = tryBuildCapture(SemaRef, UB, Captures); + if (!NewLB.isUsable() || !NewUB.isUsable()) + return nullptr; + auto CondExpr = SemaRef.BuildBinOp( S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE) : (TestIsStrictOp ? BO_GT : BO_GE), NewLB.get(), NewUB.get()); if (CondExpr.isUsable()) { - if (!SemaRef.Context.hasSameType(CondExpr.get()->getType(), - SemaRef.Context.BoolTy)) + if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(), + SemaRef.Context.BoolTy)) CondExpr = SemaRef.PerformImplicitConversion( CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting, /*AllowExplicit=*/true); @@ -3407,17 +4513,30 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const { } /// \brief Build reference expression to the counter be used for codegen. -Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const { - return buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(), +DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar( + llvm::MapVector<Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const { + auto *VD = dyn_cast<VarDecl>(LCDecl); + if (!VD) { + VD = SemaRef.IsOpenMPCapturedDecl(LCDecl); + auto *Ref = buildDeclRefExpr( + SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); + DSAStackTy::DSAVarData Data = DSA.getTopDSA(LCDecl, /*FromParent=*/false); + // If the loop control decl is explicitly marked as private, do not mark it + // as captured again. + if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr) + Captures.insert(std::make_pair(LCRef, Ref)); + return Ref; + } + return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc); } Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const { - if (Var && !Var->isInvalidDecl()) { - auto Type = Var->getType().getNonReferenceType(); + if (LCDecl && !LCDecl->isInvalidDecl()) { + auto Type = LCDecl->getType().getNonReferenceType(); auto *PrivateVar = - buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(), - Var->hasAttrs() ? &Var->getAttrs() : nullptr); + buildVarDecl(SemaRef, DefaultLoc, Type, LCDecl->getName(), + LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr); if (PrivateVar->isInvalidDecl()) return nullptr; return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc); @@ -3432,23 +4551,23 @@ Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; } Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; } /// \brief Iteration space of a single for loop. -struct LoopIterationSpace { +struct LoopIterationSpace final { /// \brief Condition of the loop. - Expr *PreCond; + Expr *PreCond = nullptr; /// \brief This expression calculates the number of iterations in the loop. /// It is always possible to calculate it before starting the loop. - Expr *NumIterations; + Expr *NumIterations = nullptr; /// \brief The loop counter variable. - Expr *CounterVar; + Expr *CounterVar = nullptr; /// \brief Private loop counter variable. - Expr *PrivateCounterVar; + Expr *PrivateCounterVar = nullptr; /// \brief This is initializer for the initial value of #CounterVar. - Expr *CounterInit; + Expr *CounterInit = nullptr; /// \brief This is step for the #CounterVar used to generate its update: /// #CounterVar = #CounterInit + #CounterStep * CurrentIteration. - Expr *CounterStep; + Expr *CounterStep = nullptr; /// \brief Should step be subtracted? - bool Subtract; + bool Subtract = false; /// \brief Source range of the loop init. SourceRange InitSrcRange; /// \brief Source range of the loop condition. @@ -3466,8 +4585,21 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) { if (AssociatedLoops > 0 && isOpenMPLoopDirective(DSAStack->getCurrentDirective())) { OpenMPIterationSpaceChecker ISC(*this, ForLoc); - if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) - DSAStack->addLoopControlVariable(ISC.GetLoopVar()); + if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) { + if (auto *D = ISC.GetLoopDecl()) { + auto *VD = dyn_cast<VarDecl>(D); + if (!VD) { + if (auto *Private = IsOpenMPCapturedDecl(D)) + VD = Private; + else { + auto *Ref = buildCapture(*this, D, ISC.GetLoopDeclRefExpr(), + /*WithInit=*/false); + VD = cast<VarDecl>(Ref->getDecl()); + } + } + DSAStack->addLoopControlVariable(D, VD); + } + } DSAStack->setAssociatedLoops(AssociatedLoops - 1); } } @@ -3478,8 +4610,9 @@ static bool CheckOpenMPIterationSpace( OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA, unsigned CurrentNestedLoopCount, unsigned NestedLoopCount, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, - LoopIterationSpace &ResultIterSpace) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, + LoopIterationSpace &ResultIterSpace, + 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); @@ -3511,98 +4644,102 @@ static bool CheckOpenMPIterationSpace( // Check init. auto Init = For->getInit(); - if (ISC.CheckInit(Init)) { + if (ISC.CheckInit(Init)) return true; - } bool HasErrors = false; // Check loop variable's type. - auto Var = ISC.GetLoopVar(); + if (auto *LCDecl = ISC.GetLoopDecl()) { + auto *LoopDeclRefExpr = ISC.GetLoopDeclRefExpr(); + + // OpenMP [2.6, Canonical Loop Form] + // Var is one of the following: + // A variable of signed or unsigned integer type. + // For C++, a variable of a random access iterator type. + // For C, a variable of a pointer type. + auto VarType = LCDecl->getType().getNonReferenceType(); + if (!VarType->isDependentType() && !VarType->isIntegerType() && + !VarType->isPointerType() && + !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) + << SemaRef.getLangOpts().CPlusPlus; + HasErrors = true; + } - // OpenMP [2.6, Canonical Loop Form] - // Var is one of the following: - // A variable of signed or unsigned integer type. - // For C++, a variable of a random access iterator type. - // For C, a variable of a pointer type. - auto VarType = Var->getType().getNonReferenceType(); - if (!VarType->isDependentType() && !VarType->isIntegerType() && - !VarType->isPointerType() && - !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type) - << SemaRef.getLangOpts().CPlusPlus; - HasErrors = true; - } - - // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a - // Construct - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct is (are) private. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop is linear with a constant-linear-step - // that is the increment of the associated for-loop. - // Exclude loop var from the list of variables with implicitly defined data - // sharing attributes. - VarsWithImplicitDSA.erase(Var); - - // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in - // a Construct, C/C++]. - // The loop iteration variable in the associated for-loop of a simd construct - // with just one associated for-loop may be listed in a linear clause with a - // constant-linear-step that is the increment of the associated for-loop. - // The loop iteration variable(s) in the associated for-loop(s) of a for or - // parallel for construct may be listed in a private or lastprivate clause. - DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false); - auto LoopVarRefExpr = ISC.GetLoopVarRefExpr(); - // If LoopVarRefExpr is nullptr it means the corresponding loop variable is - // declared in the loop and it is predetermined as a private. - auto PredeterminedCKind = - isOpenMPSimdDirective(DKind) - ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) - : OMPC_private; - if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != PredeterminedCKind) || - ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || - isOpenMPDistributeDirective(DKind)) && - !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && - DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && - (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { - SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) - << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) - << getOpenMPClauseName(PredeterminedCKind); - if (DVar.RefExpr == nullptr) - DVar.CKind = PredeterminedCKind; - ReportOriginalDSA(SemaRef, &DSA, Var, DVar, /*IsLoopIterVar=*/true); - HasErrors = true; - } else if (LoopVarRefExpr != nullptr) { - // Make the loop iteration variable private (for worksharing constructs), - // linear (for simd directives with the only one associated loop) or - // lastprivate (for simd directives with several collapsed or ordered - // loops). - if (DVar.CKind == OMPC_unknown) - DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(), - /*FromParent=*/false); - DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind); - } - - assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); - - // Check test-expr. - HasErrors |= ISC.CheckCond(For->getCond()); - - // Check incr-expr. - HasErrors |= ISC.CheckInc(For->getInc()); + // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in + // a Construct + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct is (are) private. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop is linear with a + // constant-linear-step that is the increment of the associated for-loop. + // Exclude loop var from the list of variables with implicitly defined data + // sharing attributes. + VarsWithImplicitDSA.erase(LCDecl); + + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced + // in a Construct, C/C++]. + // The loop iteration variable in the associated for-loop of a simd + // construct with just one associated for-loop may be listed in a linear + // clause with a constant-linear-step that is the increment of the + // associated for-loop. + // The loop iteration variable(s) in the associated for-loop(s) of a for or + // parallel for construct may be listed in a private or lastprivate clause. + DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false); + // If LoopVarRefExpr is nullptr it means the corresponding loop variable is + // declared in the loop and it is predetermined as a private. + auto PredeterminedCKind = + isOpenMPSimdDirective(DKind) + ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate) + : OMPC_private; + if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != PredeterminedCKind) || + ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop || + isOpenMPDistributeDirective(DKind)) && + !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown && + DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) && + (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { + SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa) + << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind) + << getOpenMPClauseName(PredeterminedCKind); + if (DVar.RefExpr == nullptr) + DVar.CKind = PredeterminedCKind; + ReportOriginalDSA(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true); + HasErrors = true; + } else if (LoopDeclRefExpr != nullptr) { + // Make the loop iteration variable private (for worksharing constructs), + // linear (for simd directives with the only one associated loop) or + // lastprivate (for simd directives with several collapsed or ordered + // loops). + if (DVar.CKind == OMPC_unknown) + DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate, + [](OpenMPDirectiveKind) -> bool { return true; }, + /*FromParent=*/false); + DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind); + } + + assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars"); + + // Check test-expr. + HasErrors |= ISC.CheckCond(For->getCond()); + + // Check incr-expr. + HasErrors |= ISC.CheckInc(For->getInc()); + } if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors) return HasErrors; // Build the loop's iteration space representation. - ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond()); + ResultIterSpace.PreCond = + ISC.BuildPreCond(DSA.getCurScope(), For->getCond(), Captures); ResultIterSpace.NumIterations = ISC.BuildNumIterations( - DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) || - isOpenMPTaskLoopDirective(DKind) || - isOpenMPDistributeDirective(DKind))); - ResultIterSpace.CounterVar = ISC.BuildCounterVar(); + DSA.getCurScope(), + (isOpenMPWorksharingDirective(DKind) || + isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)), + Captures); + ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures, DSA); ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar(); ResultIterSpace.CounterInit = ISC.BuildCounterInit(); ResultIterSpace.CounterStep = ISC.BuildCounterStep(); @@ -3622,23 +4759,15 @@ static bool CheckOpenMPIterationSpace( } /// \brief Build 'VarRef = Start. -static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, - ExprResult VarRef, ExprResult Start) { - TransformToNewDefs Transform(SemaRef); +static ExprResult +BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef, + ExprResult Start, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { // Build 'VarRef = Start. - auto *StartNoImp = Start.get()->IgnoreImplicit(); - auto NewStart = Transform.TransformExpr(StartNoImp); - if (NewStart.isInvalid()) + auto NewStart = tryBuildCapture(SemaRef, Start.get(), Captures); + if (!NewStart.isUsable()) return ExprError(); if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), - StartNoImp->getType())) { - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); - } - if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), VarRef.get()->getType())) { NewStart = SemaRef.PerformImplicitConversion( NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting, @@ -3653,58 +4782,74 @@ static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, } /// \brief Build 'VarRef = Start + Iter * Step'. -static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S, - SourceLocation Loc, ExprResult VarRef, - ExprResult Start, ExprResult Iter, - ExprResult Step, bool Subtract) { +static ExprResult +BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc, + ExprResult VarRef, ExprResult Start, ExprResult Iter, + ExprResult Step, bool Subtract, + llvm::MapVector<Expr *, DeclRefExpr *> *Captures = nullptr) { // Add parentheses (for debugging purposes only). Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get()); if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() || !Step.isUsable()) return ExprError(); - auto *StepNoImp = Step.get()->IgnoreImplicit(); - TransformToNewDefs Transform(SemaRef); - auto NewStep = Transform.TransformExpr(StepNoImp); + ExprResult NewStep = Step; + if (Captures) + NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures); if (NewStep.isInvalid()) return ExprError(); - if (!SemaRef.Context.hasSameType(NewStep.get()->getType(), - StepNoImp->getType())) { - NewStep = SemaRef.PerformImplicitConversion( - NewStep.get(), StepNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStep.isInvalid()) - return ExprError(); - } ExprResult Update = SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), NewStep.get()); if (!Update.isUsable()) return ExprError(); - // Build 'VarRef = Start + Iter * Step'. - auto *StartNoImp = Start.get()->IgnoreImplicit(); - auto NewStart = Transform.TransformExpr(StartNoImp); + // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or + // 'VarRef = Start (+|-) Iter * Step'. + ExprResult NewStart = Start; + if (Captures) + NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures); if (NewStart.isInvalid()) return ExprError(); - if (!SemaRef.Context.hasSameType(NewStart.get()->getType(), - StartNoImp->getType())) { - NewStart = SemaRef.PerformImplicitConversion( - NewStart.get(), StartNoImp->getType(), Sema::AA_Converting, - /*AllowExplicit=*/true); - if (NewStart.isInvalid()) - return ExprError(); + + // First attempt: try to build 'VarRef = Start, VarRef += Iter * Step'. + ExprResult SavedUpdate = Update; + ExprResult UpdateVal; + if (VarRef.get()->getType()->isOverloadableType() || + NewStart.get()->getType()->isOverloadableType() || + Update.get()->getType()->isOverloadableType()) { + bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics(); + SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true); + Update = + SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get()); + if (Update.isUsable()) { + UpdateVal = + SemaRef.BuildBinOp(S, Loc, Subtract ? BO_SubAssign : BO_AddAssign, + VarRef.get(), SavedUpdate.get()); + if (UpdateVal.isUsable()) { + Update = SemaRef.CreateBuiltinBinOp(Loc, BO_Comma, Update.get(), + UpdateVal.get()); + } + } + SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress); } - Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add), - NewStart.get(), Update.get()); - if (!Update.isUsable()) - return ExprError(); - Update = SemaRef.PerformImplicitConversion( - Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); - if (!Update.isUsable()) - return ExprError(); + // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'. + if (!Update.isUsable() || !UpdateVal.isUsable()) { + Update = SemaRef.BuildBinOp(S, Loc, Subtract ? BO_Sub : BO_Add, + NewStart.get(), SavedUpdate.get()); + if (!Update.isUsable()) + return ExprError(); + + if (!SemaRef.Context.hasSameType(Update.get()->getType(), + VarRef.get()->getType())) { + Update = SemaRef.PerformImplicitConversion( + Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true); + if (!Update.isUsable()) + return ExprError(); + } - Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + } return Update; } @@ -3736,6 +4881,49 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) { return false; } +/// Build preinits statement for the given declarations. +static Stmt *buildPreInits(ASTContext &Context, + SmallVectorImpl<Decl *> &PreInits) { + if (!PreInits.empty()) { + return new (Context) DeclStmt( + DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()), + SourceLocation(), SourceLocation()); + } + return nullptr; +} + +/// Build preinits statement for the given declarations. +static Stmt *buildPreInits(ASTContext &Context, + llvm::MapVector<Expr *, DeclRefExpr *> &Captures) { + if (!Captures.empty()) { + SmallVector<Decl *, 16> PreInits; + for (auto &Pair : Captures) + PreInits.push_back(Pair.second->getDecl()); + return buildPreInits(Context, PreInits); + } + return nullptr; +} + +/// Build postupdate expression for the given list of postupdates expressions. +static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) { + Expr *PostUpdate = nullptr; + if (!PostUpdates.empty()) { + for (auto *E : PostUpdates) { + Expr *ConvE = S.BuildCStyleCastExpr( + E->getExprLoc(), + S.Context.getTrivialTypeSourceInfo(S.Context.VoidTy), + E->getExprLoc(), E) + .get(); + PostUpdate = PostUpdate + ? S.CreateBuiltinBinOp(ConvE->getExprLoc(), BO_Comma, + PostUpdate, ConvE) + .get() + : ConvE; + } + } + return PostUpdate; +} + /// \brief Called on a for stmt to check itself and nested loops (if any). /// \return Returns 0 if one of the collapsed stmts is not canonical for loop, /// number of collapsed loops otherwise. @@ -3743,7 +4931,7 @@ static unsigned CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef, DSAStackTy &DSA, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA, + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA, OMPLoopDirective::HelperExprs &Built) { unsigned NestedLoopCount = 1; if (CollapseLoopCountExpr) { @@ -3769,6 +4957,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // This is helper routine for loop directives (e.g., 'for', 'simd', // 'for simd', etc.). + llvm::MapVector<Expr *, DeclRefExpr *> Captures; SmallVector<LoopIterationSpace, 4> IterSpaces; IterSpaces.resize(NestedLoopCount); Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true); @@ -3776,7 +4965,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt, NestedLoopCount, CollapseLoopCountExpr, OrderedLoopCountExpr, VarsWithImplicitDSA, - IterSpaces[Cnt])) + IterSpaces[Cnt], Captures)) return 0; // Move on to the next nested for loop, or to the loop body. // OpenMP [2.8.1, simd construct, Restrictions] @@ -3877,6 +5066,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, LastIteration32.get()->getType()->hasSignedIntegerRepresentation(), LastIteration64.get(), SemaRef))) LastIteration = LastIteration32; + QualType VType = LastIteration.get()->getType(); + QualType RealVType = VType; + QualType StrideVType = VType; + if (isOpenMPTaskLoopDirective(DKind)) { + VType = + SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0); + StrideVType = + SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1); + } if (!LastIteration.isUsable()) return 0; @@ -3898,19 +5096,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context); ExprResult CalcLastIteration; if (!IsConstant) { - SourceLocation SaveLoc; - VarDecl *SaveVar = - buildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(), - ".omp.last.iteration"); - ExprResult SaveRef = buildDeclRefExpr( - SemaRef, SaveVar, LastIteration.get()->getType(), SaveLoc); - CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign, - SaveRef.get(), LastIteration.get()); + ExprResult SaveRef = + tryBuildCapture(SemaRef, LastIteration.get(), Captures); LastIteration = SaveRef; // Prepare SaveRef + 1. NumIterations = SemaRef.BuildBinOp( - CurScope, SaveLoc, BO_Add, SaveRef.get(), + CurScope, SourceLocation(), BO_Add, SaveRef.get(), SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get()); if (!NumIterations.isUsable()) return 0; @@ -3918,9 +5110,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin(); - QualType VType = LastIteration.get()->getType(); // Build variables passed into runtime, nesessary for worksharing directives. - ExprResult LB, UB, IL, ST, EUB; + ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB; if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) { // Lower bound variable, initialized with zero. @@ -3947,8 +5138,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, /*DirectInit*/ false, /*TypeMayContainAuto*/ false); // Stride variable returned by runtime (we initialize it to 1 by default). - VarDecl *STDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.stride"); - ST = buildDeclRefExpr(SemaRef, STDecl, VType, InitLoc); + VarDecl *STDecl = + buildVarDecl(SemaRef, InitLoc, StrideVType, ".omp.stride"); + ST = buildDeclRefExpr(SemaRef, STDecl, StrideVType, InitLoc); SemaRef.AddInitializerToDecl( STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(), /*DirectInit*/ false, /*TypeMayContainAuto*/ false); @@ -3962,14 +5154,39 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(), CondOp.get()); EUB = SemaRef.ActOnFinishFullExpr(EUB.get()); + + // If we have a combined directive that combines 'distribute', 'for' or + // 'simd' we need to be able to access the bounds of the schedule of the + // enclosing region. E.g. in 'distribute parallel for' the bounds obtained + // by scheduling 'distribute' have to be passed to the schedule of 'for'. + if (isOpenMPLoopBoundSharingDirective(DKind)) { + auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl(); + + // We expect to have at least 2 more parameters than the 'parallel' + // directive does - the lower and upper bounds of the previous schedule. + assert(CD->getNumParams() >= 4 && + "Unexpected number of parameters in loop combined directive"); + + // Set the proper type for the bounds given what we learned from the + // enclosed loops. + auto *PrevLBDecl = CD->getParam(/*PrevLB=*/2); + auto *PrevUBDecl = CD->getParam(/*PrevUB=*/3); + + // Previous lower and upper bounds are obtained from the region + // parameters. + PrevLB = + buildDeclRefExpr(SemaRef, PrevLBDecl, PrevLBDecl->getType(), InitLoc); + PrevUB = + buildDeclRefExpr(SemaRef, PrevUBDecl, PrevUBDecl->getType(), InitLoc); + } } // Build the iteration variable and its initialization before loop. ExprResult IV; ExprResult Init; { - VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv"); - IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc); + VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv"); + IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc); Expr *RHS = (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)) @@ -4033,6 +5250,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.Inits.resize(NestedLoopCount); Built.Updates.resize(NestedLoopCount); Built.Finals.resize(NestedLoopCount); + SmallVector<Expr *, 4> LoopMultipliers; { ExprResult Div; // Go from inner nested loop to outer. @@ -4060,19 +5278,19 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, } // Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step - auto *CounterVar = buildDeclRefExpr( - SemaRef, cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()), - IS.CounterVar->getType(), IS.CounterVar->getExprLoc(), - /*RefersToCapture=*/true); + auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()); + auto *CounterVar = buildDeclRefExpr(SemaRef, VD, IS.CounterVar->getType(), + IS.CounterVar->getExprLoc(), + /*RefersToCapture=*/true); ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit); + IS.CounterInit, Captures); if (!Init.isUsable()) { HasErrors = true; break; } - ExprResult Update = - BuildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar, - IS.CounterInit, Iter, IS.CounterStep, IS.Subtract); + ExprResult Update = BuildCounterUpdate( + SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter, + IS.CounterStep, IS.Subtract, &Captures); if (!Update.isUsable()) { HasErrors = true; break; @@ -4081,7 +5299,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step ExprResult Final = BuildCounterUpdate( SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, - IS.NumIterations, IS.CounterStep, IS.Subtract); + IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures); if (!Final.isUsable()) { HasErrors = true; break; @@ -4097,11 +5315,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, // Add parentheses (for debugging purposes only). if (Div.isUsable()) - Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get()); + Div = tryBuildCapture(SemaRef, Div.get(), Captures); if (!Div.isUsable()) { HasErrors = true; break; } + LoopMultipliers.push_back(Div.get()); } if (!Update.isUsable() || !Final.isUsable()) { HasErrors = true; @@ -4126,6 +5345,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.CalcLastIteration = SemaRef.ActOnFinishFullExpr(CalcLastIteration.get()).get(); Built.PreCond = PreCond.get(); + Built.PreInits = buildPreInits(C, Captures); Built.Cond = Cond.get(); Built.Init = Init.get(); Built.Inc = Inc.get(); @@ -4136,6 +5356,56 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr, Built.EUB = EUB.get(); Built.NLB = NextLB.get(); Built.NUB = NextUB.get(); + Built.PrevLB = PrevLB.get(); + Built.PrevUB = PrevUB.get(); + + Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get(); + // Fill data for doacross depend clauses. + for (auto Pair : DSA.getDoacrossDependClauses()) { + if (Pair.first->getDependencyKind() == OMPC_DEPEND_source) + Pair.first->setCounterValue(CounterVal); + else { + if (NestedLoopCount != Pair.second.size() || + NestedLoopCount != LoopMultipliers.size() + 1) { + // Erroneous case - clause has some problems. + Pair.first->setCounterValue(CounterVal); + continue; + } + assert(Pair.first->getDependencyKind() == OMPC_DEPEND_sink); + auto I = Pair.second.rbegin(); + auto IS = IterSpaces.rbegin(); + auto ILM = LoopMultipliers.rbegin(); + Expr *UpCounterVal = CounterVal; + Expr *Multiplier = nullptr; + for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) { + if (I->first) { + assert(IS->CounterStep); + Expr *NormalizedOffset = + SemaRef + .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Div, + I->first, IS->CounterStep) + .get(); + if (Multiplier) { + NormalizedOffset = + SemaRef + .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Mul, + NormalizedOffset, Multiplier) + .get(); + } + 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(); + } + Multiplier = *ILM; + ++I; + ++IS; + ++ILM; + } + Pair.first->setCounterValue(UpCounterVal); + } + } return NestedLoopCount; } @@ -4156,26 +5426,44 @@ static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) { return nullptr; } -static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen, - const Expr *Safelen) { - llvm::APSInt SimdlenRes, SafelenRes; - if (Simdlen->isValueDependent() || Simdlen->isTypeDependent() || - Simdlen->isInstantiationDependent() || - Simdlen->containsUnexpandedParameterPack()) - return false; - if (Safelen->isValueDependent() || Safelen->isTypeDependent() || - Safelen->isInstantiationDependent() || - Safelen->containsUnexpandedParameterPack()) - return false; - Simdlen->EvaluateAsInt(SimdlenRes, S.Context); - Safelen->EvaluateAsInt(SafelenRes, S.Context); - // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] - // If both simdlen and safelen clauses are specified, the value of the simdlen - // parameter must be less than or equal to the value of the safelen parameter. - if (SimdlenRes > SafelenRes) { - S.Diag(Simdlen->getExprLoc(), diag::err_omp_wrong_simdlen_safelen_values) - << Simdlen->getSourceRange() << Safelen->getSourceRange(); - return true; +static bool checkSimdlenSafelenSpecified(Sema &S, + const ArrayRef<OMPClause *> Clauses) { + OMPSafelenClause *Safelen = nullptr; + OMPSimdlenClause *Simdlen = nullptr; + + for (auto *Clause : Clauses) { + if (Clause->getClauseKind() == OMPC_safelen) + Safelen = cast<OMPSafelenClause>(Clause); + else if (Clause->getClauseKind() == OMPC_simdlen) + Simdlen = cast<OMPSimdlenClause>(Clause); + if (Safelen && Simdlen) + break; + } + + if (Simdlen && Safelen) { + llvm::APSInt SimdlenRes, SafelenRes; + auto SimdlenLength = Simdlen->getSimdlen(); + auto SafelenLength = Safelen->getSafelen(); + if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() || + SimdlenLength->isInstantiationDependent() || + SimdlenLength->containsUnexpandedParameterPack()) + return false; + if (SafelenLength->isValueDependent() || SafelenLength->isTypeDependent() || + SafelenLength->isInstantiationDependent() || + SafelenLength->containsUnexpandedParameterPack()) + return false; + SimdlenLength->EvaluateAsInt(SimdlenRes, S.Context); + SafelenLength->EvaluateAsInt(SafelenRes, S.Context); + // OpenMP 4.5 [2.8.1, simd Construct, Restrictions] + // If both simdlen and safelen clauses are specified, the value of the + // simdlen parameter must be less than or equal to the value of the safelen + // parameter. + if (SimdlenRes > SafelenRes) { + S.Diag(SimdlenLength->getExprLoc(), + diag::err_omp_wrong_simdlen_safelen_values) + << SimdlenLength->getSourceRange() << SafelenLength->getSourceRange(); + return true; + } } return false; } @@ -4183,7 +5471,7 @@ static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen, StmtResult Sema::ActOnOpenMPSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4205,27 +5493,13 @@ StmtResult Sema::ActOnOpenMPSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] - // If both simdlen and safelen clauses are specified, the value of the simdlen - // parameter must be less than or equal to the value of the safelen parameter. - OMPSafelenClause *Safelen = nullptr; - OMPSimdlenClause *Simdlen = nullptr; - for (auto *Clause : Clauses) { - if (Clause->getClauseKind() == OMPC_safelen) - Safelen = cast<OMPSafelenClause>(Clause); - else if (Clause->getClauseKind() == OMPC_simdlen) - Simdlen = cast<OMPSimdlenClause>(Clause); - if (Safelen && Simdlen) - break; - } - if (Simdlen && Safelen && - checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), - Safelen->getSafelen())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -4236,7 +5510,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective( StmtResult Sema::ActOnOpenMPForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4258,7 +5532,8 @@ StmtResult Sema::ActOnOpenMPForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -4271,7 +5546,7 @@ StmtResult Sema::ActOnOpenMPForDirective( StmtResult Sema::ActOnOpenMPForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4294,27 +5569,13 @@ StmtResult Sema::ActOnOpenMPForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] - // If both simdlen and safelen clauses are specified, the value of the simdlen - // parameter must be less than or equal to the value of the safelen parameter. - OMPSafelenClause *Safelen = nullptr; - OMPSimdlenClause *Simdlen = nullptr; - for (auto *Clause : Clauses) { - if (Clause->getClauseKind() == OMPC_safelen) - Safelen = cast<OMPSafelenClause>(Clause); - else if (Clause->getClauseKind() == OMPC_simdlen) - Simdlen = cast<OMPSimdlenClause>(Clause); - if (Safelen && Simdlen) - break; - } - if (Simdlen && Safelen && - checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), - Safelen->getSafelen())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -4480,7 +5741,7 @@ StmtResult Sema::ActOnOpenMPCriticalDirective( StmtResult Sema::ActOnOpenMPParallelForDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4510,7 +5771,8 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } @@ -4524,7 +5786,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective( StmtResult Sema::ActOnOpenMPParallelForSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -4551,27 +5813,13 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective( for (auto C : Clauses) { if (auto LC = dyn_cast<OMPLinearClause>(C)) if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef), - B.NumIterations, *this, CurScope)) + B.NumIterations, *this, CurScope, + DSAStack)) return StmtError(); } } - // OpenMP 4.1 [2.8.1, simd Construct, Restrictions] - // If both simdlen and safelen clauses are specified, the value of the simdlen - // parameter must be less than or equal to the value of the safelen parameter. - OMPSafelenClause *Safelen = nullptr; - OMPSimdlenClause *Simdlen = nullptr; - for (auto *Clause : Clauses) { - if (Clause->getClauseKind() == OMPC_safelen) - Safelen = cast<OMPSafelenClause>(Clause); - else if (Clause->getClauseKind() == OMPC_simdlen) - Simdlen = cast<OMPSimdlenClause>(Clause); - if (Safelen && Simdlen) - break; - } - if (Simdlen && Safelen && - checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(), - Safelen->getSafelen())) + if (checkSimdlenSafelenSpecified(*this, Clauses)) return StmtError(); getCurFunction()->setHasBranchProtectedScope(); @@ -5453,6 +6701,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, } assert(I != CS->body_end() && "Not found statement"); S = *I; + } else { + auto *OED = dyn_cast<OMPExecutableDirective>(S); + OMPTeamsFound = OED && isOpenMPTeamsDirective(OED->getDirectiveKind()); } if (!OMPTeamsFound) { Diag(StartLoc, diag::err_omp_target_contains_not_only_teams); @@ -5469,6 +6720,84 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses, return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } +StmtResult +Sema::ActOnOpenMPTargetParallelDirective(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 OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses, + AStmt); +} + +StmtResult Sema::ActOnOpenMPTargetParallelForDirective( + 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' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = + CheckOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target 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 OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, + B, DSAStack->isCancelRegion()); +} + +/// \brief Check for existence of a map clause in the list of clauses. +static bool HasMapClause(ArrayRef<OMPClause *> Clauses) { + for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end(); + I != E; ++I) { + if (*I != nullptr && (*I)->getClauseKind() == OMPC_map) { + return true; + } + } + + return false; +} + StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, @@ -5478,12 +6807,66 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses, assert(isa<CapturedStmt>(AStmt) && "Captured statement expected"); + // OpenMP [2.10.1, Restrictions, p. 97] + // At least one map clause must appear on the directive. + if (!HasMapClause(Clauses)) { + Diag(StartLoc, diag::err_omp_no_map_for_directive) << + getOpenMPDirectiveName(OMPD_target_data); + return StmtError(); + } + getCurFunction()->setHasBranchProtectedScope(); return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt); } +StmtResult +Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.10.2, Restrictions, p. 99] + // 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_enter_data); + return StmtError(); + } + + return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc, + Clauses); +} + +StmtResult +Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + // OpenMP [2.10.3, Restrictions, p. 102] + // 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_exit_data); + return StmtError(); + } + + return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + +StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses, + SourceLocation StartLoc, + SourceLocation EndLoc) { + bool seenMotionClause = false; + for (auto *C : Clauses) { + if (C->getClauseKind() == OMPC_to || C->getClauseKind() == OMPC_from) + seenMotionClause = true; + } + if (!seenMotionClause) { + Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required); + return StmtError(); + } + return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses); +} + StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc) { @@ -5575,7 +6958,7 @@ static bool checkGrainsizeNumTasksClauses(Sema &S, StmtResult Sema::ActOnOpenMPTaskLoopDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5607,7 +6990,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective( StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5625,6 +7008,17 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( 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(); + } + } + // OpenMP, [2.9.2 taskloop Construct, Restrictions] // The grainsize clause and num_tasks clause are mutually exclusive and may // not appear on the same taskloop directive. @@ -5639,7 +7033,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective( StmtResult Sema::ActOnOpenMPDistributeDirective( ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc, SourceLocation EndLoc, - llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) { + llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) { if (!AStmt) return StmtError(); @@ -5662,6 +7056,157 @@ StmtResult Sema::ActOnOpenMPDistributeDirective( NestedLoopCount, Clauses, AStmt, B); } +StmtResult Sema::ActOnOpenMPDistributeParallelForDirective( + 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_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"); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeParallelForDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective( + 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_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 (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPDistributeSimdDirective( + 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_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 for loop exprs were not built"); + + if (checkSimdlenSafelenSpecified(*this, Clauses)) + return StmtError(); + + getCurFunction()->setHasBranchProtectedScope(); + return OMPDistributeSimdDirective::Create(Context, StartLoc, EndLoc, + NestedLoopCount, Clauses, AStmt, B); +} + +StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective( + 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' or 'ordered' with number of loops, it will + // define the nested loops number. + unsigned NestedLoopCount = CheckOpenMPLoop( + OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses), + getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack, + VarsWithImplicitDSA, B); + if (NestedLoopCount == 0) + return StmtError(); + + assert((CurContext->isDependentContext() || B.builtAll()) && + "omp target parallel for 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 OMPTargetParallelForSimdDirective::Create( + Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B); +} + OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -5735,7 +7280,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr, case OMPC_simd: case OMPC_map: case OMPC_nogroup: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -5751,12 +7303,11 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier, if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { - ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), - Condition->getExprLoc(), Condition); + ExprResult Val = CheckBooleanCondition(StartLoc, Condition); if (Val.isInvalid()) return nullptr; - ValExpr = Val.get(); + ValExpr = MakeFullExpr(Val.get()).get(); } return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc, @@ -5771,12 +7322,11 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition, if (!Condition->isValueDependent() && !Condition->isTypeDependent() && !Condition->isInstantiationDependent() && !Condition->containsUnexpandedParameterPack()) { - ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(), - Condition->getExprLoc(), Condition); + ExprResult Val = CheckBooleanCondition(StartLoc, Condition); if (Val.isInvalid()) return nullptr; - ValExpr = Val.get(); + ValExpr = MakeFullExpr(Val.get()).get(); } return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc); @@ -6018,7 +7568,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause( case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6116,6 +7673,19 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( Expr, StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc); break; + case OMPC_dist_schedule: + Res = ActOnOpenMPDistScheduleClause( + static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), Expr, + StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc); + break; + case OMPC_defaultmap: + enum { Modifier, DefaultmapKind }; + Res = ActOnOpenMPDefaultmapClause( + static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]), + static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]), + StartLoc, LParenLoc, ArgumentLoc[Modifier], + ArgumentLoc[DefaultmapKind], EndLoc); + break; case OMPC_final: case OMPC_num_threads: case OMPC_safelen: @@ -6156,6 +7726,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause( case OMPC_num_tasks: case OMPC_hint: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6230,7 +7805,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( return nullptr; } Expr *ValExpr = ChunkSize; - Expr *HelperValExpr = nullptr; + Stmt *HelperValStmt = nullptr; if (ChunkSize) { if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && !ChunkSize->isInstantiationDependent() && @@ -6253,20 +7828,18 @@ OMPClause *Sema::ActOnOpenMPScheduleClause( << "schedule" << 1 << ChunkSize->getSourceRange(); return nullptr; } - } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) { - auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(), - ChunkSize->getType(), ".chunk."); - auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(), - ChunkSize->getExprLoc(), - /*RefersToCapture=*/true); - HelperValExpr = ImpVarRef; + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + !CurContext->isDependentContext()) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); } } } return new (Context) OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind, - ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc); + ValExpr, HelperValStmt, M1, M1Loc, M2, M2Loc); } OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, @@ -6339,7 +7912,14 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind, case OMPC_grainsize: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: + case OMPC_to: + case OMPC_from: + case OMPC_use_device_ptr: + case OMPC_is_device_ptr: llvm_unreachable("Clause is not allowed."); } return Res; @@ -6406,8 +7986,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause( SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind, - OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, - OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) { + OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation DepLinMapLoc) { OMPClause *Res = nullptr; switch (Kind) { case OMPC_private: @@ -6448,8 +8029,21 @@ OMPClause *Sema::ActOnOpenMPVarListClause( StartLoc, LParenLoc, EndLoc); break; case OMPC_map: - Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc, - VarList, StartLoc, LParenLoc, EndLoc); + Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, IsMapTypeImplicit, + DepLinMapLoc, ColonLoc, VarList, StartLoc, + LParenLoc, EndLoc); + break; + case OMPC_to: + Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_from: + Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_use_device_ptr: + Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); + break; + case OMPC_is_device_ptr: + Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc); break; case OMPC_if: case OMPC_final: @@ -6480,12 +8074,93 @@ OMPClause *Sema::ActOnOpenMPVarListClause( case OMPC_nogroup: case OMPC_num_tasks: case OMPC_hint: + case OMPC_dist_schedule: + case OMPC_defaultmap: case OMPC_unknown: + case OMPC_uniform: llvm_unreachable("Clause is not allowed."); } return Res; } +ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK, + ExprObjectKind OK, SourceLocation Loc) { + ExprResult Res = BuildDeclRefExpr( + Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc); + if (!Res.isUsable()) + return ExprError(); + if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) { + Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + if (VK != VK_LValue && Res.get()->isGLValue()) { + Res = DefaultLvalueConversion(Res.get()); + if (!Res.isUsable()) + return ExprError(); + } + return Res; +} + +static std::pair<ValueDecl *, bool> +getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc, + SourceRange &ERange, bool AllowArraySection = false) { + if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || + RefExpr->containsUnexpandedParameterPack()) + return std::make_pair(nullptr, true); + + // OpenMP [3.1, C/C++] + // A list item is a variable name. + // OpenMP [2.9.3.3, Restrictions, p.1] + // A variable that is part of another variable (as an array or + // structure element) cannot appear in a private clause. + RefExpr = RefExpr->IgnoreParens(); + enum { + NoArrayExpr = -1, + ArraySubscript = 0, + OMPArraySection = 1 + } IsArrayExpr = NoArrayExpr; + if (AllowArraySection) { + if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) { + auto *Base = ASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = ArraySubscript; + } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) { + auto *Base = OASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) + Base = TempOASE->getBase()->IgnoreParenImpCasts(); + while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) + Base = TempASE->getBase()->IgnoreParenImpCasts(); + RefExpr = Base; + IsArrayExpr = OMPArraySection; + } + } + ELoc = RefExpr->getExprLoc(); + ERange = RefExpr->getSourceRange(); + RefExpr = RefExpr->IgnoreParenImpCasts(); + auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); + auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr); + if ((!DE || !isa<VarDecl>(DE->getDecl())) && + (S.getCurrentThisType().isNull() || !ME || + !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) || + !isa<FieldDecl>(ME->getMemberDecl()))) { + if (IsArrayExpr != NoArrayExpr) + S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr + << ERange; + else { + S.Diag(ELoc, + AllowArraySection + ? diag::err_omp_expected_var_name_member_expr_or_array_item + : diag::err_omp_expected_var_name_member_expr) + << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange; + } + return std::make_pair(nullptr, false); + } + return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false); +} + OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, @@ -6494,42 +8169,27 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> PrivateCopies; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP private clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + 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); PrivateCopies.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.9.3.3, Restrictions, p.1] - // A variable that is part of another variable (as an array or - // structure element) cannot appear in a private clause. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - PrivateCopies.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. - if (RequireCompleteType(ELoc, Type, - diag::err_omp_private_incomplete_type)) { + if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -6539,28 +8199,45 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_private); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && - DSAStack->getCurrentDirective() == OMPD_task) { + isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_private) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (DSAStack->getCurrentDirective() == OMPD_target) { + if (DSAStack->checkMappableExprComponentListsForDecl( + VD, /* CurrentRegionOnly = */ true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) + -> bool { return true; })) { + Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(OMPC_private) + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP [2.9.3.3, Restrictions, C/C++, p.1] // A variable of class type (or array thereof) that appears in a private // clause requires an accessible, unambiguous default constructor for the @@ -6571,16 +8248,21 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList, // IdResolver, so the code in the OpenMP region uses original variable for // proper diagnostics. Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false); if (VDPrivate->isInvalidDecl()) continue; auto VDPrivateRefExpr = buildDeclRefExpr( - *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); - - DSAStack->addDSA(VD, DE, OMPC_private); - Vars.push_back(DE); + *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc); + + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); PrivateCopies.push_back(VDPrivateRefExpr); } @@ -6621,51 +8303,37 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> PrivateCopies; SmallVector<Expr *, 8> Inits; + SmallVector<Decl *, 4> ExprCaptures; bool IsImplicitClause = StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid(); auto ImplicitClauseLoc = DSAStack->getConstructLoc(); for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP firstprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + 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); PrivateCopies.push_back(nullptr); Inits.push_back(nullptr); - continue; } - - SourceLocation ELoc = - IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.9.3.3, Restrictions, p.1] - // A variable that is part of another variable (as an array or - // structure element) cannot appear in a private clause. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - PrivateCopies.push_back(nullptr); - Inits.push_back(nullptr); - continue; - } + ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc; + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete // type or a reference type. if (RequireCompleteType(ELoc, Type, - diag::err_omp_firstprivate_incomplete_type)) { + diag::err_omp_firstprivate_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.9.3.4, Restrictions, C/C++, p.1] @@ -6675,8 +8343,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, auto ElemType = Context.getBaseElementType(Type).getNonReferenceType(); // If an implicit firstprivate variable found it was checked already. + DSAStackTy::DSAVarData TopDVar; if (!IsImplicitClause) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + TopDVar = DVar; bool IsConstant = ElemType.isConstant(Context); // OpenMP [2.4.13, Data-sharing Attribute Clauses] // A list item that specifies a given variable may not appear in more @@ -6687,7 +8357,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6702,12 +8372,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // in a Construct, C/C++, p.2] // Variables with const-qualified type having no mutable member may be // listed in a firstprivate clause, even if they are static data members. - if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr && + if (!(IsConstant || (VD && VD->isStaticDataMember())) && !DVar.RefExpr && DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_firstprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6719,14 +8389,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // to any of the parallel regions arising from the parallel construct. if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared && (isOpenMPParallelDirective(DVar.DKind) || DVar.DKind == OMPD_unknown)) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_firstprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6741,20 +8411,20 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // construct must not appear in a firstprivate clause in a task construct // encountered during execution of any of the worksharing regions arising // from the worksharing construct. - if (CurrDir == OMPD_task) { - DVar = - DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPParallelDirective(K) || - isOpenMPWorksharingDirective(K); - }, - false); + if (isOpenMPTaskingDirective(CurrDir)) { + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPParallelDirective(K) || + isOpenMPWorksharingDirective(K); + }, + false); if (DVar.CKind == OMPC_reduction && (isOpenMPParallelDirective(DVar.DKind) || isOpenMPWorksharingDirective(DVar.DKind))) { Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate) << getOpenMPDirectiveName(DVar.DKind); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6773,31 +8443,48 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // A list item may appear in a firstprivate or lastprivate clause but not // both. if (CurrDir == OMPD_distribute) { - DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_private), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPTeamsDirective(K); - }, - false); + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_private; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPTeamsDirective(K); + }, + false); if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) { Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction), - [](OpenMPDirectiveKind K) -> bool { - return isOpenMPTeamsDirective(K); - }, - false); + DVar = DSAStack->hasInnermostDSA( + D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; }, + [](OpenMPDirectiveKind K) -> bool { + return isOpenMPTeamsDirective(K); + }, + false); if (DVar.CKind == OMPC_reduction && isOpenMPTeamsDirective(DVar.DKind)) { Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DVar = DSAStack->getTopDSA(VD, false); + DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind == OMPC_lastprivate) { Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (CurrDir == OMPD_target) { + if (DSAStack->checkMappableExprComponentListsForDecl( + VD, /* CurrentRegionOnly = */ true, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef) + -> bool { return true; })) { + Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(OMPC_firstprivate) + << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -6805,21 +8492,22 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // Variably modified types are not supported for tasks. if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() && - DSAStack->getCurrentDirective() == OMPD_task) { + isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) { Diag(ELoc, diag::err_omp_variably_modified_type_not_supported) << getOpenMPClauseName(OMPC_firstprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } Type = Type.getUnqualifiedType(); - auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); // Generate helper private variable and initialize it with the value of the // original variable. The address of the original variable is replaced by // the address of the new private variable in the CodeGen. This new variable @@ -6830,11 +8518,11 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // original array element in CodeGen. if (Type->isArrayType()) { auto VDInit = - buildVarDecl(*this, DE->getExprLoc(), ElemType, VD->getName()); + buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, D->getName()); VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc); auto Init = DefaultLvalueConversion(VDInitRefExpr).get(); ElemType = ElemType.getUnqualifiedType(); - auto *VDInitTemp = buildVarDecl(*this, DE->getLocStart(), ElemType, + auto *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, ".firstprivate.temp"); InitializedEntity Entity = InitializedEntity::InitializeVariable(VDInitTemp); @@ -6849,26 +8537,39 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, // Remove temp variable declaration. Context.Deallocate(VDInitTemp); } else { - auto *VDInit = - buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp"); - VDInitRefExpr = - buildDeclRefExpr(*this, VDInit, DE->getType(), DE->getExprLoc()); + auto *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type, + ".firstprivate.temp"); + VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(), + RefExpr->getExprLoc()); AddInitializerToDecl(VDPrivate, DefaultLvalueConversion(VDInitRefExpr).get(), /*DirectInit=*/false, /*TypeMayContainAuto=*/false); } if (VDPrivate->isInvalidDecl()) { if (IsImplicitClause) { - Diag(DE->getExprLoc(), + Diag(RefExpr->getExprLoc(), diag::note_omp_task_predetermined_firstprivate_here); } continue; } CurContext->addDecl(VDPrivate); auto VDPrivateRefExpr = buildDeclRefExpr( - *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc()); - DSAStack->addDSA(VD, DE, OMPC_firstprivate); - Vars.push_back(DE); + *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), + RefExpr->getExprLoc()); + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + if (TopDVar.CKind == OMPC_lastprivate) + Ref = TopDVar.PrivateCopy; + else { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + if (!IsOpenMPCapturedDecl(D)) + ExprCaptures.push_back(Ref->getDecl()); + } + } + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); PrivateCopies.push_back(VDPrivateRefExpr); Inits.push_back(VDInitRefExpr); } @@ -6877,7 +8578,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList, return nullptr; return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars, PrivateCopies, Inits); + Vars, PrivateCopies, Inits, + buildPreInits(Context, ExprCaptures)); } OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, @@ -6888,48 +8590,34 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> SrcExprs; SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP lastprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + 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); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.5, Restrictions, p.1] - // A variable that is part of another variable (as an array or structure - // element) cannot appear in a lastprivate clause. - DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - SrcExprs.push_back(nullptr); - DstExprs.push_back(nullptr); - AssignmentOps.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.3.5, Restrictions, C/C++, p.2] // A variable that appears in a lastprivate clause must not have an // incomplete type or a reference type. if (RequireCompleteType(ELoc, Type, - diag::err_omp_lastprivate_incomplete_type)) { + diag::err_omp_lastprivate_incomplete_type)) continue; - } Type = Type.getNonReferenceType(); // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced @@ -6937,14 +8625,14 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // Variables with the predetermined data-sharing attributes may not be // listed in data-sharing attributes clauses, except for the cases // listed below. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate && DVar.CKind != OMPC_firstprivate && (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_lastprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -6958,15 +8646,28 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, DSAStackTy::DSAVarData TopDVar = DVar; if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_lastprivate) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } + + // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] + // A list item may appear in a firstprivate or lastprivate clause but not + // both. + if (CurrDir == OMPD_distribute) { + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); + if (DVar.CKind == OMPC_firstprivate) { + Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + // OpenMP [2.14.3.5, Restrictions, C++, p.1,2] // A variable of class type (or array thereof) that appears in a // lastprivate clause requires an accessible, unambiguous default @@ -6976,42 +8677,54 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, // lastprivate clause requires an accessible, unambiguous copy assignment // operator for the class type. Type = Context.getBaseElementType(Type).getNonReferenceType(); - auto *SrcVD = buildVarDecl(*this, DE->getLocStart(), + auto *SrcVD = buildVarDecl(*this, ERange.getBegin(), Type.getUnqualifiedType(), ".lastprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = buildDeclRefExpr( - *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc()); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = + buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); + buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc); // For arrays generate assignment operation for single element and replace // it by the original array element in CodeGen. - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + auto AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; - // OpenMP 4.5 [2.10.8, Distribute Construct, p.3] - // A list item may appear in a firstprivate or lastprivate clause but not - // both. - if (CurrDir == OMPD_distribute) { - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); - if (DVar.CKind == OMPC_firstprivate) { - Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute); - ReportOriginalDSA(*this, DSAStack, VD, DVar); - continue; + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + if (TopDVar.CKind == OMPC_firstprivate) + Ref = TopDVar.PrivateCopy; + else { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + if (!IsOpenMPCapturedDecl(D)) + ExprCaptures.push_back(Ref->getDecl()); + } + if (TopDVar.CKind == OMPC_firstprivate || + (!IsOpenMPCapturedDecl(D) && + Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr, + RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); } } - - if (TopDVar.CKind != OMPC_firstprivate) - DSAStack->addDSA(VD, DE, OMPC_lastprivate); - Vars.push_back(DE); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_lastprivate, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); @@ -7021,7 +8734,9 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList, return nullptr; return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc, - Vars, SrcExprs, DstExprs, AssignmentOps); + Vars, SrcExprs, DstExprs, AssignmentOps, + buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); } OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, @@ -7030,35 +8745,20 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, SourceLocation EndLoc) { SmallVector<Expr *, 8> Vars; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP lastprivate 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); - continue; - } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.2, Restrictions, p.1] - // A variable that is part of another variable (as an array or structure - // element) cannot appear in a shared unless it is a static data member - // of a C++ class. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); - continue; } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); + ValueDecl *D = Res.first; + if (!D) continue; - } + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -7066,17 +8766,22 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList, // listed below. For these exceptions only, listing a predetermined // variable in a data-sharing attribute clause is allowed and overrides // the variable's predetermined data-sharing attributes. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - DSAStack->addDSA(VD, DE, OMPC_shared); - Vars.push_back(DE); + DeclRefExpr *Ref = nullptr; + if (!VD && IsOpenMPCapturedDecl(D) && !CurContext->isDependentContext()) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref); + Vars.push_back((VD || !Ref || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); } if (Vars.empty()) @@ -7097,8 +8802,9 @@ public: return false; if (DVar.CKind != OMPC_unknown) return true; - DSAStackTy::DSAVarData DVarPrivate = - Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false); + DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA( + VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; }, + false); if (DVarPrivate.CKind != OMPC_unknown) return true; return false; @@ -7116,16 +8822,137 @@ public: }; } // namespace +namespace { +// Transform MemberExpression for specified FieldDecl of current class to +// DeclRefExpr to specified OMPCapturedExprDecl. +class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> { + typedef TreeTransform<TransformExprToCaptures> BaseTransform; + ValueDecl *Field; + DeclRefExpr *CapturedExpr; + +public: + TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl) + : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {} + + ExprResult TransformMemberExpr(MemberExpr *E) { + if (isa<CXXThisExpr>(E->getBase()->IgnoreParenImpCasts()) && + E->getMemberDecl() == Field) { + CapturedExpr = buildCapture(SemaRef, Field, E, /*WithInit=*/false); + return CapturedExpr; + } + return BaseTransform::TransformMemberExpr(E); + } + DeclRefExpr *getCapturedExpr() { return CapturedExpr; } +}; +} // namespace + +template <typename T> +static T filterLookupForUDR(SmallVectorImpl<UnresolvedSet<8>> &Lookups, + const llvm::function_ref<T(ValueDecl *)> &Gen) { + for (auto &Set : Lookups) { + for (auto *D : Set) { + if (auto Res = Gen(cast<ValueDecl>(D))) + return Res; + } + } + return T(); +} + +static ExprResult +buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range, + Scope *S, CXXScopeSpec &ReductionIdScopeSpec, + const DeclarationNameInfo &ReductionId, QualType Ty, + CXXCastPath &BasePath, Expr *UnresolvedReduction) { + if (ReductionIdScopeSpec.isInvalid()) + return ExprError(); + SmallVector<UnresolvedSet<8>, 4> Lookups; + if (S) { + LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName); + Lookup.suppressDiagnostics(); + while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) { + auto *D = Lookup.getRepresentativeDecl(); + do { + S = S->getParent(); + } while (S && !S->isDeclScope(D)); + if (S) + S = S->getParent(); + Lookups.push_back(UnresolvedSet<8>()); + Lookups.back().append(Lookup.begin(), Lookup.end()); + Lookup.clear(); + } + } else if (auto *ULE = + cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) { + Lookups.push_back(UnresolvedSet<8>()); + Decl *PrevD = nullptr; + for(auto *D : ULE->decls()) { + if (D == PrevD) + Lookups.push_back(UnresolvedSet<8>()); + else if (auto *DRD = cast<OMPDeclareReductionDecl>(D)) + Lookups.back().addDecl(DRD); + PrevD = D; + } + } + if (Ty->isDependentType() || Ty->isInstantiationDependentType() || + Ty->containsUnexpandedParameterPack() || + filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool { + return !D->isInvalidDecl() && + (D->getType()->isDependentType() || + D->getType()->isInstantiationDependentType() || + D->getType()->containsUnexpandedParameterPack()); + })) { + UnresolvedSet<8> ResSet; + for (auto &Set : Lookups) { + ResSet.append(Set.begin(), Set.end()); + // The last item marks the end of all declarations at the specified scope. + ResSet.addDecl(Set[Set.size() - 1]); + } + return UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId, + /*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end()); + } + if (auto *VD = filterLookupForUDR<ValueDecl *>( + Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.Context.hasSameType(D->getType(), Ty)) + return D; + return nullptr; + })) + return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + if (auto *VD = filterLookupForUDR<ValueDecl *>( + Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * { + if (!D->isInvalidDecl() && + SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) && + !Ty.isMoreQualifiedThan(D->getType())) + return D; + return nullptr; + })) { + CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true, + /*DetectVirtual=*/false); + if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) { + if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType( + VD->getType().getUnqualifiedType()))) { + if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(), + /*DiagID=*/0) != + Sema::AR_inaccessible) { + SemaRef.BuildBasePathArray(Paths, BasePath); + return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc); + } + } + } + } + if (ReductionIdScopeSpec.isSet()) { + SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range; + return ExprError(); + } + return ExprEmpty(); +} + OMPClause *Sema::ActOnOpenMPReductionClause( ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc, SourceLocation EndLoc, - CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId) { - // TODO: Allow scope specification search when 'declare reduction' is - // supported. - assert(ReductionIdScopeSpec.isEmpty() && - "No support for scoped reduction identifiers yet."); - + CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { auto DN = ReductionId.getName(); auto OOK = DN.getCXXOverloadedOperator(); BinaryOperatorKind BOK = BO_Comma; @@ -7209,48 +9036,21 @@ OMPClause *Sema::ActOnOpenMPReductionClause( break; } SourceRange ReductionIdRange; - if (ReductionIdScopeSpec.isValid()) { + if (ReductionIdScopeSpec.isValid()) ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc()); - } ReductionIdRange.setEnd(ReductionId.getEndLoc()); - if (BOK == BO_Comma) { - // Not allowed reduction identifier is found. - Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier) - << ReductionIdRange; - return nullptr; - } SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> Privates; SmallVector<Expr *, 8> LHSs; SmallVector<Expr *, 8> RHSs; SmallVector<Expr *, 8> ReductionOps; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; + auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end(); + bool FirstIter = true; for (auto RefExpr : VarList) { assert(RefExpr && "nullptr expr in OpenMP reduction clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { - // It will be analyzed later. - Vars.push_back(RefExpr); - Privates.push_back(nullptr); - LHSs.push_back(nullptr); - RHSs.push_back(nullptr); - ReductionOps.push_back(nullptr); - continue; - } - - if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() || - RefExpr->isInstantiationDependent() || - RefExpr->containsUnexpandedParameterPack()) { - // It will be analyzed later. - Vars.push_back(RefExpr); - Privates.push_back(nullptr); - LHSs.push_back(nullptr); - RHSs.push_back(nullptr); - ReductionOps.push_back(nullptr); - continue; - } - - auto ELoc = RefExpr->getExprLoc(); - auto ERange = RefExpr->getSourceRange(); // OpenMP [2.1, C/C++] // A list item is a variable or array section, subject to the restrictions // specified in Section 2.4 on page 42 and in each of the sections @@ -7258,52 +9058,53 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // OpenMP [2.14.3.3, Restrictions, p.1] // A variable that is part of another variable (as an array or // structure element) cannot appear in a private clause. - auto *DE = dyn_cast<DeclRefExpr>(RefExpr); - auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr); - auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr); - if (!ASE && !OASE && (!DE || !isa<VarDecl>(DE->getDecl()))) { - Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << ERange; - continue; + if (!FirstIter && IR != ER) + ++IR; + FirstIter = false; + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/true); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + Privates.push_back(nullptr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + // Try to find 'declare reduction' corresponding construct before using + // builtin/overloaded operators. + QualType Type = Context.DependentTy; + CXXCastPath BasePath; + ExprResult DeclareReductionRef = buildDeclareReductionRef( + *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec, + ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); + if (CurContext->isDependentContext() && + (DeclareReductionRef.isUnset() || + isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) + ReductionOps.push_back(DeclareReductionRef.get()); + else + ReductionOps.push_back(nullptr); } + ValueDecl *D = Res.first; + if (!D) + continue; + QualType Type; - VarDecl *VD = nullptr; - if (DE) { - auto D = DE->getDecl(); - VD = cast<VarDecl>(D); - Type = VD->getType(); - } else if (ASE) { - Type = ASE->getType(); - auto *Base = ASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - DE = dyn_cast<DeclRefExpr>(Base); - if (DE) - VD = dyn_cast<VarDecl>(DE->getDecl()); - if (!VD) { - Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) - << 0 << Base->getSourceRange(); - continue; - } - } else if (OASE) { + auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens()); + auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens()); + if (ASE) + Type = ASE->getType().getNonReferenceType(); + else if (OASE) { auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase()); if (auto *ATy = BaseType->getAsArrayTypeUnsafe()) Type = ATy->getElementType(); else Type = BaseType->getPointeeType(); - auto *Base = OASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base)) - Base = TempOASE->getBase()->IgnoreParenImpCasts(); - while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base)) - Base = TempASE->getBase()->IgnoreParenImpCasts(); - DE = dyn_cast<DeclRefExpr>(Base); - if (DE) - VD = dyn_cast<VarDecl>(DE->getDecl()); - if (!VD) { - Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name) - << 1 << Base->getSourceRange(); - continue; - } - } + Type = Type.getNonReferenceType(); + } else + Type = Context.getBaseElementType(D->getType().getNonReferenceType()); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.9.3.3, Restrictions, C/C++, p.3] // A variable that appears in a private clause must not have an incomplete @@ -7312,39 +9113,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause( diag::err_omp_reduction_incomplete_type)) continue; // OpenMP [2.14.3.6, reduction clause, Restrictions] - // Arrays may not appear in a reduction clause. - if (Type.getNonReferenceType()->isArrayType()) { - Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange; - if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } - continue; - } - // OpenMP [2.14.3.6, reduction clause, Restrictions] // A list item that appears in a reduction clause must not be // const-qualified. if (Type.getNonReferenceType().isConstant(Context)) { Diag(ELoc, diag::err_omp_const_reduction_list_item) << getOpenMPClauseName(OMPC_reduction) << Type << ERange; if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; } continue; } // OpenMP [2.9.3.6, Restrictions, C/C++, p.4] // If a list-item is a reference type then it must bind to the same object // for all threads of the team. - if (!ASE && !OASE) { + if (!ASE && !OASE && VD) { VarDecl *VDDef = VD->getDefinition(); - if (Type->isReferenceType() && VDDef) { + if (VD->getType()->isReferenceType() && VDDef) { DSARefChecker Check(DSAStack); if (Check.Visit(VDDef->getInit())) { Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange; @@ -7353,40 +9142,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause( } } } - // OpenMP [2.14.3.6, reduction clause, Restrictions] - // The type of a list item that appears in a reduction clause must be valid - // for the reduction-identifier. For a max or min reduction in C, the type - // of the list item must be an allowed arithmetic data type: char, int, - // float, double, or _Bool, possibly modified with long, short, signed, or - // unsigned. For a max or min reduction in C++, the type of the list item - // must be an allowed arithmetic data type: char, wchar_t, int, float, - // double, or bool, possibly modified with long, short, signed, or unsigned. - if ((BOK == BO_GT || BOK == BO_LT) && - !(Type->isScalarType() || - (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { - Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) - << getLangOpts().CPlusPlus; - if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } - continue; - } - if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && - !getLangOpts().CPlusPlus && Type->isFloatingType()) { - Diag(ELoc, diag::err_omp_clause_floating_type_arg); - if (!ASE && !OASE) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } - continue; - } + // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced // in a Construct] // Variables with the predetermined data-sharing attributes may not be @@ -7399,18 +9155,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause( // but a list item can appear only once in the reduction clauses for that // directive. DSAStackTy::DSAVarData DVar; - DVar = DSAStack->getTopDSA(VD, false); + DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind == OMPC_reduction) { Diag(ELoc, diag::err_omp_once_referenced) << getOpenMPClauseName(OMPC_reduction); - if (DVar.RefExpr) { + if (DVar.RefExpr) Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced); - } } else if (DVar.CKind != OMPC_unknown) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_reduction); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -7421,24 +9176,91 @@ OMPClause *Sema::ActOnOpenMPReductionClause( OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective(); if (isOpenMPWorksharingDirective(CurrDir) && !isOpenMPParallelDirective(CurrDir)) { - DVar = DSAStack->getImplicitDSA(VD, true); + DVar = DSAStack->getImplicitDSA(D, true); if (DVar.CKind != OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_reduction) << getOpenMPClauseName(OMPC_shared); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); + continue; + } + } + + // Try to find 'declare reduction' corresponding construct before using + // builtin/overloaded operators. + CXXCastPath BasePath; + ExprResult DeclareReductionRef = buildDeclareReductionRef( + *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec, + ReductionId, Type, BasePath, IR == ER ? nullptr : *IR); + if (DeclareReductionRef.isInvalid()) + continue; + if (CurContext->isDependentContext() && + (DeclareReductionRef.isUnset() || + isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) { + Vars.push_back(RefExpr); + Privates.push_back(nullptr); + LHSs.push_back(nullptr); + RHSs.push_back(nullptr); + ReductionOps.push_back(DeclareReductionRef.get()); + continue; + } + if (BOK == BO_Comma && DeclareReductionRef.isUnset()) { + // Not allowed reduction identifier is found. + Diag(ReductionId.getLocStart(), + diag::err_omp_unknown_reduction_identifier) + << Type << ReductionIdRange; + continue; + } + + // OpenMP [2.14.3.6, reduction clause, Restrictions] + // The type of a list item that appears in a reduction clause must be valid + // for the reduction-identifier. For a max or min reduction in C, the type + // of the list item must be an allowed arithmetic data type: char, int, + // float, double, or _Bool, possibly modified with long, short, signed, or + // unsigned. For a max or min reduction in C++, the type of the list item + // must be an allowed arithmetic data type: char, wchar_t, int, float, + // double, or bool, possibly modified with long, short, signed, or unsigned. + if (DeclareReductionRef.isUnset()) { + if ((BOK == BO_GT || BOK == BO_LT) && + !(Type->isScalarType() || + (getLangOpts().CPlusPlus && Type->isArithmeticType()))) { + Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg) + << getLangOpts().CPlusPlus; + if (!ASE && !OASE) { + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + continue; + } + if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) && + !getLangOpts().CPlusPlus && Type->isFloatingType()) { + Diag(ELoc, diag::err_omp_clause_floating_type_arg); + if (!ASE && !OASE) { + bool IsDecl = !VD || + VD->isThisDeclarationADefinition(Context) == + VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } continue; } } Type = Type.getNonLValueExprType(Context).getUnqualifiedType(); auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); auto PrivateTy = Type; - if (OASE) { - // For array sections only: + if (OASE || + (!ASE && + D->getType().getNonReferenceType()->isVariablyModifiedType())) { + // For arays/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 @@ -7447,162 +9269,227 @@ OMPClause *Sema::ActOnOpenMPReductionClause( Type, new (Context) OpaqueValueExpr(SourceLocation(), Context.getSizeType(), VK_RValue), ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange()); - } + } else if (!ASE && !OASE && + Context.getAsArrayType(D->getType().getNonReferenceType())) + PrivateTy = D->getType().getNonReferenceType(); // Private copy. - auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); // Add initializer for private variable. Expr *Init = nullptr; - switch (BOK) { - case BO_Add: - case BO_Xor: - case BO_Or: - case BO_LOr: - // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. - if (Type->isScalarType() || Type->isAnyComplexType()) { - Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); - } - break; - case BO_Mul: - case BO_LAnd: - if (Type->isScalarType() || Type->isAnyComplexType()) { - // '*' and '&&' reduction ops - initializer is '1'. - Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); - } - break; - case BO_And: { - // '&' reduction op - initializer is '~0'. - QualType OrigType = Type; - if (auto *ComplexTy = OrigType->getAs<ComplexType>()) { - Type = ComplexTy->getElementType(); - } - if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = - llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), - /*isIEEE=*/true); - Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, - Type, ELoc); - } else if (Type->isScalarType()) { - auto Size = Context.getTypeSize(Type); - QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); - llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); - Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); + auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); + if (DeclareReductionRef.isUsable()) { + auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>(); + auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl()); + if (DRD->getInitializer()) { + Init = DRDRef; + RHSVD->setInit(DRDRef); + RHSVD->setInitStyle(VarDecl::CallInit); } - if (Init && OrigType->isAnyComplexType()) { - // Init = 0xFFFF + 0xFFFFi; - auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); - Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } else { + switch (BOK) { + case BO_Add: + case BO_Xor: + case BO_Or: + case BO_LOr: + // '+', '-', '^', '|', '||' reduction ops - initializer is '0'. + if (Type->isScalarType() || Type->isAnyComplexType()) + Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get(); + break; + case BO_Mul: + case BO_LAnd: + if (Type->isScalarType() || Type->isAnyComplexType()) { + // '*' and '&&' reduction ops - initializer is '1'. + Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get(); + } + break; + case BO_And: { + // '&' reduction op - initializer is '~0'. + QualType OrigType = Type; + if (auto *ComplexTy = OrigType->getAs<ComplexType>()) + Type = ComplexTy->getElementType(); + if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = + llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type), + /*isIEEE=*/true); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); + } else if (Type->isScalarType()) { + auto Size = Context.getTypeSize(Type); + QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0); + llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + } + if (Init && OrigType->isAnyComplexType()) { + // Init = 0xFFFF + 0xFFFFi; + auto *Im = new (Context) ImaginaryLiteral(Init, OrigType); + Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get(); + } + Type = OrigType; + break; } - Type = OrigType; - break; - } - case BO_LT: - case BO_GT: { - // 'min' reduction op - initializer is 'Largest representable number in - // the reduction list item type'. - // 'max' reduction op - initializer is 'Least representable number in - // the reduction list item type'. - if (Type->isIntegerType() || Type->isPointerType()) { - bool IsSigned = Type->hasSignedIntegerRepresentation(); - auto Size = Context.getTypeSize(Type); - QualType IntTy = - Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); - llvm::APInt InitValue = - (BOK != BO_LT) - ? IsSigned ? llvm::APInt::getSignedMinValue(Size) - : llvm::APInt::getMinValue(Size) - : IsSigned ? llvm::APInt::getSignedMaxValue(Size) - : llvm::APInt::getMaxValue(Size); - Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); - if (Type->isPointerType()) { - // Cast to pointer type. - auto CastExpr = BuildCStyleCastExpr( - SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), - SourceLocation(), Init); - if (CastExpr.isInvalid()) - continue; - Init = CastExpr.get(); + case BO_LT: + case BO_GT: { + // 'min' reduction op - initializer is 'Largest representable number in + // the reduction list item type'. + // 'max' reduction op - initializer is 'Least representable number in + // the reduction list item type'. + if (Type->isIntegerType() || Type->isPointerType()) { + bool IsSigned = Type->hasSignedIntegerRepresentation(); + auto Size = Context.getTypeSize(Type); + QualType IntTy = + Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned); + llvm::APInt InitValue = + (BOK != BO_LT) + ? IsSigned ? llvm::APInt::getSignedMinValue(Size) + : llvm::APInt::getMinValue(Size) + : IsSigned ? llvm::APInt::getSignedMaxValue(Size) + : llvm::APInt::getMaxValue(Size); + Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc); + if (Type->isPointerType()) { + // Cast to pointer type. + auto CastExpr = BuildCStyleCastExpr( + SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc), + SourceLocation(), Init); + if (CastExpr.isInvalid()) + continue; + Init = CastExpr.get(); + } + } else if (Type->isRealFloatingType()) { + llvm::APFloat InitValue = llvm::APFloat::getLargest( + Context.getFloatTypeSemantics(Type), BOK != BO_LT); + Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, + Type, ELoc); } - } else if (Type->isRealFloatingType()) { - llvm::APFloat InitValue = llvm::APFloat::getLargest( - Context.getFloatTypeSemantics(Type), BOK != BO_LT); - Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true, - Type, ELoc); + break; + } + case BO_PtrMemD: + case BO_PtrMemI: + case BO_MulAssign: + case BO_Div: + case BO_Rem: + case BO_Sub: + case BO_Shl: + case BO_Shr: + case BO_LE: + case BO_GE: + case BO_EQ: + case BO_NE: + case BO_AndAssign: + case BO_XorAssign: + case BO_OrAssign: + case BO_Assign: + case BO_AddAssign: + case BO_SubAssign: + case BO_DivAssign: + case BO_RemAssign: + case BO_ShlAssign: + case BO_ShrAssign: + case BO_Comma: + llvm_unreachable("Unexpected reduction operation"); } - break; } - case BO_PtrMemD: - case BO_PtrMemI: - case BO_MulAssign: - case BO_Div: - case BO_Rem: - case BO_Sub: - case BO_Shl: - case BO_Shr: - case BO_LE: - case BO_GE: - case BO_EQ: - case BO_NE: - case BO_AndAssign: - case BO_XorAssign: - case BO_OrAssign: - case BO_Assign: - case BO_AddAssign: - case BO_SubAssign: - case BO_DivAssign: - case BO_RemAssign: - case BO_ShlAssign: - case BO_ShrAssign: - case BO_Comma: - llvm_unreachable("Unexpected reduction operation"); - } - if (Init) { + if (Init && DeclareReductionRef.isUnset()) { AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false, /*TypeMayContainAuto=*/false); - } else + } else if (!Init) ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false); - if (!RHSVD->hasInit()) { + if (RHSVD->isInvalidDecl()) + continue; + if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) { Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type << ReductionIdRange; - if (VD) { - bool IsDecl = VD->isThisDeclarationADefinition(Context) == - VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - } + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; continue; } // Store initializer for single element in private copy. Will be used during // codegen. PrivateVD->setInit(RHSVD->getInit()); PrivateVD->setInitStyle(RHSVD->getInitStyle()); - auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc); - auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc); auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc); - ExprResult ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK, - LHSDRE, RHSDRE); - if (ReductionOp.isUsable()) { - if (BOK != BO_LT && BOK != BO_GT) { - ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), - BO_Assign, LHSDRE, ReductionOp.get()); - } else { - auto *ConditionalOp = new (Context) ConditionalOperator( - ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), - RHSDRE, Type, VK_LValue, OK_Ordinary); - ReductionOp = - BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), - BO_Assign, LHSDRE, ConditionalOp); + ExprResult ReductionOp; + if (DeclareReductionRef.isUsable()) { + QualType RedTy = DeclareReductionRef.get()->getType(); + QualType PtrRedTy = Context.getPointerType(RedTy); + ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE); + ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE); + if (!BasePath.empty()) { + LHS = DefaultLvalueConversion(LHS.get()); + RHS = DefaultLvalueConversion(RHS.get()); + LHS = ImplicitCastExpr::Create(Context, PtrRedTy, + CK_UncheckedDerivedToBase, LHS.get(), + &BasePath, LHS.get()->getValueKind()); + RHS = ImplicitCastExpr::Create(Context, PtrRedTy, + CK_UncheckedDerivedToBase, RHS.get(), + &BasePath, RHS.get()->getValueKind()); } - ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + FunctionProtoType::ExtProtoInfo EPI; + QualType Params[] = {PtrRedTy, PtrRedTy}; + QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI); + auto *OVE = new (Context) OpaqueValueExpr( + ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary, + DefaultLvalueConversion(DeclareReductionRef.get()).get()); + Expr *Args[] = {LHS.get(), RHS.get()}; + ReductionOp = new (Context) + CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc); + } else { + ReductionOp = BuildBinOp(DSAStack->getCurScope(), + ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE); + if (ReductionOp.isUsable()) { + if (BOK != BO_LT && BOK != BO_GT) { + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ReductionOp.get()); + } else { + auto *ConditionalOp = new (Context) ConditionalOperator( + ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(), + RHSDRE, Type, VK_LValue, OK_Ordinary); + ReductionOp = + BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), + BO_Assign, LHSDRE, ConditionalOp); + } + ReductionOp = ActOnFinishFullExpr(ReductionOp.get()); + } + if (ReductionOp.isInvalid()) + continue; } - if (ReductionOp.isInvalid()) - continue; - DSAStack->addDSA(VD, DE, OMPC_reduction); - Vars.push_back(RefExpr); + DeclRefExpr *Ref = nullptr; + Expr *VarsExpr = RefExpr->IgnoreParens(); + if (!VD && !CurContext->isDependentContext()) { + if (ASE || OASE) { + TransformExprToCaptures RebuildToCapture(*this, D); + VarsExpr = + RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get(); + Ref = RebuildToCapture.getCapturedExpr(); + } else { + VarsExpr = Ref = + buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + } + if (!IsOpenMPCapturedDecl(D)) { + ExprCaptures.push_back(Ref->getDecl()); + if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + SimpleRefExpr, RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); + } + } + } + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref); + Vars.push_back(VarsExpr); Privates.push_back(PrivateDRE); LHSs.push_back(LHSDRE); RHSs.push_back(RHSDRE); @@ -7615,7 +9502,67 @@ OMPClause *Sema::ActOnOpenMPReductionClause( return OMPReductionClause::Create( Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars, ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates, - LHSs, RHSs, ReductionOps); + LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); +} + +bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind, + SourceLocation LinLoc) { + if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || + LinKind == OMPC_LINEAR_unknown) { + Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus; + return true; + } + return false; +} + +bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc, + OpenMPLinearClauseKind LinKind, + QualType Type) { + auto *VD = dyn_cast_or_null<VarDecl>(D); + // A variable must not have an incomplete type or a reference type. + if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type)) + return true; + if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) && + !Type->isReferenceType()) { + Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference) + << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind); + return true; + } + Type = Type.getNonReferenceType(); + + // A list item must not be const-qualified. + if (Type.isConstant(Context)) { + Diag(ELoc, diag::err_omp_const_variable) + << getOpenMPClauseName(OMPC_linear); + if (D) { + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + return true; + } + + // A list item must be of integral or pointer type. + Type = Type.getUnqualifiedType().getCanonicalType(); + const auto *Ty = Type.getTypePtrOrNull(); + if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && + !Ty->isPointerType())) { + Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type; + if (D) { + bool IsDecl = + !VD || + VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; + Diag(D->getLocation(), + IsDecl ? diag::note_previous_decl : diag::note_defined_here) + << D; + } + return true; + } + return false; } OMPClause *Sema::ActOnOpenMPLinearClause( @@ -7625,121 +9572,84 @@ OMPClause *Sema::ActOnOpenMPLinearClause( SmallVector<Expr *, 8> Vars; SmallVector<Expr *, 8> Privates; SmallVector<Expr *, 8> Inits; - if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) || - LinKind == OMPC_LINEAR_unknown) { - Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus; + SmallVector<Decl *, 4> ExprCaptures; + SmallVector<Expr *, 4> ExprPostUpdates; + if (CheckOpenMPLinearModifier(LinKind, LinLoc)) LinKind = OMPC_LINEAR_val; - } for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP linear clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); Privates.push_back(nullptr); Inits.push_back(nullptr); - continue; } - - // OpenMP [2.14.3.7, linear clause] - // A list item that appears in a linear clause is subject to the private - // clause semantics described in Section 2.14.3.3 on page 159 except as - // noted. In addition, the value of the new list item on each iteration - // of the associated loop(s) corresponds to the value of the original - // list item before entering the construct plus the logical number of - // the iteration times linear-step. - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.3.3, Restrictions, p.1] - // A variable that is part of another variable (as an array or - // structure element) cannot appear in a private clause. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - VarDecl *VD = cast<VarDecl>(DE->getDecl()); + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.3.7, linear clause] // A list-item cannot appear in more than one linear clause. // A list-item that appears in a linear clause cannot appear in any // other data-sharing attribute clause. - DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false); + DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false); if (DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_linear); - ReportOriginalDSA(*this, DSAStack, VD, DVar); - continue; - } - - QualType QType = VD->getType(); - if (QType->isDependentType() || QType->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - Privates.push_back(nullptr); - Inits.push_back(nullptr); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } - // A variable must not have an incomplete type or a reference type. - if (RequireCompleteType(ELoc, QType, - diag::err_omp_linear_incomplete_type)) { - continue; - } - if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) && - !QType->isReferenceType()) { - Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference) - << QType << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind); + if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type)) continue; - } - QType = QType.getNonReferenceType(); - - // A list item must not be const-qualified. - if (QType.isConstant(Context)) { - Diag(ELoc, diag::err_omp_const_variable) - << getOpenMPClauseName(OMPC_linear); - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } - - // A list item must be of integral or pointer type. - QType = QType.getUnqualifiedType().getCanonicalType(); - const Type *Ty = QType.getTypePtrOrNull(); - if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) && - !Ty->isPointerType())) { - Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType; - bool IsDecl = - VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), - IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; - continue; - } + Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType(); // Build private copy of original var. - auto *Private = buildVarDecl(*this, ELoc, QType, VD->getName(), - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PrivateRef = buildDeclRefExpr( - *this, Private, DE->getType().getUnqualifiedType(), DE->getExprLoc()); + auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(), + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc); // Build var to save initial value. - VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start"); + VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start"); Expr *InitExpr; + DeclRefExpr *Ref = nullptr; + if (!VD && !CurContext->isDependentContext()) { + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false); + if (!IsOpenMPCapturedDecl(D)) { + ExprCaptures.push_back(Ref->getDecl()); + if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) { + ExprResult RefRes = DefaultLvalueConversion(Ref); + if (!RefRes.isUsable()) + continue; + ExprResult PostUpdateRes = + BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, + SimpleRefExpr, RefRes.get()); + if (!PostUpdateRes.isUsable()) + continue; + ExprPostUpdates.push_back( + IgnoredValueConversions(PostUpdateRes.get()).get()); + } + } + } if (LinKind == OMPC_LINEAR_uval) - InitExpr = VD->getInit(); + InitExpr = VD ? VD->getInit() : SimpleRefExpr; else - InitExpr = DE; + InitExpr = VD ? SimpleRefExpr : Ref; AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(), - /*DirectInit*/ false, /*TypeMayContainAuto*/ false); - auto InitRef = buildDeclRefExpr( - *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc()); - DSAStack->addDSA(VD, DE, OMPC_linear); - Vars.push_back(DE); + /*DirectInit=*/false, /*TypeMayContainAuto=*/false); + auto InitRef = buildDeclRefExpr(*this, Init, Type, ELoc); + + DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref); + Vars.push_back((VD || CurContext->isDependentContext()) + ? RefExpr->IgnoreParens() + : Ref); Privates.push_back(PrivateRef); Inits.push_back(InitRef); } @@ -7783,12 +9693,14 @@ OMPClause *Sema::ActOnOpenMPLinearClause( return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc, ColonLoc, EndLoc, Vars, Privates, Inits, - StepExpr, CalcStepExpr); + StepExpr, CalcStepExpr, + buildPreInits(Context, ExprCaptures), + buildPostUpdate(*this, ExprPostUpdates)); } static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Expr *NumIterations, Sema &SemaRef, - Scope *S) { + Scope *S, DSAStackTy *Stack) { // Walk the vars and build update/final expressions for the CodeGen. SmallVector<Expr *, 8> Updates; SmallVector<Expr *, 8> Finals; @@ -7798,17 +9710,35 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, // If linear-step is not specified it is assumed to be 1. if (Step == nullptr) Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get(); - else if (CalcStep) + else if (CalcStep) { Step = cast<BinaryOperator>(CalcStep)->getLHS(); + } bool HasErrors = false; auto CurInit = Clause.inits().begin(); auto CurPrivate = Clause.privates().begin(); auto LinKind = Clause.getModifier(); for (auto &RefExpr : Clause.varlists()) { + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + ValueDecl *D = Res.first; + if (Res.second || !D) { + Updates.push_back(nullptr); + Finals.push_back(nullptr); + HasErrors = true; + continue; + } + if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) { + D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts()) + ->getMemberDecl(); + } + auto &&Info = Stack->isLoopControlVariable(D); Expr *InitExpr = *CurInit; // Build privatized reference to the current linear var. - auto DE = cast<DeclRefExpr>(RefExpr); + auto DE = cast<DeclRefExpr>(SimpleRefExpr); Expr *CapturedRef; if (LinKind == OMPC_LINEAR_uval) CapturedRef = cast<VarDecl>(DE->getDecl())->getInit(); @@ -7819,18 +9749,27 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, /*RefersToCapture=*/true); // Build update: Var = InitExpr + IV * Step - ExprResult Update = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, - InitExpr, IV, Step, /* Subtract */ false); + ExprResult Update; + if (!Info.first) { + Update = + BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate, + InitExpr, IV, Step, /* Subtract */ false); + } else + Update = *CurPrivate; Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(), /*DiscardedValue=*/true); // Build final: Var = InitExpr + NumIterations * Step - ExprResult Final = - BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, - InitExpr, NumIterations, Step, /* Subtract */ false); + ExprResult Final; + if (!Info.first) { + Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef, + InitExpr, NumIterations, Step, + /* Subtract */ false); + } else + Final = *CurPrivate; Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(), /*DiscardedValue=*/true); + if (!Update.isUsable() || !Final.isUsable()) { Updates.push_back(nullptr); Finals.push_back(nullptr); @@ -7839,7 +9778,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV, Updates.push_back(Update.get()); Finals.push_back(Final.get()); } - ++CurInit, ++CurPrivate; + ++CurInit; + ++CurPrivate; } Clause.setUpdates(Updates); Clause.setFinals(Finals); @@ -7852,52 +9792,55 @@ OMPClause *Sema::ActOnOpenMPAlignedClause( SmallVector<Expr *, 8> Vars; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP aligned clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP linear clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - VarDecl *VD = cast<VarDecl>(DE->getDecl()); + QualType QType = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.8.1, simd construct, Restrictions] // The type of list items appearing in the aligned clause must be // array, pointer, reference to array, or reference to pointer. - QualType QType = VD->getType(); QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType(); const Type *Ty = QType.getTypePtrOrNull(); - if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() && - !Ty->isPointerType())) { + if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) { Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr) - << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange(); + << QType << getLangOpts().CPlusPlus << ERange; bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } // OpenMP [2.8.1, simd construct, Restrictions] // A list-item cannot appear in more than one aligned clause. - if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) { - Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange(); + if (Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) { + Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange; Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa) << getOpenMPClauseName(OMPC_aligned); continue; } - Vars.push_back(DE); + DeclRefExpr *Ref = nullptr; + if (!VD && IsOpenMPCapturedDecl(D)) + Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true); + Vars.push_back(DefaultFunctionArrayConversion( + (VD || !Ref) ? RefExpr->IgnoreParens() : Ref) + .get()); } // OpenMP [2.8.1, simd construct, Description] @@ -7945,7 +9888,8 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList, // A list item that appears in a copyin clause must be threadprivate. DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + Diag(ELoc, diag::err_omp_expected_var_name_member_expr) + << 0 << RefExpr->getSourceRange(); continue; } @@ -8020,51 +9964,37 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, SmallVector<Expr *, 8> DstExprs; SmallVector<Expr *, 8> AssignmentOps; for (auto &RefExpr : VarList) { - assert(RefExpr && "NULL expr in OpenMP copyprivate clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr)) { + assert(RefExpr && "NULL expr in OpenMP linear clause."); + SourceLocation ELoc; + SourceRange ERange; + Expr *SimpleRefExpr = RefExpr; + auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { // It will be analyzed later. Vars.push_back(RefExpr); SrcExprs.push_back(nullptr); DstExprs.push_back(nullptr); AssignmentOps.push_back(nullptr); - continue; } - - SourceLocation ELoc = RefExpr->getExprLoc(); - // OpenMP [2.1, C/C++] - // A list item is a variable name. - // OpenMP [2.14.4.1, Restrictions, p.1] - // A list item that appears in a copyin clause must be threadprivate. - DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr); - if (!DE || !isa<VarDecl>(DE->getDecl())) { - Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange(); + ValueDecl *D = Res.first; + if (!D) continue; - } - Decl *D = DE->getDecl(); - VarDecl *VD = cast<VarDecl>(D); - - QualType Type = VD->getType(); - if (Type->isDependentType() || Type->isInstantiationDependentType()) { - // It will be analyzed later. - Vars.push_back(DE); - SrcExprs.push_back(nullptr); - DstExprs.push_back(nullptr); - AssignmentOps.push_back(nullptr); - continue; - } + QualType Type = D->getType(); + auto *VD = dyn_cast<VarDecl>(D); // OpenMP [2.14.4.2, Restrictions, p.2] // A list item that appears in a copyprivate clause may not appear in a // private or firstprivate clause on the single construct. - if (!DSAStack->isThreadPrivate(VD)) { - auto DVar = DSAStack->getTopDSA(VD, false); + if (!VD || !DSAStack->isThreadPrivate(VD)) { + auto DVar = DSAStack->getTopDSA(D, false); if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate && DVar.RefExpr) { Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind) << getOpenMPClauseName(OMPC_copyprivate); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } @@ -8072,12 +10002,12 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, // All list items that appear in a copyprivate clause must be either // threadprivate or private in the enclosing context. if (DVar.CKind == OMPC_unknown) { - DVar = DSAStack->getImplicitDSA(VD, false); + DVar = DSAStack->getImplicitDSA(D, false); if (DVar.CKind == OMPC_shared) { Diag(ELoc, diag::err_omp_required_access) << getOpenMPClauseName(OMPC_copyprivate) << "threadprivate or private in the enclosing context"; - ReportOriginalDSA(*this, DSAStack, VD, DVar); + ReportOriginalDSA(*this, DSAStack, D, DVar); continue; } } @@ -8089,10 +10019,11 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, << getOpenMPClauseName(OMPC_copyprivate) << Type << getOpenMPDirectiveName(DSAStack->getCurrentDirective()); bool IsDecl = + !VD || VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly; - Diag(VD->getLocation(), + Diag(D->getLocation(), IsDecl ? diag::note_previous_decl : diag::note_defined_here) - << VD; + << D; continue; } @@ -8103,27 +10034,29 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList, Type = Context.getBaseElementType(Type.getNonReferenceType()) .getUnqualifiedType(); auto *SrcVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); - auto *PseudoSrcExpr = - buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc()); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.src", + D->hasAttrs() ? &D->getAttrs() : nullptr); + auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc); auto *DstVD = - buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst", - VD->hasAttrs() ? &VD->getAttrs() : nullptr); + buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst", + D->hasAttrs() ? &D->getAttrs() : nullptr); auto *PseudoDstExpr = - buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc()); - auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign, + buildDeclRefExpr(*this, DstVD, Type, ELoc); + auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, PseudoDstExpr, PseudoSrcExpr); if (AssignmentOp.isInvalid()) continue; - AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(), + AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc, /*DiscardedValue=*/true); if (AssignmentOp.isInvalid()) continue; // No need to mark vars as copyprivate, they are already threadprivate or // implicitly private. - Vars.push_back(DE); + assert(VD || IsOpenMPCapturedDecl(D)); + Vars.push_back( + VD ? RefExpr->IgnoreParens() + : buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false)); SrcExprs.push_back(PseudoSrcExpr); DstExprs.push_back(PseudoDstExpr); AssignmentOps.push_back(AssignmentOp.get()); @@ -8168,6 +10101,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, return nullptr; } SmallVector<Expr *, 8> Vars; + DSAStackTy::OperatorOffsetTy OpsOffs; llvm::APSInt DepCounter(/*BitWidth=*/32); llvm::APSInt TotalDepCount(/*BitWidth=*/32); if (DepKind == OMPC_DEPEND_sink) { @@ -8180,8 +10114,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, DSAStack->getParentOrderedRegionParam()) { for (auto &RefExpr : VarList) { assert(RefExpr && "NULL expr in OpenMP shared clause."); - if (isa<DependentScopeDeclRefExpr>(RefExpr) || - (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) { + if (isa<DependentScopeDeclRefExpr>(RefExpr)) { // It will be analyzed later. Vars.push_back(RefExpr); continue; @@ -8203,61 +10136,66 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, // directive, xi denotes the loop iteration variable of the i-th nested // loop associated with the loop directive, and di is a constant // non-negative integer. + if (CurContext->isDependentContext()) { + // It will be analyzed later. + Vars.push_back(RefExpr); + continue; + } SimpleExpr = SimpleExpr->IgnoreImplicit(); - auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); - if (!DE) { - OverloadedOperatorKind OOK = OO_None; - SourceLocation OOLoc; - Expr *LHS, *RHS; - if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) { - OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); - OOLoc = BO->getOperatorLoc(); - LHS = BO->getLHS()->IgnoreParenImpCasts(); - RHS = BO->getRHS()->IgnoreParenImpCasts(); - } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) { - OOK = OCE->getOperator(); - OOLoc = OCE->getOperatorLoc(); - LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); - } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) { - OOK = MCE->getMethodDecl() - ->getNameInfo() - .getName() - .getCXXOverloadedOperator(); - OOLoc = MCE->getCallee()->getExprLoc(); - LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); - RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); - } else { - Diag(ELoc, diag::err_omp_depend_sink_wrong_expr); - continue; - } - DE = dyn_cast<DeclRefExpr>(LHS); - if (!DE) { - Diag(LHS->getExprLoc(), - diag::err_omp_depend_sink_expected_loop_iteration) - << DSAStack->getParentLoopControlVariable( - DepCounter.getZExtValue()); - continue; - } - if (OOK != OO_Plus && OOK != OO_Minus) { - Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); - continue; - } - ExprResult Res = VerifyPositiveIntegerConstantInClause( + OverloadedOperatorKind OOK = OO_None; + SourceLocation OOLoc; + Expr *LHS = SimpleExpr; + Expr *RHS = nullptr; + if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) { + OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode()); + OOLoc = BO->getOperatorLoc(); + LHS = BO->getLHS()->IgnoreParenImpCasts(); + RHS = BO->getRHS()->IgnoreParenImpCasts(); + } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) { + OOK = OCE->getOperator(); + OOLoc = OCE->getOperatorLoc(); + LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts(); + } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) { + OOK = MCE->getMethodDecl() + ->getNameInfo() + .getName() + .getCXXOverloadedOperator(); + OOLoc = MCE->getCallee()->getExprLoc(); + LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts(); + RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts(); + } + SourceLocation ELoc; + SourceRange ERange; + auto Res = getPrivateItem(*this, LHS, ELoc, ERange, + /*AllowArraySection=*/false); + if (Res.second) { + // It will be analyzed later. + Vars.push_back(RefExpr); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) { + Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus); + continue; + } + if (RHS) { + ExprResult RHSRes = VerifyPositiveIntegerConstantInClause( RHS, OMPC_depend, /*StrictlyPositive=*/false); - if (Res.isInvalid()) + if (RHSRes.isInvalid()) continue; } - auto *VD = dyn_cast<VarDecl>(DE->getDecl()); if (!CurContext->isDependentContext() && DSAStack->getParentOrderedRegionParam() && - (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) { - Diag(DE->getExprLoc(), - diag::err_omp_depend_sink_expected_loop_iteration) + DepCounter != DSAStack->isParentLoopControlVariable(D).first) { + Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration) << DSAStack->getParentLoopControlVariable( - DepCounter.getZExtValue()); + DepCounter.getZExtValue()); continue; } + OpsOffs.push_back({RHS, OOK}); } else { // OpenMP [2.11.1.1, Restrictions, p.3] // A variable that is part of another variable (such as a field of a @@ -8268,14 +10206,17 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); if (!RefExpr->IgnoreParenImpCasts()->isLValue() || (!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) || - (ASE && !ASE->getBase()->getType()->isAnyPointerType() && - !ASE->getBase()->getType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) - << RefExpr->getSourceRange(); + (ASE && + !ASE->getBase() + ->getType() + .getNonReferenceType() + ->isPointerType() && + !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) { + Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item) + << 0 << RefExpr->getSourceRange(); continue; } } - Vars.push_back(RefExpr->IgnoreParenImpCasts()); } @@ -8289,9 +10230,11 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind, Vars.empty()) return nullptr; } - - return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind, - DepLoc, ColonLoc, Vars); + auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, + DepKind, DepLoc, ColonLoc, Vars); + if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source) + DSAStack->addDoacrossDependClause(C, OpsOffs); + return C; } OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc, @@ -8366,125 +10309,950 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef, return true; } -OMPClause *Sema::ActOnOpenMPMapClause( - OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, - SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) { - SmallVector<Expr *, 4> Vars; +/// \brief Return true if it can be proven that the provided array expression +/// (array section or array subscript) does NOT specify the whole size of the +/// array whose base type is \a BaseQTy. +static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef, + const Expr *E, + QualType BaseQTy) { + auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + + // If this is an array subscript, it refers to the whole size if the size of + // the dimension is constant and equals 1. Also, an array section assumes the + // format of an array subscript if no colon is used. + if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) { + if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + return ATy->getSize().getSExtValue() != 1; + // Size can't be evaluated statically. + return false; + } - for (auto &RE : VarList) { - assert(RE && "Null expr in omp map"); - if (isa<DependentScopeDeclRefExpr>(RE)) { - // It will be analyzed later. - Vars.push_back(RE); + assert(OASE && "Expecting array section if not an array subscript."); + auto *LowerBound = OASE->getLowerBound(); + auto *Length = OASE->getLength(); + + // If there is a lower bound that does not evaluates to zero, we are not + // convering the whole dimension. + if (LowerBound) { + llvm::APSInt ConstLowerBound; + if (!LowerBound->EvaluateAsInt(ConstLowerBound, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + if (ConstLowerBound.getSExtValue()) + return true; + } + + // If we don't have a length we covering the whole dimension. + if (!Length) + return false; + + // If the base is a pointer, we don't have a way to get the size of the + // pointee. + if (BaseQTy->isPointerType()) + return false; + + // We can only check if the length is the same as the size of the dimension + // if we have a constant array. + auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()); + if (!CATy) + return false; + + llvm::APSInt ConstLength; + if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + + return CATy->getSize().getSExtValue() != ConstLength.getSExtValue(); +} + +// Return true if it can be proven that the provided array expression (array +// 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) { + auto *OASE = dyn_cast<OMPArraySectionExpr>(E); + + // An array subscript always refer to a single element. Also, an array section + // assumes the format of an array subscript if no colon is used. + if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) + return false; + + assert(OASE && "Expecting array section if not an array subscript."); + auto *Length = OASE->getLength(); + + // If we don't have a length we have to check if the array has unitary size + // for this dimension. Also, we should always expect a length if the base type + // is pointer. + if (!Length) { + if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr())) + return ATy->getSize().getSExtValue() != 1; + // We cannot assume anything. + return false; + } + + // Check if the length evaluates to 1. + llvm::APSInt ConstLength; + if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext())) + return false; // Can't get the integer value as a constant. + + return ConstLength.getSExtValue() != 1; +} + +// Return the expression of the base of the mappable expression or null if it +// cannot be determined and do all the necessary checks to see if the expression +// is valid as a standalone mappable expression. In the process, record all the +// components of the expression. +static Expr *CheckMapClauseExpressionBase( + Sema &SemaRef, Expr *E, + OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents, + OpenMPClauseKind CKind) { + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + + // The base of elements of list in a map clause have to be either: + // - a reference to variable or field. + // - a member expression. + // - an array expression. + // + // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the + // reference to 'r'. + // + // If we have: + // + // struct SS { + // Bla S; + // foo() { + // #pragma omp target map (S.Arr[:12]); + // } + // } + // + // We want to retrieve the member expression 'this->S'; + + Expr *RelevantExpr = nullptr; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2] + // If a list item is an array section, it must specify contiguous storage. + // + // For this restriction it is sufficient that we make sure only references + // to variables or fields and array expressions, and that no array sections + // exist except in the rightmost expression (unless they cover the whole + // dimension of the array). E.g. these would be invalid: + // + // r.ArrS[3:5].Arr[6:7] + // + // r.ArrS[3:5].x + // + // but these would be valid: + // r.ArrS[3].Arr[6:7] + // + // r.ArrS[3].x + + bool AllowUnitySizeArraySection = true; + bool AllowWholeSizeArraySection = true; + + while (!RelevantExpr) { + E = E->IgnoreParenImpCasts(); + + if (auto *CurE = dyn_cast<DeclRefExpr>(E)) { + if (!isa<VarDecl>(CurE->getDecl())) + break; + + RelevantExpr = CurE; + + // If we got a reference to a declaration, we should not expect any array + // section before that. + AllowUnitySizeArraySection = false; + AllowWholeSizeArraySection = false; + + // Record the component. + CurComponents.push_back(OMPClauseMappableExprCommon::MappableComponent( + CurE, CurE->getDecl())); + continue; + } + + if (auto *CurE = dyn_cast<MemberExpr>(E)) { + auto *BaseE = CurE->getBase()->IgnoreParenImpCasts(); + + if (isa<CXXThisExpr>(BaseE)) + // We found a base expression: this->Val. + RelevantExpr = CurE; + else + E = BaseE; + + if (!isa<FieldDecl>(CurE->getMemberDecl())) { + SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field) + << CurE->getSourceRange(); + break; + } + + auto *FD = cast<FieldDecl>(CurE->getMemberDecl()); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3] + // A bit-field cannot appear in a map clause. + // + if (FD->isBitField()) { + SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause) + << CurE->getSourceRange() << getOpenMPClauseName(CKind); + break; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + QualType CurType = BaseE->getType().getNonReferenceType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2] + // A list item cannot be a variable that is a member of a structure with + // a union type. + // + if (auto *RT = CurType->getAs<RecordType>()) + if (RT->isUnionType()) { + SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed) + << CurE->getSourceRange(); + break; + } + + // If we got a member expression, we should not expect any array section + // before that: + // + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7] + // If a list item is an element of a structure, only the rightmost symbol + // of the variable reference can be an array section. + // + AllowUnitySizeArraySection = false; + AllowWholeSizeArraySection = false; + + // Record the component. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, FD)); + continue; + } + + if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) { + E = CurE->getBase()->IgnoreParenImpCasts(); + + if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << CurE->getSourceRange(); + break; + } + + // If we got an array subscript that express the whole dimension we + // can have any array expressions before. If it only expressing part of + // the dimension, we can only have unitary-size array expressions. + if (CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, + E->getType())) + AllowWholeSizeArraySection = false; + + // Record the component - we don't have any declaration associated. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); + continue; + } + + if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) { + E = CurE->getBase()->IgnoreParenImpCasts(); + + auto CurType = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + if (CurType->isReferenceType()) + CurType = CurType->getPointeeType(); + + bool IsPointer = CurType->isAnyPointerType(); + + if (!IsPointer && !CurType->isArrayType()) { + SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name) + << 0 << CurE->getSourceRange(); + break; + } + + bool NotWhole = + CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType); + bool NotUnity = + CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType); + + if (AllowWholeSizeArraySection && AllowUnitySizeArraySection) { + // Any array section is currently allowed. + // + // 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)) { + // A unity or whole array section is not allowed and that is not + // compatible with the properties of the current array section. + SemaRef.Diag( + ELoc, diag::err_array_section_does_not_specify_contiguous_storage) + << CurE->getSourceRange(); + break; + } + + // Record the component - we don't have any declaration associated. + CurComponents.push_back( + OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr)); continue; } + + // If nothing else worked, this is not a valid map clause expression. + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << ERange; + break; + } + + return RelevantExpr; +} + +// Return true if expression E associated with value VD has conflicts with other +// map information. +static bool CheckMapConflicts( + Sema &SemaRef, DSAStackTy *DSAS, ValueDecl *VD, Expr *E, + bool CurrentRegionOnly, + OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents, + OpenMPClauseKind CKind) { + assert(VD && E); + SourceLocation ELoc = E->getExprLoc(); + SourceRange ERange = E->getSourceRange(); + + // In order to easily check the conflicts we need to match each component of + // the expression under test with the components of the expressions that are + // already in the stack. + + assert(!CurComponents.empty() && "Map clause expression with no components!"); + assert(CurComponents.back().getAssociatedDeclaration() == VD && + "Map clause expression with unexpected base!"); + + // Variables to help detecting enclosing problems in data environment nests. + bool IsEnclosedByDataEnvironmentExpr = false; + const Expr *EnclosingExpr = nullptr; + + bool FoundError = DSAS->checkMappableExprComponentListsForDecl( + VD, CurrentRegionOnly, + [&](OMPClauseMappableExprCommon::MappableExprComponentListRef + StackComponents) -> bool { + + assert(!StackComponents.empty() && + "Map clause expression with no components!"); + assert(StackComponents.back().getAssociatedDeclaration() == VD && + "Map clause expression with unexpected base!"); + + // The whole expression in the stack. + auto *RE = StackComponents.front().getAssociatedExpression(); + + // Expressions must start from the same base. Here we detect at which + // point both expressions diverge from each other and see if we can + // detect if the memory referred to both expressions is contiguous and + // do not overlap. + auto CI = CurComponents.rbegin(); + auto CE = CurComponents.rend(); + auto SI = StackComponents.rbegin(); + auto SE = StackComponents.rend(); + for (; CI != CE && SI != SE; ++CI, ++SI) { + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.3] + // At most one list item can be an array item derived from a given + // variable in map clauses of the same construct. + if (CurrentRegionOnly && + (isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) && + (isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) || + isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) { + SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(), + diag::err_omp_multiple_array_items_in_map_clause) + << CI->getAssociatedExpression()->getSourceRange(); + SemaRef.Diag(SI->getAssociatedExpression()->getExprLoc(), + diag::note_used_here) + << SI->getAssociatedExpression()->getSourceRange(); + return true; + } + + // Do both expressions have the same kind? + if (CI->getAssociatedExpression()->getStmtClass() != + SI->getAssociatedExpression()->getStmtClass()) + break; + + // Are we dealing with different variables/fields? + if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration()) + break; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4] + // List items of map clauses in the same construct must not share + // original storage. + // + // If the expressions are exactly the same or one is a subset of the + // other, it means they are sharing storage. + if (CI == CE && SI == SE) { + if (CurrentRegionOnly) { + if (CKind == OMPC_map) + SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; + else { + assert(CKind == OMPC_to || CKind == OMPC_from); + SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) + << ERange; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } else { + // If we find the same expression in the enclosing data environment, + // that is legal. + IsEnclosedByDataEnvironmentExpr = true; + return false; + } + } + + QualType DerivedType = + std::prev(CI)->getAssociatedDeclaration()->getType(); + SourceLocation DerivedLoc = + std::prev(CI)->getAssociatedExpression()->getExprLoc(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type + // will be considered to be T for all purposes of this clause. + DerivedType = DerivedType.getNonReferenceType(); + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.1] + // A variable for which the type is pointer and an array section + // derived from that variable must not appear as list items of map + // clauses of the same construct. + // + // Also, cover one of the cases in: + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5] + // If any part of the original storage of a list item has corresponding + // storage in the device data environment, all of the original storage + // must have corresponding storage in the device data environment. + // + if (DerivedType->isAnyPointerType()) { + if (CI == CE || SI == SE) { + SemaRef.Diag( + DerivedLoc, + diag::err_omp_pointer_mapped_along_with_derived_section) + << DerivedLoc; + } else { + assert(CI != CE && SI != SE); + SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_derreferenced) + << DerivedLoc; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4] + // List items of map clauses in the same construct must not share + // original storage. + // + // An expression is a subset of the other. + if (CurrentRegionOnly && (CI == CE || SI == SE)) { + if (CKind == OMPC_map) + SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange; + else { + assert(CKind == OMPC_to || CKind == OMPC_from); + SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update) + << ERange; + } + SemaRef.Diag(RE->getExprLoc(), diag::note_used_here) + << RE->getSourceRange(); + return true; + } + + // The current expression uses the same base as other expression in the + // data environment but does not contain it completely. + if (!CurrentRegionOnly && SI != SE) + EnclosingExpr = RE; + + // The current expression is a subset of the expression in the data + // environment. + IsEnclosedByDataEnvironmentExpr |= + (!CurrentRegionOnly && CI != CE && SI == SE); + + return false; + }); + + if (CurrentRegionOnly) + return FoundError; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5] + // If any part of the original storage of a list item has corresponding + // storage in the device data environment, all of the original storage must + // have corresponding storage in the device data environment. + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.6] + // If a list item is an element of a structure, and a different element of + // the structure has a corresponding list item in the device data environment + // prior to a task encountering the construct associated with the map clause, + // then the list item must also have a corresponding list item in the device + // data environment prior to the task encountering the construct. + // + if (EnclosingExpr && !IsEnclosedByDataEnvironmentExpr) { + SemaRef.Diag(ELoc, + diag::err_omp_original_storage_is_shared_and_does_not_contain) + << ERange; + SemaRef.Diag(EnclosingExpr->getExprLoc(), diag::note_used_here) + << EnclosingExpr->getSourceRange(); + return true; + } + + return FoundError; +} + +namespace { +// Utility struct that gathers all the related lists associated with a mappable +// expression. +struct MappableVarListInfo final { + // The list of expressions. + ArrayRef<Expr *> VarList; + // The list of processed expressions. + SmallVector<Expr *, 16> ProcessedVarList; + // The mappble components for each expression. + OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents; + // The base declaration of the variable. + SmallVector<ValueDecl *, 16> VarBaseDeclarations; + + MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) { + // We have a list of components and base declarations for each entry in the + // variable list. + VarComponents.reserve(VarList.size()); + VarBaseDeclarations.reserve(VarList.size()); + } +}; +} + +// Check the validity of the provided variable list for the provided clause kind +// \a CKind. In the check process the valid expressions, and mappable expression +// components and variables are extracted and used to fill \a Vars, +// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and +// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'. +static void +checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS, + OpenMPClauseKind CKind, MappableVarListInfo &MVLI, + SourceLocation StartLoc, + OpenMPMapClauseKind MapType = OMPC_MAP_unknown, + bool IsMapTypeImplicit = false) { + // We only expect mappable expressions in 'to', 'from', and 'map' clauses. + assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) && + "Unexpected clause kind with mappable expressions!"); + + // Keep track of the mappable components and base declarations in this clause. + // Each entry in the list is going to have a list of components associated. We + // record each set of the components so that we can build the clause later on. + // In the end we should have the same amount of declarations and component + // lists. + + for (auto &RE : MVLI.VarList) { + assert(RE && "Null expr in omp to/from/map clause"); SourceLocation ELoc = RE->getExprLoc(); - // OpenMP [2.14.5, Restrictions] - // A variable that is part of another variable (such as field of a - // structure) but is not an array element or an array section cannot appear - // in a map clause. auto *VE = RE->IgnoreParenLValueCasts(); if (VE->isValueDependent() || VE->isTypeDependent() || VE->isInstantiationDependent() || VE->containsUnexpandedParameterPack()) { - // It will be analyzed later. - Vars.push_back(RE); + // We can only analyze this information once the missing information is + // resolved. + MVLI.ProcessedVarList.push_back(RE); continue; } auto *SimpleExpr = RE->IgnoreParenCasts(); - auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr); - auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr); - auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr); - - if (!RE->IgnoreParenImpCasts()->isLValue() || - (!OASE && !ASE && !DE) || - (DE && !isa<VarDecl>(DE->getDecl())) || - (ASE && !ASE->getBase()->getType()->isAnyPointerType() && - !ASE->getBase()->getType()->isArrayType())) { - Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) - << RE->getSourceRange(); + + if (!RE->IgnoreParenImpCasts()->isLValue()) { + SemaRef.Diag(ELoc, + diag::err_omp_expected_named_var_member_or_array_expression) + << RE->getSourceRange(); continue; } - Decl *D = nullptr; - if (DE) { - D = DE->getDecl(); - } else if (ASE) { - auto *B = ASE->getBase()->IgnoreParenCasts(); - D = dyn_cast<DeclRefExpr>(B)->getDecl(); - } else if (OASE) { - auto *B = OASE->getBase(); - D = dyn_cast<DeclRefExpr>(B)->getDecl(); - } - assert(D && "Null decl on map clause."); - auto *VD = cast<VarDecl>(D); + OMPClauseMappableExprCommon::MappableExprComponentList CurComponents; + ValueDecl *CurDeclaration = nullptr; - // OpenMP [2.14.5, Restrictions, p.8] + // Obtain the array or member expression bases if required. Also, fill the + // components array with all the components identified in the process. + auto *BE = + CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind); + if (!BE) + continue; + + assert(!CurComponents.empty() && + "Invalid mappable expression information."); + + // For the following checks, we rely on the base declaration which is + // expected to be associated with the last component. The declaration is + // expected to be a variable or a field (if 'this' is being mapped). + CurDeclaration = CurComponents.back().getAssociatedDeclaration(); + assert(CurDeclaration && "Null decl on map clause."); + assert( + CurDeclaration->isCanonicalDecl() && + "Expecting components to have associated only canonical declarations."); + + auto *VD = dyn_cast<VarDecl>(CurDeclaration); + auto *FD = dyn_cast<FieldDecl>(CurDeclaration); + + assert((VD || FD) && "Only variables or fields are expected here!"); + (void)FD; + + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.10] // threadprivate variables cannot appear in a map clause. - if (DSAStack->isThreadPrivate(VD)) { - auto DVar = DSAStack->getTopDSA(VD, false); - Diag(ELoc, diag::err_omp_threadprivate_in_map); - ReportOriginalDSA(*this, DSAStack, VD, DVar); + // OpenMP 4.5 [2.10.5, target update Construct] + // threadprivate variables cannot appear in a from clause. + if (VD && DSAS->isThreadPrivate(VD)) { + auto DVar = DSAS->getTopDSA(VD, false); + SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause) + << getOpenMPClauseName(CKind); + ReportOriginalDSA(SemaRef, DSAS, VD, DVar); continue; } - // OpenMP [2.14.5, Restrictions, p.2] - // At most one list item can be an array item derived from a given variable - // in map clauses of the same construct. - // OpenMP [2.14.5, Restrictions, p.3] - // List items of map clauses in the same construct must not share original - // storage. - // OpenMP [2.14.5, Restrictions, C/C++, p.2] - // A variable for which the type is pointer, reference to array, or - // reference to pointer and an array section derived from that variable - // must not appear as list items of map clauses of the same construct. - DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD); - if (MI.RefExpr) { - Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; - Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) - << MI.RefExpr->getSourceRange(); + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct. + + // Check conflicts with other map clause expressions. We check the conflicts + // with the current construct separately from the enclosing data + // environment, because the restrictions are different. We only have to + // check conflicts across regions for the map clauses. + if (CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + /*CurrentRegionOnly=*/true, CurComponents, CKind)) + break; + if (CKind == OMPC_map && + CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr, + /*CurrentRegionOnly=*/false, CurComponents, CKind)) + break; + + // OpenMP 4.5 [2.10.5, target update Construct] + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1] + // If the type of a list item is a reference to a type T then the type will + // be considered to be T for all purposes of this clause. + QualType Type = CurDeclaration->getType().getNonReferenceType(); + + // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4] + // A list item in a to or from clause must have a mappable type. + // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9] + // A list item must have a mappable type. + if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef, + DSAS, Type)) continue; + + if (CKind == OMPC_map) { + // target enter data + // OpenMP [2.10.2, Restrictions, p. 99] + // A map-type must be specified in all map clauses and must be either + // to or alloc. + OpenMPDirectiveKind DKind = DSAS->getCurrentDirective(); + if (DKind == OMPD_target_enter_data && + !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) { + SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) + << (IsMapTypeImplicit ? 1 : 0) + << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) + << getOpenMPDirectiveName(DKind); + continue; + } + + // target exit_data + // OpenMP [2.10.3, Restrictions, p. 102] + // A map-type must be specified in all map clauses and must be either + // from, release, or delete. + if (DKind == OMPD_target_exit_data && + !(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release || + MapType == OMPC_MAP_delete)) { + SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive) + << (IsMapTypeImplicit ? 1 : 0) + << getOpenMPSimpleClauseTypeName(OMPC_map, MapType) + << getOpenMPDirectiveName(DKind); + continue; + } + + // OpenMP 4.5 [2.15.5.1, Restrictions, p.3] + // A list item cannot appear in both a map clause and a data-sharing + // attribute clause on the same construct + if (DKind == OMPD_target && VD) { + auto DVar = DSAS->getTopDSA(VD, false); + if (isOpenMPPrivate(DVar.CKind)) { + SemaRef.Diag(ELoc, diag::err_omp_variable_in_map_and_dsa) + << getOpenMPClauseName(DVar.CKind) + << getOpenMPDirectiveName(DSAS->getCurrentDirective()); + ReportOriginalDSA(SemaRef, DSAS, CurDeclaration, DVar); + continue; + } + } } - // OpenMP [2.14.5, Restrictions, C/C++, p.3,4] - // A variable for which the type is pointer, reference to array, or - // reference to pointer must not appear as a list item if the enclosing - // device data environment already contains an array section derived from - // that variable. - // An array section derived from a variable for which the type is pointer, - // reference to array, or reference to pointer must not appear as a list - // item if the enclosing device data environment already contains that - // variable. - QualType Type = VD->getType(); - MI = DSAStack->getMapInfoForVar(VD); - if (MI.RefExpr && (isa<DeclRefExpr>(MI.RefExpr->IgnoreParenLValueCasts()) != - isa<DeclRefExpr>(VE)) && - (Type->isPointerType() || Type->isReferenceType())) { - Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc; - Diag(MI.RefExpr->getExprLoc(), diag::note_used_here) - << MI.RefExpr->getSourceRange(); - continue; + // Save the current expression. + MVLI.ProcessedVarList.push_back(RE); + + // Store the components in the stack so that they can be used to check + // against other clauses later on. + DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents); + + // Save the components and declaration to create the clause. For purposes of + // the clause creation, any component list that has has base 'this' uses + // null as base declaration. + MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1); + MVLI.VarComponents.back().append(CurComponents.begin(), + CurComponents.end()); + MVLI.VarBaseDeclarations.push_back(isa<MemberExpr>(BE) ? nullptr + : CurDeclaration); + } +} + +OMPClause * +Sema::ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc, + MapType, IsMapTypeImplicit); + + // We need to produce a map clause even if we don't have variables so that + // other diagnostics related with non-existing map clauses are accurate. + return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents, MapTypeModifier, MapType, + IsMapTypeImplicit, MapLoc); +} + +QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc, + TypeResult ParsedType) { + assert(ParsedType.isUsable()); + + QualType ReductionType = GetTypeFromParser(ParsedType.get()); + if (ReductionType.isNull()) + return QualType(); + + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++ + // A type name in a declare reduction directive cannot be a function type, an + // array type, a reference type, or a type qualified with const, volatile or + // restrict. + if (ReductionType.hasQualifiers()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0; + return QualType(); + } + + if (ReductionType->isFunctionType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1; + return QualType(); + } + if (ReductionType->isReferenceType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2; + return QualType(); + } + if (ReductionType->isArrayType()) { + Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3; + return QualType(); + } + return ReductionType; +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart( + Scope *S, DeclContext *DC, DeclarationName Name, + ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes, + AccessSpecifier AS, Decl *PrevDeclInScope) { + SmallVector<Decl *, 8> Decls; + Decls.reserve(ReductionTypes.size()); + + LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName, + ForRedeclaration); + // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions + // A reduction-identifier may not be re-declared in the current scope for the + // same type or for a type that is compatible according to the base language + // rules. + llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes; + OMPDeclareReductionDecl *PrevDRD = nullptr; + bool InCompoundScope = true; + if (S != nullptr) { + // Find previous declaration with the same name not referenced in other + // declarations. + FunctionScopeInfo *ParentFn = getEnclosingFunction(); + InCompoundScope = + (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty(); + LookupName(Lookup, S); + FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false, + /*AllowInlineNamespace=*/false); + llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious; + auto Filter = Lookup.makeFilter(); + while (Filter.hasNext()) { + auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next()); + if (InCompoundScope) { + auto I = UsedAsPrevious.find(PrevDecl); + if (I == UsedAsPrevious.end()) + UsedAsPrevious[PrevDecl] = false; + if (auto *D = PrevDecl->getPrevDeclInScope()) + UsedAsPrevious[D] = true; + } + PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] = + PrevDecl->getLocation(); + } + Filter.done(); + if (InCompoundScope) { + for (auto &PrevData : UsedAsPrevious) { + if (!PrevData.second) { + PrevDRD = PrevData.first; + break; + } + } } + } else if (PrevDeclInScope != nullptr) { + auto *PrevDRDInScope = PrevDRD = + cast<OMPDeclareReductionDecl>(PrevDeclInScope); + do { + PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] = + PrevDRDInScope->getLocation(); + PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope(); + } while (PrevDRDInScope != nullptr); + } + for (auto &TyData : ReductionTypes) { + auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType()); + bool Invalid = false; + if (I != PreviousRedeclTypes.end()) { + Diag(TyData.second, diag::err_omp_declare_reduction_redefinition) + << TyData.first; + Diag(I->second, diag::note_previous_definition); + Invalid = true; + } + PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second; + auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second, + Name, TyData.first, PrevDRD); + DC->addDecl(DRD); + DRD->setAccess(AS); + Decls.push_back(DRD); + if (Invalid) + DRD->setInvalidDecl(); + else + PrevDRD = DRD; + } - // OpenMP [2.14.5, Restrictions, C/C++, p.7] - // A list item must have a mappable type. - if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this, - DSAStack, Type)) - continue; + return DeclGroupPtrTy::make( + DeclGroupRef::Create(Context, Decls.begin(), Decls.size())); +} + +void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + getCurFunction()->setHasOMPDeclareReductionCombiner(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); - Vars.push_back(RE); - MI.RefExpr = RE; - DSAStack->addMapInfoForVar(VD, MI); + QualType ReductionType = DRD->getType(); + // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_in' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_in;' variable. + auto *OmpInParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in"); + // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_out' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_out;' variable. + auto *OmpOutParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out"); + if (S != nullptr) { + PushOnScopeChains(OmpInParm, S); + PushOnScopeChains(OmpOutParm, S); + } else { + DRD->addDecl(OmpInParm); + DRD->addDecl(OmpOutParm); } - if (Vars.empty()) - return nullptr; +} + +void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); + + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Combiner != nullptr) + DRD->setCombiner(Combiner); + else + DRD->setInvalidDecl(); +} + +void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + + // Enter new function scope. + PushFunctionScope(); + getCurFunction()->setHasBranchProtectedScope(); + + if (S != nullptr) + PushDeclContext(S, DRD); + else + CurContext = DRD; + + PushExpressionEvaluationContext(PotentiallyEvaluated); + + QualType ReductionType = DRD->getType(); + // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_priv' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_priv;' variable. + auto *OmpPrivParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv"); + // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will + // be replaced by '*omp_parm' during codegen. This required because 'omp_orig' + // uses semantics of argument handles by value, but it should be passed by + // reference. C lang does not support references, so pass all parameters as + // pointers. + // Create 'T omp_orig;' variable. + auto *OmpOrigParm = + buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig"); + if (S != nullptr) { + PushOnScopeChains(OmpPrivParm, S); + PushOnScopeChains(OmpOrigParm, S); + } else { + DRD->addDecl(OmpPrivParm); + DRD->addDecl(OmpOrigParm); + } +} + +void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D, + Expr *Initializer) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + DiscardCleanupsInEvaluationContext(); + PopExpressionEvaluationContext(); - return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars, - MapTypeModifier, MapType, MapLoc); + PopDeclContext(); + PopFunctionScopeInfo(); + + if (Initializer != nullptr) + DRD->setInitializer(Initializer); + else + DRD->setInvalidDecl(); +} + +Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd( + Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) { + for (auto *D : DeclReductions.get()) { + if (IsValid) { + auto *DRD = cast<OMPDeclareReductionDecl>(D); + if (S != nullptr) + PushOnScopeChains(DRD, S, /*AddToContext=*/false); + } else + D->setInvalidDecl(); + } + return DeclReductions; } OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams, @@ -8578,3 +11346,377 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc, OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc); } +OMPClause *Sema::ActOnOpenMPDistScheduleClause( + OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc, + SourceLocation EndLoc) { + if (Kind == OMPC_DIST_SCHEDULE_unknown) { + std::string Values; + Values += "'"; + Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0); + Values += "'"; + Diag(KindLoc, diag::err_omp_unexpected_clause_value) + << Values << getOpenMPClauseName(OMPC_dist_schedule); + return nullptr; + } + Expr *ValExpr = ChunkSize; + Stmt *HelperValStmt = nullptr; + if (ChunkSize) { + if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() && + !ChunkSize->isInstantiationDependent() && + !ChunkSize->containsUnexpandedParameterPack()) { + SourceLocation ChunkSizeLoc = ChunkSize->getLocStart(); + ExprResult Val = + PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize); + if (Val.isInvalid()) + return nullptr; + + ValExpr = Val.get(); + + // OpenMP [2.7.1, Restrictions] + // chunk_size must be a loop invariant integer expression with a positive + // value. + llvm::APSInt Result; + if (ValExpr->isIntegerConstantExpr(Result, Context)) { + if (Result.isSigned() && !Result.isStrictlyPositive()) { + Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause) + << "dist_schedule" << ChunkSize->getSourceRange(); + return nullptr; + } + } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) && + !CurContext->isDependentContext()) { + llvm::MapVector<Expr *, DeclRefExpr *> Captures; + ValExpr = tryBuildCapture(*this, ValExpr, Captures).get(); + HelperValStmt = buildPreInits(Context, Captures); + } + } + } + + return new (Context) + OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, + Kind, ValExpr, HelperValStmt); +} + +OMPClause *Sema::ActOnOpenMPDefaultmapClause( + OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind, + 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) { + std::string Value; + SourceLocation Loc; + Value += "'"; + if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_MODIFIER_tofrom); + Loc = MLoc; + } else { + Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap, + OMPC_DEFAULTMAP_scalar); + Loc = KindLoc; + } + Value += "'"; + Diag(Loc, diag::err_omp_unexpected_clause_value) + << Value << getOpenMPClauseName(OMPC_defaultmap); + return nullptr; + } + + return new (Context) + OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M); +} + +bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) { + DeclContext *CurLexicalContext = getCurLexicalContext(); + if (!CurLexicalContext->isFileContext() && + !CurLexicalContext->isExternCContext() && + !CurLexicalContext->isExternCXXContext()) { + Diag(Loc, diag::err_omp_region_not_file_context); + return false; + } + if (IsInOpenMPDeclareTargetContext) { + Diag(Loc, diag::err_omp_enclosed_declare_target); + return false; + } + + IsInOpenMPDeclareTargetContext = true; + return true; +} + +void Sema::ActOnFinishOpenMPDeclareTargetDirective() { + assert(IsInOpenMPDeclareTargetContext && + "Unexpected ActOnFinishOpenMPDeclareTargetDirective"); + + IsInOpenMPDeclareTargetContext = false; +} + +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); + + if (Lookup.isAmbiguous()) + return; + Lookup.suppressDiagnostics(); + + if (!Lookup.isSingleResult()) { + if (TypoCorrection Corrected = + CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr, + llvm::make_unique<VarOrFuncDeclFilterCCC>(*this), + CTK_ErrorRecovery)) { + diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest) + << Id.getName()); + checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl()); + return; + } + + Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName(); + return; + } + + NamedDecl *ND = Lookup.getAsSingle<NamedDecl>(); + if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) { + if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl()))) + Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName(); + + if (!ND->hasAttr<OMPDeclareTargetDeclAttr>()) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT); + ND->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(ND, A); + checkDeclIsAllowedInOpenMPTarget(nullptr, ND); + } else if (ND->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() != MT) { + Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link) + << Id.getName(); + } + } else + Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName(); +} + +static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR, + Sema &SemaRef, Decl *D) { + if (!D) + return; + Decl *LD = nullptr; + if (isa<TagDecl>(D)) { + LD = cast<TagDecl>(D)->getDefinition(); + } else if (isa<VarDecl>(D)) { + LD = cast<VarDecl>(D)->getDefinition(); + + // If this is an implicit variable that is legal and we do not need to do + // anything. + if (cast<VarDecl>(D)->isImplicit()) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + return; + } + + } else if (isa<FunctionDecl>(D)) { + const FunctionDecl *FD = nullptr; + if (cast<FunctionDecl>(D)->hasBody(FD)) + LD = const_cast<FunctionDecl *>(FD); + + // If the definition is associated with the current declaration in the + // target region (it can be e.g. a lambda) that is legal and we do not need + // to do anything else. + if (LD == D) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + return; + } + } + if (!LD) + LD = D; + if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() && + (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) { + // Outlined declaration is not declared target. + if (LD->isOutOfLine()) { + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } else { + DeclContext *DC = LD->getDeclContext(); + while (DC) { + if (isa<FunctionDecl>(DC) && + cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>()) + break; + DC = DC->getParent(); + } + if (DC) + return; + + // Is not declared in target context. + SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context); + SemaRef.Diag(SL, diag::note_used_here) << SR; + } + // Mark decl as declared target to prevent further diagnostic. + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + } +} + +static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR, + Sema &SemaRef, DSAStackTy *Stack, + ValueDecl *VD) { + if (VD->hasAttr<OMPDeclareTargetDeclAttr>()) + return true; + if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType())) + return false; + return true; +} + +void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) { + if (!D || D->isInvalidDecl()) + return; + SourceRange SR = E ? E->getSourceRange() : D->getSourceRange(); + SourceLocation SL = E ? E->getLocStart() : D->getLocation(); + // 2.10.6: threadprivate variable cannot appear in a declare target directive. + if (VarDecl *VD = dyn_cast<VarDecl>(D)) { + if (DSAStack->isThreadPrivate(VD)) { + Diag(SL, diag::err_omp_threadprivate_in_target); + ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false)); + return; + } + } + if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) { + // Problem if any with var declared with incomplete type will be reported + // as normal, so no need to check it here. + if ((E || !VD->getType()->isIncompleteType()) && + !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) { + // Mark decl as declared target to prevent further diagnostic. + if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + Context, OMPDeclareTargetDeclAttr::MT_To); + VD->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(VD, A); + } + return; + } + } + if (!E) { + // Checking declaration inside declare target region. + if (!D->hasAttr<OMPDeclareTargetDeclAttr>() && + (isa<VarDecl>(D) || isa<FunctionDecl>(D))) { + Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit( + Context, OMPDeclareTargetDeclAttr::MT_To); + D->addAttr(A); + if (ASTMutationListener *ML = Context.getASTMutationListener()) + ML->DeclarationMarkedOpenMPDeclareTarget(D, A); + } + return; + } + checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D); +} + +OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc); + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + MappableVarListInfo MVLI(VarList); + checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc); + if (MVLI.ProcessedVarList.empty()) + return nullptr; + + return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc, + MVLI.ProcessedVarList, MVLI.VarBaseDeclarations, + MVLI.VarComponents); +} + +OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_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); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + QualType Type = D->getType(); + // item should be a pointer or reference to pointer + if (!Type.getNonReferenceType()->isPointerType()) { + Diag(ELoc, diag::err_omp_usedeviceptr_not_a_pointer) + << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(RefExpr->IgnoreParens()); + } + + if (Vars.empty()) + return nullptr; + + return OMPUseDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} + +OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + SmallVector<Expr *, 8> Vars; + for (auto &RefExpr : VarList) { + assert(RefExpr && "NULL expr in OpenMP use_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); + } + ValueDecl *D = Res.first; + if (!D) + continue; + + QualType Type = D->getType(); + // item should be a pointer or array or reference to pointer or array + if (!Type.getNonReferenceType()->isPointerType() && + !Type.getNonReferenceType()->isArrayType()) { + Diag(ELoc, diag::err_omp_argument_type_isdeviceptr) + << 0 << RefExpr->getSourceRange(); + continue; + } + Vars.push_back(RefExpr->IgnoreParens()); + } + + if (Vars.empty()) + return nullptr; + + return OMPIsDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc, + Vars); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp index d6a0ff7dc3d1..b025a397edca 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp @@ -39,8 +39,8 @@ using namespace clang; using namespace sema; static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) { - return std::any_of(FD->param_begin(), FD->param_end(), - std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); + return llvm::any_of(FD->parameters(), + std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); } /// A convenience routine for creating a decayed reference to a function. @@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, // A narrowing conversion is an implicit conversion ... QualType FromType = getToType(0); QualType ToType = getToType(1); + + // A conversion to an enumeration type is narrowing if the conversion to + // the underlying type is narrowing. This only arises for expressions of + // the form 'Enum{init}'. + if (auto *ET = ToType->getAs<EnumType>()) + ToType = ET->getDecl()->getIntegerType(); + switch (Second) { // 'bool' is an integral type; dispatch to the right place to handle it. case ICK_Boolean_Conversion: @@ -433,7 +440,7 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx, /// dump - Print this standard conversion sequence to standard /// error. Useful for debugging overloading issues. -void StandardConversionSequence::dump() const { +LLVM_DUMP_METHOD void StandardConversionSequence::dump() const { raw_ostream &OS = llvm::errs(); bool PrintedSomething = false; if (First != ICK_Identity) { @@ -985,7 +992,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old, } bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, - bool UseUsingDeclRules) { + bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) { // C++ [basic.start.main]p2: This function shall not be overloaded. if (New->isMain()) return false; @@ -1041,7 +1048,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // // However, we don't consider either of these when deciding whether // a member introduced by a shadow declaration is hidden. - if (!UseUsingDeclRules && NewTemplate && + if (!UseMemberUsingDeclRules && NewTemplate && (!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(), OldTemplate->getTemplateParameters(), false, TPL_TemplateMatch) || @@ -1061,7 +1068,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, if (OldMethod && NewMethod && !OldMethod->isStatic() && !NewMethod->isStatic()) { if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) { - if (!UseUsingDeclRules && + if (!UseMemberUsingDeclRules && (OldMethod->getRefQualifier() == RQ_None || NewMethod->getRefQualifier() == RQ_None)) { // C++0x [over.load]p2: @@ -1118,7 +1125,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, return true; } - if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) { + if (getLangOpts().CUDA && ConsiderCudaAttrs) { CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New), OldTarget = IdentifyCUDATarget(Old); if (NewTarget == CFT_InvalidTarget || NewTarget == CFT_Global) @@ -1129,7 +1136,10 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, // 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 . - if ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice)) + // __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 @@ -1147,7 +1157,16 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old, /// \returns true if \arg FD is unavailable and current context is inside /// an available function, false otherwise. bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) { - return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable(); + if (!FD->isUnavailable()) + return false; + + // Walk up the context of the caller. + Decl *C = cast<Decl>(CurContext); + do { + if (C->isUnavailable()) + return false; + } while ((C = cast_or_null<Decl>(C->getDeclContext()))); + return true; } /// \brief Tries a user-defined conversion from From to ToType. @@ -1199,11 +1218,13 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, S.IsDerivedFrom(From->getLocStart(), FromCanon, ToCanon))) { // Turn this into a "standard" conversion sequence, so that it // gets ranked with standard conversion sequences. + DeclAccessPair Found = ICS.UserDefined.FoundConversionFunction; ICS.setStandard(); ICS.Standard.setAsIdentityConversion(); ICS.Standard.setFromType(From->getType()); ICS.Standard.setAllToTypes(ToType); ICS.Standard.CopyConstructor = Constructor; + ICS.Standard.FoundCopyConstructor = Found; if (ToCanon != FromCanon) ICS.Standard.Second = ICK_Derived_To_Base; } @@ -1217,7 +1238,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType, for (OverloadCandidateSet::iterator Cand = Conversions.begin(); Cand != Conversions.end(); ++Cand) if (Cand->Viable) - ICS.Ambiguous.addConversion(Cand->Function); + ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function); break; // Fall through. @@ -1652,6 +1673,20 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType, SCS.Second = ICK_Complex_Real; FromType = ToType.getUnqualifiedType(); } else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) { + // FIXME: disable conversions between long double and __float128 if + // their representation is different until there is back end support + // We of course allow this conversion if long double is really double. + if (&S.Context.getFloatTypeSemantics(FromType) != + &S.Context.getFloatTypeSemantics(ToType)) { + bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty && + ToType == S.Context.LongDoubleTy) || + (FromType == S.Context.LongDoubleTy && + ToType == S.Context.Float128Ty)); + if (Float128AndLongDouble && + (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) != + &llvm::APFloat::IEEEdouble)) + return false; + } // Floating point conversions (C++ 4.8). SCS.Second = ICK_Floating_Conversion; FromType = ToType.getUnqualifiedType(); @@ -1809,8 +1844,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) { (FromType->isSignedIntegerType() || // We can promote any unsigned integer type whose size is // less than int to an int. - (!FromType->isSignedIntegerType() && - Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) { + Context.getTypeSize(FromType) < Context.getTypeSize(ToType))) { return To->getKind() == BuiltinType::Int; } @@ -1955,7 +1989,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) { if (!getLangOpts().CPlusPlus && (FromBuiltin->getKind() == BuiltinType::Float || FromBuiltin->getKind() == BuiltinType::Double) && - (ToBuiltin->getKind() == BuiltinType::LongDouble)) + (ToBuiltin->getKind() == BuiltinType::LongDouble || + ToBuiltin->getKind() == BuiltinType::Float128)) return true; // Half can be promoted to float. @@ -2538,9 +2573,8 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType, // Argument types are too different. Abort. return false; } - if (LangOpts.ObjCAutoRefCount && - !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType, - ToFunctionType)) + if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType, + ToFunctionType)) return false; ConvertedType = ToType; @@ -2919,6 +2953,10 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType, Qualifiers FromQuals = FromType.getQualifiers(); Qualifiers ToQuals = ToType.getQualifiers(); + + // Ignore __unaligned qualifier if this type is void. + if (ToType.getUnqualifiedType()->isVoidType()) + FromQuals.removeUnaligned(); // Objective-C ARC: // Check Objective-C lifetime conversions. @@ -3015,39 +3053,26 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType, UserDefinedConversionSequence &User, OverloadCandidateSet &CandidateSet, bool AllowExplicit) { - DeclContext::lookup_result R = S.LookupConstructors(To); - for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end(); - Con != ConEnd; ++Con) { - NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = nullptr; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); + for (auto *D : S.LookupConstructors(To)) { + auto Info = getConstructorInfo(D); + if (!Info) + continue; - bool Usable = !Constructor->isInvalidDecl() && - S.isInitListConstructor(Constructor) && - (AllowExplicit || !Constructor->isExplicit()); + bool Usable = !Info.Constructor->isInvalidDecl() && + S.isInitListConstructor(Info.Constructor) && + (AllowExplicit || !Info.Constructor->isExplicit()); if (Usable) { // If the first argument is (a reference to) the target type, // suppress conversions. - bool SuppressUserConversions = - isFirstArgumentCompatibleWithType(S.Context, Constructor, ToType); - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ nullptr, - From, CandidateSet, - SuppressUserConversions); + bool SuppressUserConversions = isFirstArgumentCompatibleWithType( + S.Context, Info.Constructor, ToType); + if (Info.ConstructorTmpl) + S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl, + /*ExplicitArgs*/ nullptr, From, + CandidateSet, SuppressUserConversions); else - S.AddOverloadCandidate(Constructor, FoundDecl, - From, CandidateSet, - SuppressUserConversions); + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From, + CandidateSet, SuppressUserConversions); } } @@ -3147,27 +3172,17 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, ListInitializing = true; } - DeclContext::lookup_result R = S.LookupConstructors(ToRecordDecl); - for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end(); - Con != ConEnd; ++Con) { - NamedDecl *D = *Con; - DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess()); - - // Find the constructor (which may be a template). - CXXConstructorDecl *Constructor = nullptr; - FunctionTemplateDecl *ConstructorTmpl - = dyn_cast<FunctionTemplateDecl>(D); - if (ConstructorTmpl) - Constructor - = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl()); - else - Constructor = cast<CXXConstructorDecl>(D); + for (auto *D : S.LookupConstructors(ToRecordDecl)) { + auto Info = getConstructorInfo(D); + if (!Info) + continue; - bool Usable = !Constructor->isInvalidDecl(); + bool Usable = !Info.Constructor->isInvalidDecl(); if (ListInitializing) - Usable = Usable && (AllowExplicit || !Constructor->isExplicit()); + Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit()); else - Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit); + Usable = Usable && + Info.Constructor->isConvertingConstructor(AllowExplicit); if (Usable) { bool SuppressUserConversions = !ConstructorsOnly; if (SuppressUserConversions && ListInitializing) { @@ -3176,18 +3191,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType, // If the first argument is (a reference to) the target type, // suppress conversions. SuppressUserConversions = isFirstArgumentCompatibleWithType( - S.Context, Constructor, ToType); + S.Context, Info.Constructor, ToType); } } - if (ConstructorTmpl) - S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, - /*ExplicitArgs*/ nullptr, - llvm::makeArrayRef(Args, NumArgs), - CandidateSet, SuppressUserConversions); + if (Info.ConstructorTmpl) + S.AddTemplateOverloadCandidate( + Info.ConstructorTmpl, Info.FoundDecl, + /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs), + CandidateSet, SuppressUserConversions); else // Allow one user-defined conversion when user specifies a // From->ToType conversion via an static cast (c-style, etc). - S.AddOverloadCandidate(Constructor, FoundDecl, + S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, llvm::makeArrayRef(Args, NumArgs), CandidateSet, SuppressUserConversions); } @@ -4127,6 +4142,10 @@ Sema::CompareReferenceRelationship(SourceLocation Loc, T2Quals.removeObjCLifetime(); } + // MS compiler ignores __unaligned qualifier for references; do the same. + T1Quals.removeUnaligned(); + T2Quals.removeUnaligned(); + if (T1Quals == T2Quals) return Ref_Compatible; else if (T1Quals.compatiblyIncludes(T2Quals)) @@ -4248,7 +4267,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS, for (OverloadCandidateSet::iterator Cand = CandidateSet.begin(); Cand != CandidateSet.end(); ++Cand) if (Cand->Viable) - ICS.Ambiguous.addConversion(Cand->Function); + ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function); return true; case OR_No_Viable_Function: @@ -4448,13 +4467,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType, // initialization fails. // // Note that we only want to check address spaces and cvr-qualifiers here. - // ObjC GC and lifetime qualifiers aren't important. + // ObjC GC, lifetime and unaligned qualifiers aren't important. Qualifiers T1Quals = T1.getQualifiers(); Qualifiers T2Quals = T2.getQualifiers(); T1Quals.removeObjCGCAttr(); T1Quals.removeObjCLifetime(); T2Quals.removeObjCGCAttr(); T2Quals.removeObjCLifetime(); + // MS compiler ignores __unaligned qualifier for references; do the same. + T1Quals.removeUnaligned(); + T2Quals.removeUnaligned(); if (!T1Quals.compatiblyIncludes(T2Quals)) return ICS; } @@ -5838,12 +5860,12 @@ Sema::AddOverloadCandidate(FunctionDecl *Function, } } -ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, - bool IsInstance) { - SmallVector<ObjCMethodDecl*, 4> Methods; - if (!CollectMultipleMethodsInGlobalPool(Sel, Methods, IsInstance)) +ObjCMethodDecl * +Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance, + SmallVectorImpl<ObjCMethodDecl *> &Methods) { + if (Methods.size() <= 1) return nullptr; - + for (unsigned b = 0, e = Methods.size(); b < e; b++) { bool Match = true; ObjCMethodDecl *Method = Methods[b]; @@ -5952,37 +5974,28 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, SFINAETrap Trap(*this); SmallVector<Expr *, 16> ConvertedArgs; bool InitializationFailed = false; - bool ContainsValueDependentExpr = false; // Convert the arguments. - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) && + for (unsigned I = 0, E = Args.size(); I != E; ++I) { + ExprResult R; + if (I == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) && !cast<CXXMethodDecl>(Function)->isStatic() && !isa<CXXConstructorDecl>(Function)) { CXXMethodDecl *Method = cast<CXXMethodDecl>(Function); - ExprResult R = - PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr, - Method, Method); - if (R.isInvalid()) { - InitializationFailed = true; - break; - } - ContainsValueDependentExpr |= R.get()->isValueDependent(); - ConvertedArgs.push_back(R.get()); + R = PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr, + Method, Method); } else { - ExprResult R = - PerformCopyInitialization(InitializedEntity::InitializeParameter( - Context, - Function->getParamDecl(i)), - SourceLocation(), - Args[i]); - if (R.isInvalid()) { - InitializationFailed = true; - break; - } - ContainsValueDependentExpr |= R.get()->isValueDependent(); - ConvertedArgs.push_back(R.get()); + R = PerformCopyInitialization(InitializedEntity::InitializeParameter( + Context, Function->getParamDecl(I)), + SourceLocation(), Args[I]); } + + if (R.isInvalid()) { + InitializationFailed = true; + break; + } + + ConvertedArgs.push_back(R.get()); } if (InitializationFailed || Trap.hasErrorOccurred()) @@ -6002,7 +6015,6 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, InitializationFailed = true; break; } - ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } @@ -6012,18 +6024,14 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, for (auto *EIA : EnableIfAttrs) { APValue Result; - if (EIA->getCond()->isValueDependent()) { - // Don't even try now, we'll examine it after instantiation. - continue; - } - + // FIXME: This doesn't consider value-dependent cases, because doing so is + // very difficult. Ideally, we should handle them more gracefully. if (!EIA->getCond()->EvaluateWithSubstitution( - Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) { - if (!ContainsValueDependentExpr) - return EIA; - } else if (!Result.isInt() || !Result.getInt().getBoolValue()) { + Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) + return EIA; + + if (!Result.isInt() || !Result.getInt().getBoolValue()) return EIA; - } } return nullptr; } @@ -6814,7 +6822,8 @@ namespace { /// enumeration types. class BuiltinCandidateTypeSet { /// TypeSet - A set of types. - typedef llvm::SmallPtrSet<QualType, 8> TypeSet; + typedef llvm::SetVector<QualType, SmallVector<QualType, 8>, + llvm::SmallPtrSet<QualType, 8>> TypeSet; /// PointerTypes - The set of pointer types that will be used in the /// built-in candidates. @@ -6913,7 +6922,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty, const Qualifiers &VisibleQuals) { // Insert this type. - if (!PointerTypes.insert(Ty).second) + if (!PointerTypes.insert(Ty)) return false; QualType PointeeTy; @@ -6981,7 +6990,7 @@ bool BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( QualType Ty) { // Insert this type. - if (!MemberPointerTypes.insert(Ty).second) + if (!MemberPointerTypes.insert(Ty)) return false; const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>(); @@ -7187,13 +7196,13 @@ class BuiltinOperatorOverloadBuilder { // provided via the getArithmeticType() method below. // The "promoted arithmetic types" are the arithmetic // types are that preserved by promotion (C++ [over.built]p2). - static const unsigned FirstIntegralType = 3; - static const unsigned LastIntegralType = 20; - static const unsigned FirstPromotedIntegralType = 3, - LastPromotedIntegralType = 11; + static const unsigned FirstIntegralType = 4; + static const unsigned LastIntegralType = 21; + static const unsigned FirstPromotedIntegralType = 4, + LastPromotedIntegralType = 12; static const unsigned FirstPromotedArithmeticType = 0, - LastPromotedArithmeticType = 11; - static const unsigned NumArithmeticTypes = 20; + LastPromotedArithmeticType = 12; + static const unsigned NumArithmeticTypes = 21; /// \brief Get the canonical type for a given arithmetic type index. CanQualType getArithmeticType(unsigned index) { @@ -7204,6 +7213,7 @@ class BuiltinOperatorOverloadBuilder { &ASTContext::FloatTy, &ASTContext::DoubleTy, &ASTContext::LongDoubleTy, + &ASTContext::Float128Ty, // Start of integral types. &ASTContext::IntTy, @@ -7246,7 +7256,7 @@ class BuiltinOperatorOverloadBuilder { // (we could precompute SLL x UI for all known platforms, but it's // better not to make any assumptions). // We assume that int128 has a higher rank than long long on all platforms. - enum PromotedType { + enum PromotedType : int8_t { Dep=-1, Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128 }; @@ -8476,16 +8486,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name, } } -// Determines whether Cand1 is "better" in terms of its enable_if attrs than -// Cand2 for overloading. This function assumes that all of the enable_if attrs -// on Cand1 and Cand2 have conditions that evaluate to true. -// -// Cand1's set of enable_if attributes are said to be "better" than Cand2's iff -// Cand1's first N enable_if attributes have precisely the same conditions as -// Cand2's first N enable_if attributes (where N = the number of enable_if -// attributes on Cand2), and Cand1 has more than N enable_if attributes. -static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1, - const FunctionDecl *Cand2) { +namespace { +enum class Comparison { Equal, Better, Worse }; +} + +/// Compares the enable_if attributes of two FunctionDecls, for the purposes of +/// overload resolution. +/// +/// Cand1's set of enable_if attributes are said to be "better" than Cand2's iff +/// Cand1's first N enable_if attributes have precisely the same conditions as +/// Cand2's first N enable_if attributes (where N = the number of enable_if +/// attributes on Cand2), and Cand1 has more than N enable_if attributes. +/// +/// Note that you can have a pair of candidates such that Cand1's enable_if +/// attributes are worse than Cand2's, and Cand2's enable_if attributes are +/// worse than Cand1's. +static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1, + const FunctionDecl *Cand2) { + // Common case: One (or both) decls don't have enable_if attrs. + bool Cand1Attr = Cand1->hasAttr<EnableIfAttr>(); + bool Cand2Attr = Cand2->hasAttr<EnableIfAttr>(); + if (!Cand1Attr || !Cand2Attr) { + if (Cand1Attr == Cand2Attr) + return Comparison::Equal; + return Cand1Attr ? Comparison::Better : Comparison::Worse; + } // FIXME: The next several lines are just // specific_attr_iterator<EnableIfAttr> but going in declaration order, @@ -8493,10 +8518,10 @@ static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1, auto Cand1Attrs = getOrderedEnableIfAttrs(Cand1); auto Cand2Attrs = getOrderedEnableIfAttrs(Cand2); - // Candidate 1 is better if it has strictly more attributes and - // the common sequence is identical. - if (Cand1Attrs.size() <= Cand2Attrs.size()) - return false; + // It's impossible for Cand1 to be better than (or equal to) Cand2 if Cand1 + // has fewer enable_if attributes than Cand2. + if (Cand1Attrs.size() < Cand2Attrs.size()) + return Comparison::Worse; auto Cand1I = Cand1Attrs.begin(); llvm::FoldingSetNodeID Cand1ID, Cand2ID; @@ -8508,10 +8533,10 @@ static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1, Cand1A->getCond()->Profile(Cand1ID, S.getASTContext(), true); Cand2A->getCond()->Profile(Cand2ID, S.getASTContext(), true); if (Cand1ID != Cand2ID) - return false; + return Comparison::Worse; } - return true; + return Cand1I == Cand1Attrs.end() ? Comparison::Equal : Comparison::Better; } /// isBetterOverloadCandidate - Determines whether the first overload @@ -8621,14 +8646,33 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1, return BetterTemplate == Cand1.Function->getPrimaryTemplate(); } + // FIXME: Work around a defect in the C++17 inheriting constructor wording. + // A derived-class constructor beats an (inherited) base class constructor. + bool Cand1IsInherited = + dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl()); + bool Cand2IsInherited = + dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand2.FoundDecl.getDecl()); + if (Cand1IsInherited != Cand2IsInherited) + return Cand2IsInherited; + else if (Cand1IsInherited) { + assert(Cand2IsInherited); + auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext()); + auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext()); + if (Cand1Class->isDerivedFrom(Cand2Class)) + return true; + if (Cand2Class->isDerivedFrom(Cand1Class)) + return false; + // Inherited from sibling base classes: still ambiguous. + } + // Check for enable_if value-based overload resolution. - if (Cand1.Function && Cand2.Function && - (Cand1.Function->hasAttr<EnableIfAttr>() || - Cand2.Function->hasAttr<EnableIfAttr>())) - return hasBetterEnableIfAttrs(S, Cand1.Function, Cand2.Function); + if (Cand1.Function && Cand2.Function) { + Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function); + if (Cmp != Comparison::Equal) + return Cmp == Comparison::Better; + } - if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads && - Cand1.Function && Cand2.Function) { + if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) { FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext); return S.IdentifyCUDAPreference(Caller, Cand1.Function) > S.IdentifyCUDAPreference(Caller, Cand2.Function); @@ -8722,14 +8766,44 @@ OverloadingResult OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, iterator &Best, bool UserDefinedConversion) { + llvm::SmallVector<OverloadCandidate *, 16> Candidates; + 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 + // 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 + // candidate call is WrongSide and the other is SameSide, we ignore + // the WrongSide candidate. + if (S.getLangOpts().CUDA) { + const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext); + bool ContainsSameSideCandidate = + llvm::any_of(Candidates, [&](OverloadCandidate *Cand) { + return Cand->Function && + S.IdentifyCUDAPreference(Caller, Cand->Function) == + Sema::CFP_SameSide; + }); + if (ContainsSameSideCandidate) { + auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) { + return Cand->Function && + S.IdentifyCUDAPreference(Caller, Cand->Function) == + Sema::CFP_WrongSide; + }; + Candidates.erase(std::remove_if(Candidates.begin(), Candidates.end(), + IsWrongSideCandidate), + Candidates.end()); + } + } + // Find the best viable function. Best = end(); - for (iterator Cand = begin(); Cand != end(); ++Cand) { + for (auto *Cand : Candidates) if (Cand->Viable) if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc, UserDefinedConversion)) Best = Cand; - } // If we didn't find any viable functions, abort. if (Best == end()) @@ -8739,7 +8813,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc, // Make sure that this function is better than every other viable // function. If not, we have an ambiguity. - for (iterator Cand = begin(); Cand != end(); ++Cand) { + for (auto *Cand : Candidates) { if (Cand->Viable && Cand != Best && !isBetterOverloadCandidate(S, *Best, *Cand, Loc, @@ -8782,10 +8856,12 @@ enum OverloadCandidateKind { oc_implicit_move_constructor, oc_implicit_copy_assignment, oc_implicit_move_assignment, - oc_implicit_inherited_constructor + oc_inherited_constructor, + oc_inherited_constructor_template }; OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, + NamedDecl *Found, FunctionDecl *Fn, std::string &Description) { bool isTemplate = false; @@ -8797,11 +8873,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, } if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) { - if (!Ctor->isImplicit()) - return isTemplate ? oc_constructor_template : oc_constructor; - - if (Ctor->getInheritedConstructor()) - return oc_implicit_inherited_constructor; + if (!Ctor->isImplicit()) { + if (isa<ConstructorUsingShadowDecl>(Found)) + return isTemplate ? oc_inherited_constructor_template + : oc_inherited_constructor; + else + return isTemplate ? oc_constructor_template : oc_constructor; + } if (Ctor->isDefaultConstructor()) return oc_implicit_default_constructor; @@ -8833,14 +8911,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S, return isTemplate ? oc_function_template : oc_function; } -void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) { - const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn); - if (!Ctor) return; - - Ctor = Ctor->getInheritedConstructor(); - if (!Ctor) return; - - S.Diag(Ctor->getLocation(), diag::note_ovl_candidate_inherited_constructor); +void MaybeEmitInheritedConstructorNote(Sema &S, Decl *FoundDecl) { + // FIXME: It'd be nice to only emit a note once per using-decl per overload + // set. + if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) + S.Diag(FoundDecl->getLocation(), + diag::note_ovl_candidate_inherited_constructor) + << Shadow->getNominatedBaseClass(); } } // end anonymous namespace @@ -8879,8 +8956,8 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD, return false; } - auto I = std::find_if(FD->param_begin(), FD->param_end(), - std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); + auto I = llvm::find_if( + FD->parameters(), std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)); if (I == FD->param_end()) return true; @@ -8914,19 +8991,19 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function, } // Notes the location of an overload candidate. -void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType, - bool TakingAddress) { +void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn, + QualType DestType, bool TakingAddress) { if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn)) return; std::string FnDesc; - OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc); + OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Found, Fn, FnDesc); PartialDiagnostic PD = PDiag(diag::note_ovl_candidate) << (unsigned) K << FnDesc; HandleFunctionTypeMismatch(PD, Fn->getType(), DestType); Diag(Fn->getLocation(), PD); - MaybeEmitInheritedConstructorNote(*this, Fn); + MaybeEmitInheritedConstructorNote(*this, Found); } // Notes the location of all overload candidates designated through @@ -8943,11 +9020,11 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType, I != IEnd; ++I) { if (FunctionTemplateDecl *FunTmpl = dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType, + NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType, TakingAddress); } else if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) { - NoteOverloadCandidate(Fun, DestType, TakingAddress); + NoteOverloadCandidate(*I, Fun, DestType, TakingAddress); } } } @@ -8971,7 +9048,7 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion( if (CandsShown >= 4 && ShowOverloads == Ovl_Best) break; ++CandsShown; - S.NoteOverloadCandidate(*I); + S.NoteOverloadCandidate(I->first, I->second); } if (I != E) S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I); @@ -8996,7 +9073,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, } std::string FnDesc; - OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + OverloadCandidateKind FnKind = + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); Expr *FromExpr = Conv.Bad.FromExpr; QualType FromTy = Conv.Bad.getFromType(); @@ -9013,7 +9091,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << ToTy << Name << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9026,8 +9104,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, else { // TODO: detect and diagnose the full richness of const mismatches. if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>()) - if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>()) - CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType(); + if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>()) { + CFromTy = FromPT->getPointeeType(); + CToTy = ToPT->getPointeeType(); + } } if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() && @@ -9042,7 +9122,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << FromTy << FromQs.getAddressSpace() << ToQs.getAddressSpace() << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9053,7 +9133,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << FromTy << FromQs.getObjCLifetime() << ToQs.getObjCLifetime() << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9064,7 +9144,16 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << FromTy << FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr() << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); + return; + } + + if (FromQs.hasUnaligned() != ToQs.hasUnaligned()) { + S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_unaligned) + << (unsigned) FnKind << FnDesc + << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) + << FromTy << FromQs.hasUnaligned() << I+1; + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9082,7 +9171,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << (CVR - 1) << I+1; } - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9093,7 +9182,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << ToTy << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9104,11 +9193,14 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, if (const PointerType *PTy = TempFromTy->getAs<PointerType>()) TempFromTy = PTy->getPointeeType(); if (TempFromTy->isIncompleteType()) { + // Emit the generic diagnostic and, optionally, add the hints to it. S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete) << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) - << FromTy << ToTy << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + << FromTy << ToTy << (unsigned) isObjectArgument << I+1 + << (unsigned) (Cand->Fix.Kind); + + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9147,7 +9239,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << (unsigned) isObjectArgument << I + 1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } } @@ -9159,7 +9251,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << (BaseToDerivedConversion - 1) << FromTy << ToTy << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } @@ -9172,7 +9264,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, << (unsigned) FnKind << FnDesc << (FromExpr ? FromExpr->getSourceRange() : SourceRange()) << FromTy << ToTy << (unsigned) isObjectArgument << I+1; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } } @@ -9194,7 +9286,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand, FDiag << *HI; S.Diag(Fn->getLocation(), FDiag); - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); } /// Additional arity mismatch diagnosis specific to a function overload @@ -9228,7 +9320,8 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand, } /// General arity mismatch diagnosis over a candidate in a candidate set. -static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { +static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D, + unsigned NumFormalArgs) { assert(isa<FunctionDecl>(D) && "The templated declaration should at least be a function" " when diagnosing bad template argument deduction due to too many" @@ -9258,7 +9351,8 @@ static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { } std::string Description; - OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description); + OverloadCandidateKind FnKind = + ClassifyOverloadCandidate(S, Found, Fn, Description); if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName()) S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one) @@ -9268,28 +9362,25 @@ static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity) << (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr) << mode << modeCount << NumFormalArgs; - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Found); } /// Arity mismatch diagnosis specific to a function overload candidate. static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand, unsigned NumFormalArgs) { if (!CheckArityMismatch(S, Cand, NumFormalArgs)) - DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs); + DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs); } static TemplateDecl *getDescribedTemplate(Decl *Templated) { - if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated)) - return FD->getDescribedFunctionTemplate(); - else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated)) - return RD->getDescribedClassTemplate(); - + if (TemplateDecl *TD = Templated->getDescribedTemplate()) + return TD; llvm_unreachable("Unsupported: Getting the described template declaration" " for bad deduction diagnosis"); } /// Diagnose a failed template-argument deduction. -static void DiagnoseBadDeduction(Sema &S, Decl *Templated, +static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated, DeductionFailureInfo &DeductionFailure, unsigned NumArgs, bool TakingCandidateAddress) { @@ -9307,7 +9398,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, S.Diag(Templated->getLocation(), diag::note_ovl_candidate_incomplete_deduction) << ParamD->getDeclName(); - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; } @@ -9332,7 +9423,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified) << ParamD->getDeclName() << Arg << NonCanonParam; - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; } @@ -9351,7 +9442,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, diag::note_ovl_candidate_inconsistent_deduction) << which << ParamD->getDeclName() << *DeductionFailure.getFirstArg() << *DeductionFailure.getSecondArg(); - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; } @@ -9374,18 +9465,18 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, diag::note_ovl_candidate_explicit_arg_mismatch_unnamed) << (index + 1); } - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; case Sema::TDK_TooManyArguments: case Sema::TDK_TooFewArguments: - DiagnoseArityMismatch(S, Templated, NumArgs); + DiagnoseArityMismatch(S, Found, Templated, NumArgs); return; case Sema::TDK_InstantiationDepth: S.Diag(Templated->getLocation(), diag::note_ovl_candidate_instantiation_depth); - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; case Sema::TDK_SubstitutionFailure: { @@ -9423,7 +9514,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, S.Diag(Templated->getLocation(), diag::note_ovl_candidate_substitution_failure) << TemplateArgString << SFINAEArgString << R; - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; } @@ -9495,7 +9586,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated, // note_ovl_candidate_bad_deduction, which is uselessly vague. case Sema::TDK_MiscellaneousDeductionFailure: S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction); - MaybeEmitInheritedConstructorNote(S, Templated); + MaybeEmitInheritedConstructorNote(S, Found); return; } } @@ -9509,7 +9600,7 @@ static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand, if (CheckArityMismatch(S, Cand, NumArgs)) return; } - DiagnoseBadDeduction(S, Cand->Function, // pattern + DiagnoseBadDeduction(S, Cand->FoundDecl, Cand->Function, // pattern Cand->DeductionFailure, NumArgs, TakingCandidateAddress); } @@ -9522,7 +9613,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) { CalleeTarget = S.IdentifyCUDATarget(Callee); std::string FnDesc; - OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc); + OverloadCandidateKind FnKind = + ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc); S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target) << (unsigned)FnKind << CalleeTarget << CallerTarget; @@ -9599,18 +9691,19 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, if (Cand->Viable && (Fn->isDeleted() || S.isFunctionConsideredUnavailable(Fn))) { std::string FnDesc; - OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc); + OverloadCandidateKind FnKind = + ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc); S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted) << FnKind << FnDesc << (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0); - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } // We don't really have anything else to say about viable candidates. if (Cand->Viable) { - S.NoteOverloadCandidate(Fn); + S.NoteOverloadCandidate(Cand->FoundDecl, Fn); return; } @@ -9620,19 +9713,20 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, return DiagnoseArityMismatch(S, Cand, NumArgs); case ovl_fail_bad_deduction: - return DiagnoseBadDeduction(S, Cand, NumArgs, TakingCandidateAddress); + return DiagnoseBadDeduction(S, Cand, NumArgs, + TakingCandidateAddress); case ovl_fail_illegal_constructor: { S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor) << (Fn->getPrimaryTemplate() ? 1 : 0); - MaybeEmitInheritedConstructorNote(S, Fn); + MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl); return; } case ovl_fail_trivial_conversion: case ovl_fail_bad_final_conversion: case ovl_fail_final_conversion_not_exact: - return S.NoteOverloadCandidate(Fn); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn); case ovl_fail_bad_conversion: { unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0); @@ -9643,7 +9737,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand, // FIXME: this currently happens when we're called from SemaInit // when user-conversion overload fails. Figure out how to handle // those conditions and diagnose them well. - return S.NoteOverloadCandidate(Fn); + return S.NoteOverloadCandidate(Cand->FoundDecl, Fn); } case ovl_fail_bad_target: @@ -9691,7 +9785,6 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) { S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand) << FnType; - MaybeEmitInheritedConstructorNote(S, Cand->Surrogate); } static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc, @@ -9721,8 +9814,8 @@ static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc, if (ICS.isBad()) break; // all meaningless after first invalid if (!ICS.isAmbiguous()) continue; - ICS.DiagnoseAmbiguousConversion(S, OpLoc, - S.PDiag(diag::note_ambiguous_type_conversion)); + ICS.DiagnoseAmbiguousConversion( + S, OpLoc, S.PDiag(diag::note_ambiguous_type_conversion)); } } @@ -10089,7 +10182,7 @@ struct CompareTemplateSpecCandidatesForDisplay { /// deductions. void TemplateSpecCandidate::NoteDeductionFailure(Sema &S, bool ForTakingAddress) { - DiagnoseBadDeduction(S, Specialization, // pattern + DiagnoseBadDeduction(S, FoundDecl, Specialization, // pattern DeductionFailure, /*NumArgs=*/0, ForTakingAddress); } @@ -10252,21 +10345,32 @@ public: } } - if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads && - Matches.size() > 1) + if (S.getLangOpts().CUDA && Matches.size() > 1) EliminateSuboptimalCudaMatches(); } bool hasComplained() const { return HasComplained; } private: - // Is A considered a better overload candidate for the desired type than B? + bool candidateHasExactlyCorrectType(const FunctionDecl *FD) { + QualType Discard; + return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) || + S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard); + } + + /// \return true if A is considered a better overload candidate for the + /// desired type than B. bool isBetterCandidate(const FunctionDecl *A, const FunctionDecl *B) { - return hasBetterEnableIfAttrs(S, A, B); + // If A doesn't have exactly the correct type, we don't want to classify it + // as "better" than anything else. This way, the user is required to + // disambiguate for us if there are multiple candidates and no exact match. + return candidateHasExactlyCorrectType(A) && + (!candidateHasExactlyCorrectType(B) || + compareEnableIfAttrs(S, A, B) == Comparison::Better); } - // Returns true if we've eliminated any (read: all but one) candidates, false - // otherwise. + /// \return true if we were able to eliminate all but one overload candidate, + /// false otherwise. bool eliminiateSuboptimalOverloadCandidates() { // Same algorithm as overload resolution -- one pass to pick the "best", // another pass to be sure that nothing is better than the best. @@ -10331,7 +10435,7 @@ private: Info, /*InOverloadResolution=*/true)) { // Make a note of the failed deduction for diagnostics. FailedCandidates.addCandidate() - .set(FunctionTemplate->getTemplatedDecl(), + .set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(), MakeDeductionFailureInfo(Context, Result, Info)); return false; } @@ -10339,7 +10443,6 @@ private: // Template argument deduction ensures that we have an exact match or // compatible pointer-to-function arguments that would be adjusted by ICS. // This function template specicalization works. - Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl()); assert(S.isSameOrCompatibleFunctionType( Context.getCanonicalType(Specialization->getType()), Context.getCanonicalType(TargetFunctionType))); @@ -10380,12 +10483,9 @@ private: if (!S.checkAddressOfFunctionIsAvailable(FunDecl)) return false; - QualType ResultTy; - if (Context.hasSameUnqualifiedType(TargetFunctionType, - FunDecl->getType()) || - S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType, - ResultTy) || - (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())) { + // If we're in C, we need to support types that aren't exactly identical. + if (!S.getLangOpts().CPlusPlus || + candidateHasExactlyCorrectType(FunDecl)) { Matches.push_back(std::make_pair( CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl()))); FoundNonTemplateFunction = true; @@ -10451,9 +10551,10 @@ private: UnresolvedSetIterator Result = S.getMostSpecialized( MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates, SourceExpr->getLocStart(), S.PDiag(), - S.PDiag(diag::err_addr_ovl_ambiguous) << Matches[0] - .second->getDeclName(), - S.PDiag(diag::note_ovl_candidate) << (unsigned)oc_function_template, + S.PDiag(diag::err_addr_ovl_ambiguous) + << Matches[0].second->getDeclName(), + S.PDiag(diag::note_ovl_candidate) + << (unsigned)oc_function_template, Complain, TargetFunctionType); if (Result != MatchesCopy.end()) { @@ -10501,7 +10602,7 @@ public: if (FunctionDecl *Fun = dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl())) if (!functionHasPassObjectSizeParams(Fun)) - S.NoteOverloadCandidate(Fun, TargetFunctionType, + S.NoteOverloadCandidate(*I, Fun, TargetFunctionType, /*TakingAddress=*/true); FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart()); } @@ -10614,6 +10715,72 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr, } /// \brief Given an expression that refers to an overloaded function, try to +/// resolve that function to a single function that can have its address taken. +/// This will modify `Pair` iff it returns non-null. +/// +/// This routine can only realistically succeed if all but one candidates in the +/// overload set for SrcExpr cannot have their addresses taken. +FunctionDecl * +Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E, + DeclAccessPair &Pair) { + OverloadExpr::FindResult R = OverloadExpr::find(E); + OverloadExpr *Ovl = R.Expression; + FunctionDecl *Result = nullptr; + DeclAccessPair DAP; + // Don't use the AddressOfResolver because we're specifically looking for + // cases where we have one overload candidate that lacks + // enable_if/pass_object_size/... + for (auto I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) { + auto *FD = dyn_cast<FunctionDecl>(I->getUnderlyingDecl()); + if (!FD) + return nullptr; + + if (!checkAddressOfFunctionIsAvailable(FD)) + continue; + + // We have more than one result; quit. + if (Result) + return nullptr; + DAP = I.getPair(); + Result = FD; + } + + if (Result) + Pair = DAP; + return Result; +} + +/// \brief Given an overloaded function, tries to turn it into a non-overloaded +/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This +/// will perform access checks, diagnose the use of the resultant decl, and, if +/// necessary, perform a function-to-pointer decay. +/// +/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails. +/// Otherwise, returns true. This may emit diagnostics and return true. +bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate( + ExprResult &SrcExpr) { + Expr *E = SrcExpr.get(); + assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload"); + + DeclAccessPair DAP; + FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP); + if (!Found) + return false; + + // Emitting multiple diagnostics for a function that is both inaccessible and + // unavailable is consistent with our behavior elsewhere. So, always check + // for both. + DiagnoseUseOfDecl(Found, E->getExprLoc()); + CheckAddressOfMemberAccess(E, DAP); + Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found); + if (Fixed->getType()->isFunctionType()) + SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false); + else + SrcExpr = Fixed; + return true; +} + +/// \brief Given an expression that refers to an overloaded function, try to /// resolve that overloaded function expression down to a single function. /// /// This routine can only resolve template-ids that refer to a single function @@ -10671,7 +10838,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl, // Make a note of the failed deduction for diagnostics. // TODO: Actually use the failed-deduction info? FailedCandidates.addCandidate() - .set(FunctionTemplate->getTemplatedDecl(), + .set(I.getPair(), FunctionTemplate->getTemplatedDecl(), MakeDeductionFailureInfo(Context, Result, Info)); continue; } @@ -12236,6 +12403,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE, << MD->getDeclName(); } } + + if (CXXDestructorDecl *DD = + dyn_cast<CXXDestructorDecl>(TheCall->getMethodDecl())) { + // a->A::f() doesn't go through the vtable, except in AppleKext mode. + bool CallCanBeVirtual = !MemExpr->hasQualifier() || getLangOpts().AppleKext; + CheckVirtualDtorCall(DD, MemExpr->getLocStart(), /*IsDelete=*/false, + CallCanBeVirtual, /*WarnOnNonAbstractTypes=*/true, + MemExpr->getMemberLoc()); + } + return MaybeBindToTemporary(TheCall); } @@ -12843,6 +13020,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found, = Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext())); QualType MemPtrType = Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr()); + // Under the MS ABI, lock down the inheritance model now. + if (Context.getTargetInfo().getCXXABI().isMicrosoft()) + (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType); return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType, VK_RValue, OK_Ordinary, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp index e5d51f173caa..c93d800f96d1 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp @@ -578,7 +578,7 @@ bool ObjCPropertyOpBuilder::isWeakProperty() const { if (RefExpr->isExplicitProperty()) { const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty(); if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak) - return !Prop->hasAttr<IBOutletAttr>(); + return true; T = Prop->getType(); } else if (Getter) { @@ -658,7 +658,8 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) { SmallString<100> PropertyName = thisPropertyName; PropertyName[0] = front; IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName); - if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember)) + if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration( + AltMember, prop->getQueryKind())) if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) { S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use) << prop << prop1 << setter->getSelector(); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp index e1b1a47e182b..8e8104e581b2 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp @@ -37,6 +37,7 @@ #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" + using namespace clang; using namespace sema; @@ -249,10 +250,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { // is written in a macro body, only warn if it has the warn_unused_result // attribute. if (const Decl *FD = CE->getCalleeDecl()) { - const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD); - if (Func ? Func->hasUnusedResultAttr() - : FD->hasAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_result) << R1 << R2; + if (const Attr *A = isa<FunctionDecl>(FD) + ? cast<FunctionDecl>(FD)->getUnusedResultAttr() + : FD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } if (ShouldSuppress) @@ -276,8 +277,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) { } const ObjCMethodDecl *MD = ME->getMethodDecl(); if (MD) { - if (MD->hasAttr<WarnUnusedResultAttr>()) { - Diag(Loc, diag::warn_unused_result) << R1 << R2; + if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) { + Diag(Loc, diag::warn_unused_result) << A << R1 << R2; return; } } @@ -488,36 +489,62 @@ StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc, return LS; } +namespace { +class CommaVisitor : public EvaluatedExprVisitor<CommaVisitor> { + typedef EvaluatedExprVisitor<CommaVisitor> Inherited; + Sema &SemaRef; +public: + CommaVisitor(Sema &SemaRef) : Inherited(SemaRef.Context), SemaRef(SemaRef) {} + void VisitBinaryOperator(BinaryOperator *E) { + if (E->getOpcode() == BO_Comma) + SemaRef.DiagnoseCommaOperator(E->getLHS(), E->getExprLoc()); + EvaluatedExprVisitor<CommaVisitor>::VisitBinaryOperator(E); + } +}; +} + StmtResult -Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar, +Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt, + ConditionResult Cond, Stmt *thenStmt, SourceLocation ElseLoc, Stmt *elseStmt) { - ExprResult CondResult(CondVal.release()); - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, IfLoc, true); - CondResult = ActOnFinishFullExpr(CondResult.get(), IfLoc); - } - Expr *ConditionExpr = CondResult.getAs<Expr>(); - if (ConditionExpr) { - DiagnoseUnusedExprResult(thenStmt); + if (Cond.isInvalid()) + Cond = ConditionResult( + *this, nullptr, + MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(), + Context.BoolTy, VK_RValue), + IfLoc), + false); + + Expr *CondExpr = Cond.get().second; + if (!Diags.isIgnored(diag::warn_comma_operator, + CondExpr->getExprLoc())) + CommaVisitor(*this).Visit(CondExpr); + + if (!elseStmt) + DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt, + diag::warn_empty_if_body); + + return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc, + elseStmt); +} + +StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, + Stmt *InitStmt, ConditionResult Cond, + Stmt *thenStmt, SourceLocation ElseLoc, + Stmt *elseStmt) { + if (Cond.isInvalid()) + return StmtError(); - if (!elseStmt) { - DiagnoseEmptyStmtBody(ConditionExpr->getLocEnd(), thenStmt, - diag::warn_empty_if_body); - } + if (IsConstexpr) + getCurFunction()->setHasBranchProtectedScope(); - DiagnoseUnusedExprResult(elseStmt); - } else { - // Create a dummy Expr for the condition for error recovery - ConditionExpr = new (Context) OpaqueValueExpr(SourceLocation(), - Context.BoolTy, VK_RValue); - } + DiagnoseUnusedExprResult(thenStmt); + DiagnoseUnusedExprResult(elseStmt); - return new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr, - thenStmt, ElseLoc, elseStmt); + return new (Context) + IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first, + Cond.get().second, thenStmt, ElseLoc, elseStmt); } namespace { @@ -579,24 +606,7 @@ static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) { return expr->getType(); } -StmtResult -Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, - Decl *CondVar) { - ExprResult CondResult; - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false); - if (CondResult.isInvalid()) - return StmtError(); - - Cond = CondResult.get(); - } - - if (!Cond) - return StmtError(); - +ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) { class SwitchConvertDiagnoser : public ICEConvertDiagnoser { Expr *Cond; @@ -644,24 +654,24 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond, } } SwitchDiagnoser(Cond); - CondResult = + ExprResult CondResult = PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser); - if (CondResult.isInvalid()) return StmtError(); - Cond = CondResult.get(); + if (CondResult.isInvalid()) + return ExprError(); // C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr. - CondResult = UsualUnaryConversions(Cond); - if (CondResult.isInvalid()) return StmtError(); - Cond = CondResult.get(); + return UsualUnaryConversions(CondResult.get()); +} - CondResult = ActOnFinishFullExpr(Cond, SwitchLoc); - if (CondResult.isInvalid()) +StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, + Stmt *InitStmt, ConditionResult Cond) { + if (Cond.isInvalid()) return StmtError(); - Cond = CondResult.get(); getCurFunction()->setHasBranchIntoScope(); - SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond); + SwitchStmt *SS = new (Context) + SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second); getCurFunction()->SwitchStack.push_back(SS); return SS; } @@ -980,7 +990,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch, << SourceRange(CR->getLHS()->getLocStart(), Hi->getLocEnd()); CaseRanges.erase(CaseRanges.begin()+i); - --i, --e; + --i; + --e; continue; } @@ -1221,23 +1232,17 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType, } } -StmtResult -Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, - Decl *CondVar, Stmt *Body) { - ExprResult CondResult(Cond.release()); - - VarDecl *ConditionVar = nullptr; - if (CondVar) { - ConditionVar = cast<VarDecl>(CondVar); - CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true); - CondResult = ActOnFinishFullExpr(CondResult.get(), WhileLoc); - if (CondResult.isInvalid()) - return StmtError(); - } - Expr *ConditionExpr = CondResult.get(); - if (!ConditionExpr) +StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond, + Stmt *Body) { + if (Cond.isInvalid()) return StmtError(); - CheckBreakContinueBinding(ConditionExpr); + + auto CondVal = Cond.get(); + CheckBreakContinueBinding(CondVal.second); + + if (CondVal.second && + !Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc())) + CommaVisitor(*this).Visit(CondVal.second); DiagnoseUnusedExprResult(Body); @@ -1245,7 +1250,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond, getCurCompoundScope().setHasEmptyLoopBodies(); return new (Context) - WhileStmt(Context, ConditionVar, ConditionExpr, Body, WhileLoc); + WhileStmt(Context, CondVal.first, CondVal.second, Body, WhileLoc); } StmtResult @@ -1255,7 +1260,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body, assert(Cond && "ActOnDoStmt(): missing expression"); CheckBreakContinueBinding(Cond); - ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc); + ExprResult CondResult = CheckBooleanCondition(DoLoc, Cond); if (CondResult.isInvalid()) return StmtError(); Cond = CondResult.get(); @@ -1416,6 +1421,18 @@ namespace { FoundDecl = true; } + void VisitPseudoObjectExpr(PseudoObjectExpr *POE) { + // Only need to visit the semantics for POE. + // SyntaticForm doesn't really use the Decal. + for (auto *S : POE->semantics()) { + if (auto *OVE = dyn_cast<OpaqueValueExpr>(S)) + // Look past the OVE into the expression it binds. + Visit(OVE->getSourceExpr()); + else + Visit(S); + } + } + bool FoundDeclInUse() { return FoundDecl; } }; // end class DeclMatcher @@ -1481,6 +1498,10 @@ namespace { // variables Increment and DRE. bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment, DeclRefExpr *&DRE) { + if (auto Cleanups = dyn_cast<ExprWithCleanups>(Statement)) + if (!Cleanups->cleanupsHaveSideEffects()) + Statement = Cleanups->getSubExpr(); + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) { switch (UO->getOpcode()) { default: return false; @@ -1603,11 +1624,13 @@ void Sema::CheckBreakContinueBinding(Expr *E) { } } -StmtResult -Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - Stmt *First, FullExprArg second, Decl *secondVar, - FullExprArg third, - SourceLocation RParenLoc, Stmt *Body) { +StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, + Stmt *First, ConditionResult Second, + FullExprArg third, SourceLocation RParenLoc, + Stmt *Body) { + if (Second.isInvalid()) + return StmtError(); + if (!getLangOpts().CPlusPlus) { if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) { // C99 6.8.5p3: The declaration part of a 'for' statement shall only @@ -1625,21 +1648,18 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, } } - CheckBreakContinueBinding(second.get()); + CheckBreakContinueBinding(Second.get().second); CheckBreakContinueBinding(third.get()); - CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body); + if (!Second.get().first) + CheckForLoopConditionalStatement(*this, Second.get().second, third.get(), + Body); CheckForRedundantIteration(*this, third.get(), Body); - ExprResult SecondResult(second.release()); - VarDecl *ConditionVar = nullptr; - if (secondVar) { - ConditionVar = cast<VarDecl>(secondVar); - SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true); - SecondResult = ActOnFinishFullExpr(SecondResult.get(), ForLoc); - if (SecondResult.isInvalid()) - return StmtError(); - } + if (Second.get().second && + !Diags.isIgnored(diag::warn_comma_operator, + Second.get().second->getExprLoc())) + CommaVisitor(*this).Visit(Second.get().second); Expr *Third = third.release().getAs<Expr>(); @@ -1650,8 +1670,9 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, if (isa<NullStmt>(Body)) getCurCompoundScope().setHasEmptyLoopBodies(); - return new (Context) ForStmt(Context, First, SecondResult.get(), ConditionVar, - Third, Body, ForLoc, LParenLoc, RParenLoc); + return new (Context) + ForStmt(Context, First, Second.get().second, Second.get().first, Third, + Body, ForLoc, LParenLoc, RParenLoc); } /// In an Objective C collection iteration statement: @@ -1992,8 +2013,9 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc, } return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(), - /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr, - /*Inc=*/nullptr, DS, RParenLoc, Kind); + /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr, + /*Cond=*/nullptr, /*Inc=*/nullptr, + DS, RParenLoc, Kind); } /// \brief Create the initialization, compare, and increment steps for @@ -2143,8 +2165,8 @@ struct InvalidateOnErrorScope { /// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement. StmtResult Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, - SourceLocation ColonLoc, - Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond, + SourceLocation ColonLoc, Stmt *RangeDecl, + Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVarDecl, SourceLocation RParenLoc, BuildForRangeKind Kind) { // FIXME: This should not be used during template instantiation. We should @@ -2170,7 +2192,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, InvalidateOnErrorScope Invalidate(*this, LoopVar, LoopVar->getType()->isUndeducedType()); - StmtResult BeginEndDecl = BeginEnd; + StmtResult BeginDeclStmt = Begin; + StmtResult EndDeclStmt = End; ExprResult NotEqExpr = Cond, IncrExpr = Inc; if (RangeVarType->isDependentType()) { @@ -2181,7 +2204,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // them in properly when we instantiate the loop. if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check) LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy)); - } else if (!BeginEndDecl.get()) { + } else if (!BeginDeclStmt.get()) { SourceLocation RangeLoc = RangeVar->getLocation(); const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType(); @@ -2306,20 +2329,21 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, "invalid range expression in for loop"); // C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same. + // C++1z removes this restriction. QualType BeginType = BeginVar->getType(), EndType = EndVar->getType(); if (!Context.hasSameType(BeginType, EndType)) { - Diag(RangeLoc, diag::err_for_range_begin_end_types_differ) - << BeginType << EndType; + Diag(RangeLoc, getLangOpts().CPlusPlus1z + ? diag::warn_for_range_begin_end_types_differ + : diag::ext_for_range_begin_end_types_differ) + << BeginType << EndType; NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin); NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end); } - Decl *BeginEndDecls[] = { BeginVar, EndVar }; - // Claim the type doesn't contain auto: we've already done the checking. - DeclGroupPtrTy BeginEndGroup = - BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2), - /*TypeMayContainAuto=*/ false); - BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc); + BeginDeclStmt = + ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc); + EndDeclStmt = + ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc); const QualType BeginRefNonRefType = BeginType.getNonReferenceType(); ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType, @@ -2335,8 +2359,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, // Build and check __begin != __end expression. NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal, BeginRef.get(), EndRef.get()); - NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get()); - NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); + if (!NotEqExpr.isInvalid()) + NotEqExpr = CheckBooleanCondition(ColonLoc, NotEqExpr.get()); + if (!NotEqExpr.isInvalid()) + NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get()); if (NotEqExpr.isInvalid()) { Diag(RangeLoc, diag::note_for_range_invalid_iterator) << RangeLoc << 0 << BeginRangeRef.get()->getType(); @@ -2394,7 +2420,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, return StmtResult(); return new (Context) CXXForRangeStmt( - RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(), + RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()), + cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(), IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc, ColonLoc, RParenLoc); } @@ -2426,6 +2453,10 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef, QualType VariableType = VD->getType(); + if (auto Cleanups = dyn_cast<ExprWithCleanups>(InitExpr)) + if (!Cleanups->cleanupsHaveSideEffects()) + InitExpr = Cleanups->getSubExpr(); + const MaterializeTemporaryExpr *MTE = dyn_cast<MaterializeTemporaryExpr>(InitExpr); @@ -2663,16 +2694,16 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) { /// \param E The expression being returned from the function or block, or /// being thrown. /// -/// \param AllowFunctionParameter Whether we allow function parameters to -/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but -/// we re-use this logic to determine whether we should try to move as part of -/// a return or throw (which does allow function parameters). +/// \param AllowParamOrMoveConstructible Whether we allow function parameters or +/// id-expressions that could be moved out of the function to be considered NRVO +/// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to +/// determine whether we should try to move as part of a return or throw (which +/// does allow function parameters). /// /// \returns The NRVO candidate variable, if the return statement may use the /// NRVO, or NULL if there is no such candidate. -VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, - Expr *E, - bool AllowFunctionParameter) { +VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E, + bool AllowParamOrMoveConstructible) { if (!getLangOpts().CPlusPlus) return nullptr; @@ -2685,13 +2716,13 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, if (!VD) return nullptr; - if (isCopyElisionCandidate(ReturnType, VD, AllowFunctionParameter)) + if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible)) return VD; return nullptr; } bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, - bool AllowFunctionParameter) { + bool AllowParamOrMoveConstructible) { QualType VDType = VD->getType(); // - in a return statement in a function with ... // ... a class return type ... @@ -2699,20 +2730,24 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, if (!ReturnType->isRecordType()) return false; // ... the same cv-unqualified type as the function return type ... - if (!VDType->isDependentType() && + // When considering moving this expression out, allow dissimilar types. + if (!AllowParamOrMoveConstructible && !VDType->isDependentType() && !Context.hasSameUnqualifiedType(ReturnType, VDType)) return false; } // ...object (other than a function or catch-clause parameter)... if (VD->getKind() != Decl::Var && - !(AllowFunctionParameter && VD->getKind() == Decl::ParmVar)) + !(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar)) return false; if (VD->isExceptionVariable()) return false; // ...automatic... if (!VD->hasLocalStorage()) return false; + if (AllowParamOrMoveConstructible) + return true; + // ...non-volatile... if (VD->getType().isVolatileQualified()) return false; @@ -2731,7 +2766,7 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD, /// \brief Perform the initialization of a potentially-movable value, which /// is the result of return value. /// -/// This routine implements C++0x [class.copy]p33, which attempts to treat +/// This routine implements C++14 [class.copy]p32, which attempts to treat /// returned lvalues as rvalues in certain cases (to prefer move construction), /// then falls back to treating them as lvalues if that failed. ExprResult @@ -2740,52 +2775,59 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity, QualType ResultType, Expr *Value, bool AllowNRVO) { - // C++0x [class.copy]p33: - // When the criteria for elision of a copy operation are met or would - // be met save for the fact that the source object is a function - // parameter, and the object to be copied is designated by an lvalue, - // overload resolution to select the constructor for the copy is first - // performed as if the object were designated by an rvalue. + // C++14 [class.copy]p32: + // When the criteria for elision of a copy/move operation are met, but not for + // an exception-declaration, and the object to be copied is designated by an + // lvalue, or when the expression in a return statement is a (possibly + // parenthesized) id-expression that names an object with automatic storage + // duration declared in the body or parameter-declaration-clause of the + // innermost enclosing function or lambda-expression, overload resolution to + // select the constructor for the copy is first performed as if the object + // were designated by an rvalue. ExprResult Res = ExprError(); - if (AllowNRVO && - (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) { - ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, - Value->getType(), CK_NoOp, Value, VK_XValue); + + if (AllowNRVO && !NRVOCandidate) + NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true); + + if (AllowNRVO && NRVOCandidate) { + ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(), + CK_NoOp, Value, VK_XValue); Expr *InitExpr = &AsRvalue; - InitializationKind Kind - = InitializationKind::CreateCopy(Value->getLocStart(), - Value->getLocStart()); - InitializationSequence Seq(*this, Entity, Kind, InitExpr); - // [...] If overload resolution fails, or if the type of the first - // parameter of the selected constructor is not an rvalue reference - // to the object's type (possibly cv-qualified), overload resolution - // is performed again, considering the object as an lvalue. + InitializationKind Kind = InitializationKind::CreateCopy( + Value->getLocStart(), Value->getLocStart()); + + InitializationSequence Seq(*this, Entity, Kind, InitExpr); if (Seq) { - for (InitializationSequence::step_iterator Step = Seq.step_begin(), - StepEnd = Seq.step_end(); - Step != StepEnd; ++Step) { - if (Step->Kind != InitializationSequence::SK_ConstructorInitialization) + for (const InitializationSequence::Step &Step : Seq.steps()) { + if (!(Step.Kind == + InitializationSequence::SK_ConstructorInitialization || + (Step.Kind == InitializationSequence::SK_UserConversion && + isa<CXXConstructorDecl>(Step.Function.Function)))) continue; - CXXConstructorDecl *Constructor - = cast<CXXConstructorDecl>(Step->Function.Function); + CXXConstructorDecl *Constructor = + cast<CXXConstructorDecl>(Step.Function.Function); const RValueReferenceType *RRefType = Constructor->getParamDecl(0)->getType() ->getAs<RValueReferenceType>(); - // If we don't meet the criteria, break out now. + // [...] If the first overload resolution fails or was not performed, or + // if the type of the first parameter of the selected constructor is not + // an rvalue reference to the object’s type (possibly cv-qualified), + // overload resolution is performed again, considering the object as an + // lvalue. if (!RRefType || !Context.hasSameUnqualifiedType(RRefType->getPointeeType(), - Context.getTypeDeclType(Constructor->getParent()))) + NRVOCandidate->getType())) break; // Promote "AsRvalue" to the heap, since we now need this // expression node to persist. - Value = ImplicitCastExpr::Create(Context, Value->getType(), - CK_NoOp, Value, nullptr, VK_XValue); + Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp, + Value, nullptr, VK_XValue); // Complete type-checking the initialization of the return type // using the constructor we found. @@ -2821,8 +2863,21 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction()); QualType FnRetType = CurCap->ReturnType; LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap); + bool HasDeducedReturnType = + CurLambda && hasDeducedReturnType(CurLambda->CallOperator); + + if (ExprEvalContexts.back().Context == DiscardedStatement && + (HasDeducedReturnType || CurCap->HasImplicitReturnType)) { + if (RetValExp) { + ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc); + if (ER.isInvalid()) + return StmtError(); + RetValExp = ER.get(); + } + return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr); + } - if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) { + if (HasDeducedReturnType) { // In C++1y, the return type may involve 'auto'. // FIXME: Blocks might have a return type of 'auto' explicitly specified. FunctionDecl *FD = CurLambda->CallOperator; @@ -3066,22 +3121,28 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD, // has multiple return statements, the return type is deduced for each return // statement. [...] if the type deduced is not the same in each deduction, // the program is ill-formed. - if (AT->isDeduced() && !FD->isInvalidDecl()) { + QualType DeducedT = AT->getDeducedType(); + if (!DeducedT.isNull() && !FD->isInvalidDecl()) { AutoType *NewAT = Deduced->getContainedAutoType(); + // It is possible that NewAT->getDeducedType() is null. When that happens, + // we should not crash, instead we ignore this deduction. + if (NewAT->getDeducedType().isNull()) + return false; + CanQualType OldDeducedType = Context.getCanonicalFunctionResultType( - AT->getDeducedType()); + DeducedT); CanQualType NewDeducedType = Context.getCanonicalFunctionResultType( NewAT->getDeducedType()); if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) { const LambdaScopeInfo *LambdaSI = getCurLambda(); if (LambdaSI && LambdaSI->HasImplicitReturnType) { Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible) - << NewAT->getDeducedType() << AT->getDeducedType() + << NewAT->getDeducedType() << DeducedT << true /*IsLambda*/; } else { Diag(ReturnLoc, diag::err_auto_fn_different_deductions) << (AT->isDecltypeAuto() ? 1 : 0) - << NewAT->getDeducedType() << AT->getDeducedType(); + << NewAT->getDeducedType() << DeducedT; } return true; } @@ -3097,9 +3158,8 @@ StmtResult Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp, Scope *CurScope) { StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp); - if (R.isInvalid()) { + if (R.isInvalid() || ExprEvalContexts.back().Context == DiscardedStatement) return R; - } if (VarDecl *VD = const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) { @@ -3148,6 +3208,19 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { } else // If we don't have a function/method context, bail. return StmtError(); + // C++1z: discarded return statements are not considered when deducing a + // return type. + if (ExprEvalContexts.back().Context == DiscardedStatement && + FnRetType->getContainedAutoType()) { + if (RetValExp) { + ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc); + if (ER.isInvalid()) + return StmtError(); + RetValExp = ER.get(); + } + return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr); + } + // FIXME: Add a flag to the ScopeInfo to indicate whether we're performing // deduction. if (getLangOpts().CPlusPlus14) { @@ -3525,11 +3598,6 @@ template <> struct DenseMapInfo<CatchHandlerType> { return LHS == RHS; } }; - -// It's OK to treat CatchHandlerType as a POD type. -template <> struct isPodLike<CatchHandlerType> { - static const bool value = true; -}; } namespace { @@ -3554,7 +3622,7 @@ public: bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) { if (S->getAccessSpecifier() == AccessSpecifier::AS_public) { CatchHandlerType Check(S->getType(), CheckAgainstPointer); - auto M = TypesToCheck; + const auto &M = TypesToCheck; auto I = M.find(Check); if (I != M.end()) { FoundHandler = I->second; @@ -3916,9 +3984,9 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) { CapturedDecl *CD = RSI->TheCapturedDecl; RecordDecl *RD = RSI->TheRecordDecl; - CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S, - RSI->CapRegionKind, Captures, - CaptureInits, CD, RD); + CapturedStmt *Res = CapturedStmt::Create( + getASTContext(), S, static_cast<CapturedRegionKind>(RSI->CapRegionKind), + Captures, CaptureInits, CD, RD); CD->setBody(Res->getCapturedStmt()); RD->completeDefinition(); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp index 11a4f8bfa85c..cd4269cd7eae 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp @@ -623,16 +623,12 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, if (!LookupName(BaseResult, getCurScope())) return true; - - LookupResult CurrBaseResult(BaseResult); - + + if(!BaseResult.isSingleResult()) + return true; + NamedDecl *FoundDecl = BaseResult.getFoundDecl(); for (StringRef NextMember : Members) { - - if (!CurrBaseResult.isSingleResult()) - return true; - const RecordType *RT = nullptr; - NamedDecl *FoundDecl = CurrBaseResult.getFoundDecl(); if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl)) RT = VD->getType()->getAs<RecordType>(); else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) { @@ -655,13 +651,15 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member, if (!LookupQualifiedName(FieldResult, RT->getDecl())) return true; + if (!FieldResult.isSingleResult()) + return true; + FoundDecl = FieldResult.getFoundDecl(); + // FIXME: Handle IndirectFieldDecl? - FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl()); + FieldDecl *FD = dyn_cast<FieldDecl>(FoundDecl); if (!FD) return true; - CurrBaseResult = FieldResult; - const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl()); unsigned i = FD->getFieldIndex(); CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i)); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp index 984bd078fa03..87fd88939572 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp @@ -25,9 +25,11 @@ using namespace sema; static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range) { + FallThroughAttr Attr(A.getRange(), S.Context, + A.getAttributeSpellingListIndex()); if (!isa<NullStmt>(St)) { S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target) - << St->getLocStart(); + << Attr.getSpelling() << St->getLocStart(); if (isa<SwitchCase>(St)) { SourceLocation L = S.getLocForEndOfToken(Range.getEnd()); S.Diag(L, diag::note_fallthrough_insert_semi_fixit) @@ -35,12 +37,20 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A, } return nullptr; } - if (S.getCurFunction()->SwitchStack.empty()) { + auto *FnScope = S.getCurFunction(); + if (FnScope->SwitchStack.empty()) { S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch); return nullptr; } - return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context, - A.getAttributeSpellingListIndex()); + + // If this is spelled as the standard C++1z attribute, but not in C++1z, warn + // about using it as an extension. + if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() && + !A.getScopeName()) + S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName(); + + FnScope->setHasFallthroughStmt(); + return ::new (S.Context) auto(Attr); } static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, @@ -97,6 +107,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, .Case("interleave_count", LoopHintAttr::InterleaveCount) .Case("unroll", LoopHintAttr::Unroll) .Case("unroll_count", LoopHintAttr::UnrollCount) + .Case("distribute", LoopHintAttr::Distribute) .Default(LoopHintAttr::Vectorize); if (Option == LoopHintAttr::VectorizeWidth || Option == LoopHintAttr::InterleaveCount || @@ -107,7 +118,8 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, State = LoopHintAttr::Numeric; } else if (Option == LoopHintAttr::Vectorize || Option == LoopHintAttr::Interleave || - Option == LoopHintAttr::Unroll) { + Option == LoopHintAttr::Unroll || + Option == LoopHintAttr::Distribute) { assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument"); if (StateLoc->Ident->isStr("disable")) State = LoopHintAttr::Disable; @@ -130,18 +142,21 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A, static void CheckForIncompatibleAttributes(Sema &S, const SmallVectorImpl<const Attr *> &Attrs) { - // There are 3 categories of loop hints attributes: vectorize, interleave, - // and unroll. Each comes in two variants: a state form and a numeric form. - // The state form selectively defaults/enables/disables the transformation - // for the loop (for unroll, default indicates full unrolling rather than - // enabling the transformation). The numeric form form provides an integer - // hint (for example, unroll count) to the transformer. The following array - // accumulates the hints encountered while iterating through the attributes - // to check for compatibility. + // There are 4 categories of loop hints attributes: vectorize, interleave, + // unroll and distribute. Except for distribute they come in two variants: a + // state form and a numeric form. The state form selectively + // defaults/enables/disables the transformation for the loop (for unroll, + // default indicates full unrolling rather than enabling the transformation). + // The numeric form form provides an integer hint (for example, unroll count) + // to the transformer. The following array accumulates the hints encountered + // while iterating through the attributes to check for compatibility. struct { const LoopHintAttr *StateAttr; const LoopHintAttr *NumericAttr; - } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}}; + } HintAttrs[] = {{nullptr, nullptr}, + {nullptr, nullptr}, + {nullptr, nullptr}, + {nullptr, nullptr}}; for (const auto *I : Attrs) { const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I); @@ -151,7 +166,7 @@ CheckForIncompatibleAttributes(Sema &S, continue; LoopHintAttr::OptionType Option = LH->getOption(); - enum { Vectorize, Interleave, Unroll } Category; + enum { Vectorize, Interleave, Unroll, Distribute } Category; switch (Option) { case LoopHintAttr::Vectorize: case LoopHintAttr::VectorizeWidth: @@ -165,12 +180,17 @@ CheckForIncompatibleAttributes(Sema &S, case LoopHintAttr::UnrollCount: Category = Unroll; break; + case LoopHintAttr::Distribute: + // Perform the check for duplicated 'distribute' hints. + Category = Distribute; + break; }; auto &CategoryState = HintAttrs[Category]; const LoopHintAttr *PrevAttr; if (Option == LoopHintAttr::Vectorize || - Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) { + Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll || + Option == LoopHintAttr::Distribute) { // Enable|Disable|AssumeSafety hint. For example, vectorize(enable). PrevAttr = CategoryState.StateAttr; CategoryState.StateAttr = LH; @@ -203,6 +223,52 @@ 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 + // 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) { + S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName() + << 1; + return nullptr; + } + + unsigned UnrollFactor = 0; + + if (NumArgs == 1) { + Expr *E = A.getArgAsExpr(0); + llvm::APSInt ArgVal(32); + + if (!E->isIntegerConstantExpr(ArgVal, S.Context)) { + S.Diag(A.getLoc(), diag::err_attribute_argument_type) + << A.getName() << AANT_ArgumentIntegerConstant << E->getSourceRange(); + return nullptr; + } + + int Val = ArgVal.getSExtValue(); + + if (Val <= 0) { + S.Diag(A.getRange().getBegin(), + diag::err_attribute_requires_positive_integer) + << A.getName(); + return nullptr; + } + UnrollFactor = Val; + } + + return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor); +} + static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, SourceRange Range) { switch (A.getKind()) { @@ -215,10 +281,12 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A, return handleFallThroughAttr(S, St, A, Range); case AttributeList::AT_LoopHint: return handleLoopHintAttr(S, St, A, Range); + case AttributeList::AT_OpenCLUnrollHint: + return handleOpenCLUnrollHint(S, St, A, Range); default: // if we're here, then we parsed a known attribute, but didn't recognize // it as a statement attribute => it is declaration attribute - S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt) + S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt) << A.getName() << St->getLocStart(); return nullptr; } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp index 138cee0b9424..7fc5db82d32c 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp @@ -1,13 +1,13 @@ -//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/ +//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. -//===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===// // // This file implements semantic analysis for C++ templates. -//===----------------------------------------------------------------------===/ +//===----------------------------------------------------------------------===// #include "TreeTransform.h" #include "clang/AST/ASTConsumer.h" @@ -32,6 +32,8 @@ #include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" + +#include <iterator> using namespace clang; using namespace sema; @@ -413,9 +415,22 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS, const TemplateArgumentListInfo *TemplateArgs) { DeclContext *DC = getFunctionLevelDeclContext(); - if (!isAddressOfOperand && - isa<CXXMethodDecl>(DC) && - cast<CXXMethodDecl>(DC)->isInstance()) { + // C++11 [expr.prim.general]p12: + // An id-expression that denotes a non-static data member or non-static + // member function of a class can only be used: + // (...) + // - if that id-expression denotes a non-static data member and it + // appears in an unevaluated operand. + // + // If this might be the case, form a DependentScopeDeclRefExpr instead of a + // CXXDependentScopeMemberExpr. The former can instantiate to either + // DeclRefExpr or MemberExpr depending on lookup results, while the latter is + // always a MemberExpr. + bool MightBeCxx11UnevalField = + getLangOpts().CPlusPlus11 && isUnevaluatedContext(); + + if (!MightBeCxx11UnevalField && !isAddressOfOperand && + isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) { QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context); // Since the 'this' expression is synthesized, we don't need to @@ -458,7 +473,6 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) { Diag(Loc, diag::err_template_param_shadow) << cast<NamedDecl>(PrevDecl)->getDeclName(); Diag(PrevDecl->getLocation(), diag::note_template_param_here); - return; } /// AdjustDeclIfTemplate - If the given decl happens to be a template, reset @@ -555,7 +569,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, ParsedType DefaultArg) { assert(S->isTemplateParamScope() && "Template type parameter not in template parameter scope!"); - bool Invalid = false; SourceLocation Loc = ParamNameLoc; if (!ParamName) @@ -567,8 +580,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, KeyLoc, Loc, Depth, Position, ParamName, Typename, IsParameterPack); Param->setAccess(AS_public); - if (Invalid) - Param->setInvalidDecl(); if (ParamName) { maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName); @@ -583,7 +594,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename, // template-parameter that is not a template parameter pack. if (DefaultArg && IsParameterPack) { Diag(EqualLoc, diag::err_template_param_pack_default_arg); - DefaultArg = ParsedType(); + DefaultArg = nullptr; } // Handle the default argument, if provided. @@ -790,7 +801,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, // However, it isn't worth doing. TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default); if (DefaultArg.getArgument().getAsTemplate().isNull()) { - Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template) + Diag(DefaultArg.getLocation(), diag::err_template_arg_not_valid_template) << DefaultArg.getSourceRange(); return Param; } @@ -807,18 +818,21 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S, return Param; } -/// ActOnTemplateParameterList - Builds a TemplateParameterList that -/// contains the template parameters in Params/NumParams. +/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally +/// constrained by RequiresClause, that contains the template parameters in +/// Params. TemplateParameterList * Sema::ActOnTemplateParameterList(unsigned Depth, SourceLocation ExportLoc, SourceLocation TemplateLoc, SourceLocation LAngleLoc, ArrayRef<Decl *> Params, - SourceLocation RAngleLoc) { + SourceLocation RAngleLoc, + Expr *RequiresClause) { 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()), @@ -916,6 +930,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, if (Previous.begin() != Previous.end()) PrevDecl = (*Previous.begin())->getUnderlyingDecl(); + if (PrevDecl && PrevDecl->isTemplateParameter()) { + // Maybe we will complain about the shadowed template parameter. + DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); + // Just pretend that we didn't see the previous declaration. + PrevDecl = nullptr; + } + // If there is a previous declaration with the same name, check // whether this is a valid redeclaration. ClassTemplateDecl *PrevClassTemplate @@ -1041,12 +1062,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK, // definition, as part of error recovery? return true; } - } - } else if (PrevDecl && PrevDecl->isTemplateParameter()) { - // Maybe we will complain about the shadowed template parameter. - DiagnoseTemplateParameterShadow(NameLoc, PrevDecl); - // Just pretend that we didn't see the previous declaration. - PrevDecl = nullptr; + } } else if (PrevDecl) { // C++ [temp]p5: // A class template shall not have the same name as any other @@ -1577,7 +1593,7 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> { return TraverseType(T->getInjectedSpecializationType()); } }; -} +} // end anonymous namespace /// Determines whether a given type depends on the given parameter /// list. @@ -2027,7 +2043,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, TemplateArgumentListInfo &TemplateArgs) { ASTContext &Context = SemaRef.getASTContext(); switch (BTD->getBuiltinTemplateKind()) { - case BTK__make_integer_seq: + case BTK__make_integer_seq: { // Specializations of __make_integer_seq<S, T, N> are treated like // S<T, 0, ..., N-1>. @@ -2069,6 +2085,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD, return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(), TemplateLoc, SyntheticTemplateArgs); } + + case BTK__type_pack_element: + // Specializations of + // __type_pack_element<Index, T_1, ..., T_N> + // are treated like T_Index. + assert(Converted.size() == 2 && + "__type_pack_element should be given an index and a parameter pack"); + + // If the Index is out of bounds, the program is ill-formed. + TemplateArgument IndexArg = Converted[0], Ts = Converted[1]; + llvm::APSInt Index = IndexArg.getAsIntegral(); + assert(Index >= 0 && "the index used with __type_pack_element should be of " + "type std::size_t, and hence be non-negative"); + if (Index >= Ts.pack_size()) { + SemaRef.Diag(TemplateArgs[0].getLocation(), + diag::err_type_pack_element_out_of_bounds); + return QualType(); + } + + // We simply return the type at index `Index`. + auto Nth = std::next(Ts.pack_begin(), Index.getExtValue()); + return Nth->getAsType(); + } llvm_unreachable("unexpected BuiltinTemplateDecl!"); } @@ -2119,7 +2158,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, return QualType(); TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; @@ -2150,8 +2189,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, // template<typename T, typename U = T> struct A; TemplateName CanonName = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonName, - Converted.data(), - Converted.size()); + Converted); // FIXME: CanonType is not actually the canonical type, and unfortunately // it is a TemplateSpecializationType that we will never use again. @@ -2213,8 +2251,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, ClassTemplate->getTemplatedDecl()->getLocStart(), ClassTemplate->getLocation(), ClassTemplate, - Converted.data(), - Converted.size(), nullptr); + Converted, nullptr); ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); @@ -2538,7 +2575,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), TemplateArgs.size(), + TemplateArgs.arguments(), InstantiationDependent)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << VarTemplate->getDeclName(); @@ -2595,7 +2632,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( VarTemplatePartialSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC, - Converted.data(), Converted.size(), TemplateArgs); + Converted, TemplateArgs); if (!PrevPartial) VarTemplate->AddPartialSpecialization(Partial, InsertPos); @@ -2637,7 +2674,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization( // this explicit specialization or friend declaration. Specialization = VarTemplateSpecializationDecl::Create( Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc, - VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size()); + VarTemplate, DI->getType(), DI, SC, Converted); Specialization->setTemplateArgsInfo(TemplateArgs); if (!PrevDecl) @@ -2713,7 +2750,7 @@ struct PartialSpecMatchResult { VarTemplatePartialSpecializationDecl *Partial; TemplateArgumentList *Args; }; -} +} // end anonymous namespace DeclResult Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, @@ -2733,9 +2770,11 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // corresponds to these arguments. void *InsertPos = nullptr; if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization( - Converted, InsertPos)) + Converted, InsertPos)) { + checkSpecializationVisibility(TemplateNameLoc, Spec); // If we already have a variable template specialization, return it. return Spec; + } // This is the first time we have referenced this variable template // specialization. Create the canonical declaration and add it to @@ -2743,7 +2782,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, // that it represents. That is, VarDecl *InstantiationPattern = Template->getTemplatedDecl(); TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + Converted); TemplateArgumentList *InstantiationArgs = &TemplateArgList; bool AmbiguousPartialSpec = false; typedef PartialSpecMatchResult MatchResult; @@ -2776,8 +2815,9 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, DeduceTemplateArguments(Partial, TemplateArgList, Info)) { // Store the failed-deduction information for use in diagnostics, later. // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); + FailedCandidates.addCandidate().set( + DeclAccessPair::make(Template, AS_public), Partial, + MakeDeductionFailureInfo(Context, Result, Info)); (void)Result; } else { Matched.push_back(PartialSpecMatchResult()); @@ -2834,8 +2874,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, } // 2. Create the canonical declaration. - // Note that we do not instantiate the variable just yet, since - // instantiation is handled in DoMarkVarDeclReferenced(). + // Note that we do not instantiate a definition until we see an odr-use + // in DoMarkVarDeclReferenced(). // FIXME: LateAttrs et al.? VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation( Template, InstantiationPattern, *InstantiationArgs, TemplateArgs, @@ -2863,6 +2903,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc, dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern)) Decl->setInstantiationOf(D, InstantiationArgs); + checkSpecializationVisibility(TemplateNameLoc, Decl); + assert(Decl && "No variable template specialization?"); return Decl; } @@ -3219,8 +3261,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, if (Inst.isInvalid()) return nullptr; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; @@ -3272,8 +3313,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, if (Inst.isInvalid()) return ExprError(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; @@ -3324,8 +3364,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef, if (Inst.isInvalid()) return TemplateName(); - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); // Only substitute for the innermost template argument list. MultiLevelTemplateArgumentList TemplateArgLists; @@ -3476,7 +3515,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, return true; TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + Converted); NTTPType = SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), NTTP->getLocation(), @@ -3616,8 +3655,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param, if (Inst.isInvalid()) return true; - TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, - Converted.data(), Converted.size()); + TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted); TempParm = cast_or_null<TemplateTemplateParmDecl>( SubstDecl(TempParm, CurContext, MultiLevelTemplateArgumentList(TemplateArgs))); @@ -3728,7 +3766,7 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc, S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD), D->getDefaultArgumentLoc(), Modules, Sema::MissingImportKind::DefaultArgument, - /*Recover*/ true); + /*Recover*/true); return true; } @@ -4014,7 +4052,7 @@ namespace { bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); }; -} +} // end anonymous namespace bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { return false; @@ -4229,7 +4267,6 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } - /// \brief Check a template argument against its corresponding /// template type parameter. /// @@ -5340,10 +5377,11 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param, // partial specializations. if (!isa<ClassTemplateDecl>(Template) && !isa<TemplateTemplateParmDecl>(Template) && - !isa<TypeAliasTemplateDecl>(Template)) { + !isa<TypeAliasTemplateDecl>(Template) && + !isa<BuiltinTemplateDecl>(Template)) { assert(isa<FunctionTemplateDecl>(Template) && "Only function templates are possible here"); - Diag(Arg.getLocation(), diag::err_template_arg_not_class_template); + Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template); Diag(Template->getLocation(), diag::note_template_arg_refers_here_func) << Template; } @@ -6281,9 +6319,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, bool InstantiationDependent; if (!Name.isDependent() && !TemplateSpecializationType::anyDependentTemplateArguments( - TemplateArgs.getArgumentArray(), - TemplateArgs.size(), - InstantiationDependent)) { + TemplateArgs.arguments(), InstantiationDependent)) { Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized) << ClassTemplate->getDeclName(); isPartialSpecialization = false; @@ -6316,8 +6352,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, // arguments of the class template partial specialization. TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType(CanonTemplate, - Converted.data(), - Converted.size()); + Converted); if (Context.hasSameType(CanonType, ClassTemplate->getInjectedClassNameSpecialization())) { @@ -6348,8 +6383,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, TemplateArgs, CanonType, PrevPartial); @@ -6404,8 +6438,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); if (TemplateParameterLists.size() > 0) { @@ -6423,7 +6456,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, "Only possible with -fms-extensions!"); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); CanonType = Context.getTemplateSpecializationType( - CanonTemplate, Converted.data(), Converted.size()); + CanonTemplate, Converted); } else { CanonType = Context.getTypeDeclType(Specialization); } @@ -6879,12 +6912,13 @@ bool Sema::CheckFunctionTemplateSpecialization( FunctionDecl *Specialization = nullptr; if (TemplateDeductionResult TDK = DeduceTemplateArguments( cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()), - ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info)) { + ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, + Info)) { // Template argument deduction failed; record why it failed, so // that we can provide nifty diagnostics. - FailedCandidates.addCandidate() - .set(FunTmpl->getTemplatedDecl(), - MakeDeductionFailureInfo(Context, TDK, Info)); + FailedCandidates.addCandidate().set( + I.getPair(), FunTmpl->getTemplatedDecl(), + MakeDeductionFailureInfo(Context, TDK, Info)); (void)TDK; continue; } @@ -6911,6 +6945,15 @@ bool Sema::CheckFunctionTemplateSpecialization( // Ignore access information; it doesn't figure into redeclaration checking. FunctionDecl *Specialization = cast<FunctionDecl>(*Result); + // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...] + // an explicit specialization (14.8.3) [...] of a concept definition. + if (Specialization->getPrimaryTemplate()->isConcept()) { + Diag(FD->getLocation(), diag::err_concept_specialized) + << 0 /*function*/ << 1 /*explicitly specialized*/; + Diag(Specialization->getLocation(), diag::note_previous_declaration); + return true; + } + FunctionTemplateSpecializationInfo *SpecInfo = Specialization->getTemplateSpecializationInfo(); assert(SpecInfo && "Function template specialization info missing?"); @@ -6960,6 +7003,21 @@ bool Sema::CheckFunctionTemplateSpecialization( // Mark the prior declaration as an explicit specialization, so that later // clients know that this is an explicit specialization. if (!isFriend) { + // Since explicit specializations do not inherit '=delete' from their + // primary function template - check if the 'specialization' that was + // implicitly generated (during template argument deduction for partial + // ordering) from the most specialized of all the function templates that + // 'FD' could have been specializing, has a 'deleted' definition. If so, + // first check that it was implicitly generated during template argument + // deduction by making sure it wasn't referenced, and then reset the deleted + // flag to not-deleted, so that we can inherit that information from 'FD'. + if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() && + !Specialization->getCanonicalDecl()->isReferenced()) { + assert( + Specialization->getCanonicalDecl() == Specialization && + "This must be the only existing declaration of this specialization"); + Specialization->setDeletedAsWritten(false); + } SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization); MarkUnusedFileScopedDecl(Specialization); } @@ -7001,6 +7059,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { assert(!isa<TemplateDecl>(Member) && "Only for non-template members"); // Try to find the member we are instantiating. + NamedDecl *FoundInstantiation = nullptr; NamedDecl *Instantiation = nullptr; NamedDecl *InstantiatedFrom = nullptr; MemberSpecializationInfo *MSInfo = nullptr; @@ -7016,6 +7075,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { if (!hasExplicitCallingConv(Adjusted)) Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType()); if (Context.hasSameType(Adjusted, Method->getType())) { + FoundInstantiation = *I; Instantiation = Method; InstantiatedFrom = Method->getInstantiatedFromMemberFunction(); MSInfo = Method->getMemberSpecializationInfo(); @@ -7028,6 +7088,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { if (Previous.isSingleResult() && (PrevVar = dyn_cast<VarDecl>(Previous.getFoundDecl()))) if (PrevVar->isStaticDataMember()) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevVar; InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember(); MSInfo = PrevVar->getMemberSpecializationInfo(); @@ -7036,6 +7097,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { CXXRecordDecl *PrevRecord; if (Previous.isSingleResult() && (PrevRecord = dyn_cast<CXXRecordDecl>(Previous.getFoundDecl()))) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevRecord; InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass(); MSInfo = PrevRecord->getMemberSpecializationInfo(); @@ -7044,6 +7106,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { EnumDecl *PrevEnum; if (Previous.isSingleResult() && (PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) { + FoundInstantiation = Previous.getRepresentativeDecl(); Instantiation = PrevEnum; InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum(); MSInfo = PrevEnum->getMemberSpecializationInfo(); @@ -7072,7 +7135,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { } Previous.clear(); - Previous.addDecl(Instantiation); + Previous.addDecl(FoundInstantiation); return false; } @@ -7119,6 +7182,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { InstantiationFunction->setTemplateSpecializationKind( TSK_ExplicitSpecialization); InstantiationFunction->setLocation(Member->getLocation()); + // Explicit specializations of member functions of class templates do not + // inherit '=delete' from the member function they are specializing. + if (InstantiationFunction->isDeleted()) { + assert(InstantiationFunction->getCanonicalDecl() == + InstantiationFunction); + InstantiationFunction->setDeletedAsWritten(false);
+ } } cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction( @@ -7166,7 +7236,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { // Save the caller the trouble of having to figure out which declaration // this specialization matches. Previous.clear(); - Previous.addDecl(Instantiation); + Previous.addDecl(FoundInstantiation); return false; } @@ -7268,15 +7338,21 @@ Sema::ActOnExplicitInstantiation(Scope *S, assert(Kind != TTK_Enum && "Invalid enum tag in class template explicit instantiation!"); - if (isa<TypeAliasTemplateDecl>(TD)) { - Diag(KWLoc, diag::err_tag_reference_non_tag) << Kind; - Diag(TD->getTemplatedDecl()->getLocation(), - diag::note_previous_use); + 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; + Diag(TD->getLocation(), diag::note_previous_use); return true; } - ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(TD); - if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(), Kind, /*isDefinition*/false, KWLoc, ClassTemplate->getIdentifier())) { @@ -7315,6 +7391,29 @@ Sema::ActOnExplicitInstantiation(Scope *S, } } + // In MSVC mode, dllimported explicit instantiation definitions are treated as + // instantiation declarations for most purposes. + bool DLLImportExplicitInstantiationDef = false; + if (TSK == TSK_ExplicitInstantiationDefinition && + Context.getTargetInfo().getCXXABI().isMicrosoft()) { + // Check for dllimport class template instantiation definitions. + bool DLLImport = + ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>(); + for (AttributeList *A = Attr; A; A = A->getNext()) { + if (A->getKind() == AttributeList::AT_DLLImport) + DLLImport = true; + if (A->getKind() == AttributeList::AT_DLLExport) { + // dllexport trumps dllimport here. + DLLImport = false; + break; + } + } + if (DLLImport) { + TSK = TSK_ExplicitInstantiationDeclaration; + DLLImportExplicitInstantiationDef = true; + } + } + // Translate the parser's template argument list in our AST format. TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc); translateTemplateArguments(TemplateArgsIn, TemplateArgs); @@ -7368,6 +7467,12 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->setLocation(TemplateNameLoc); PrevDecl = nullptr; } + + if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration && + DLLImportExplicitInstantiationDef) { + // The new specialization might add a dllimport attribute. + HasNoEffect = false; + } } if (!Specialization) { @@ -7378,8 +7483,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); @@ -7405,7 +7509,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, // Set source locations for keywords. Specialization->setExternLoc(ExternLoc); Specialization->setTemplateKeywordLoc(TemplateLoc); - Specialization->setRBraceLoc(SourceLocation()); + Specialization->setBraceRange(SourceRange()); if (Attr) ProcessDeclAttributeList(S, Specialization, Attr); @@ -7445,11 +7549,11 @@ Sema::ActOnExplicitInstantiation(Scope *S, Specialization->getDefinition()); if (Def) { TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind(); - // Fix a TSK_ExplicitInstantiationDeclaration followed by a // TSK_ExplicitInstantiationDefinition if (Old_TSK == TSK_ExplicitInstantiationDeclaration && - TSK == TSK_ExplicitInstantiationDefinition) { + (TSK == TSK_ExplicitInstantiationDefinition || + DLLImportExplicitInstantiationDef)) { // FIXME: Need to notify the ASTMutationListener that we did this. Def->setTemplateSpecializationKind(TSK); @@ -7462,7 +7566,13 @@ 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()) { @@ -7673,6 +7783,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_explicit_instantiation_constexpr); + // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be + // applied only to the definition of a function template or variable template, + // declared in namespace scope. + if (D.getDeclSpec().isConceptSpecified()) { + Diag(D.getDeclSpec().getConceptSpecLoc(), + diag::err_concept_specified_specialization) << 0; + return true; + } + // C++0x [temp.explicit]p2: // There are two forms of explicit instantiation: an explicit instantiation // definition and an explicit instantiation declaration. An explicit @@ -7744,6 +7863,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, return true; } + // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an + // explicit instantiation (14.8.2) [...] of a concept definition. + if (PrevTemplate->isConcept()) { + Diag(D.getIdentifierLoc(), diag::err_concept_specialized) + << 1 /*variable*/ << 0 /*explicitly instantiated*/; + Diag(PrevTemplate->getLocation(), diag::note_previous_declaration); + return true; + } + // Translate the parser's template argument list into our AST format. TemplateArgumentListInfo TemplateArgs = makeTemplateArgumentListInfo(*this, *D.getName().TemplateId); @@ -7856,7 +7984,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, R, Specialization, Info)) { // Keep track of almost-matches. FailedCandidates.addCandidate() - .set(FunTmpl->getTemplatedDecl(), + .set(P.getPair(), FunTmpl->getTemplatedDecl(), MakeDeductionFailureInfo(Context, TDK, Info)); (void)TDK; continue; @@ -7958,6 +8086,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S, diag::ext_explicit_instantiation_without_qualified_id) << Specialization << D.getCXXScopeSpec().getRange(); + // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an + // explicit instantiation (14.8.2) [...] of a concept definition. + if (FunTmpl && FunTmpl->isConcept() && + !D.getDeclSpec().isConceptSpecified()) { + Diag(D.getIdentifierLoc(), diag::err_concept_specialized) + << 0 /*function*/ << 0 /*explicitly instantiated*/; + Diag(FunTmpl->getLocation(), diag::note_previous_declaration); + return true; + } + CheckExplicitInstantiationScope(*this, FunTmpl? (NamedDecl *)FunTmpl : Specialization->getInstantiatedFromMemberFunction(), @@ -8294,7 +8432,7 @@ namespace { return E; } }; -} +} // end anonymous namespace /// \brief Rebuilds a type within the context of the current instantiation. /// @@ -8469,3 +8607,149 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() { } return false; } + +/// \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: +/// +/// If a template, a member template or a member of a class template is +/// explicitly specialized then that specialization shall be declared before +/// the first use of that specialization that would cause an implicit +/// instantiation to take place, in every translation unit in which such a +/// use occurs; no diagnostic is required. +/// +/// and also C++ [temp.class.spec]/1: +/// +/// A partial specialization shall be declared before the first use of a +/// class template specialization that would make use of the partial +/// specialization as the result of an implicit or explicit instantiation +/// in every translation unit in which such a use occurs; no diagnostic is +/// required. +class ExplicitSpecializationVisibilityChecker { + Sema &S; + SourceLocation Loc; + llvm::SmallVector<Module *, 8> Modules; + +public: + ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc) + : S(S), Loc(Loc) {} + + void check(NamedDecl *ND) { + if (auto *FD = dyn_cast<FunctionDecl>(ND)) + return checkImpl(FD); + if (auto *RD = dyn_cast<CXXRecordDecl>(ND)) + return checkImpl(RD); + if (auto *VD = dyn_cast<VarDecl>(ND)) + return checkImpl(VD); + if (auto *ED = dyn_cast<EnumDecl>(ND)) + return checkImpl(ED); + } + +private: + void diagnose(NamedDecl *D, bool IsPartialSpec) { + auto Kind = IsPartialSpec ? Sema::MissingImportKind::PartialSpecialization + : Sema::MissingImportKind::ExplicitSpecialization; + const bool Recover = true; + + // If we got a custom set of modules (because only a subset of the + // declarations are interesting), use them, otherwise let + // diagnoseMissingImport intelligently pick some. + if (Modules.empty()) + S.diagnoseMissingImport(Loc, D, Kind, Recover); + else + S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover); + } + + // Check a specific declaration. There are three problematic cases: + // + // 1) The declaration is an explicit specialization of a template + // specialization. + // 2) The declaration is an explicit specialization of a member of an + // templated class. + // 3) The declaration is an instantiation of a template, and that template + // is an explicit specialization of a member of a templated class. + // + // We don't need to go any deeper than that, as the instantiation of the + // surrounding class / etc is not triggered by whatever triggered this + // instantiation, and thus should be checked elsewhere. + template<typename SpecDecl> + void checkImpl(SpecDecl *Spec) { + bool IsHiddenExplicitSpecialization = false; + if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) { + IsHiddenExplicitSpecialization = + Spec->getMemberSpecializationInfo() + ? !S.hasVisibleMemberSpecialization(Spec, &Modules) + : !S.hasVisibleDeclaration(Spec); + } else { + checkInstantiated(Spec); + } + + if (IsHiddenExplicitSpecialization) + diagnose(Spec->getMostRecentDecl(), false); + } + + void checkInstantiated(FunctionDecl *FD) { + if (auto *TD = FD->getPrimaryTemplate()) + checkTemplate(TD); + } + + void checkInstantiated(CXXRecordDecl *RD) { + auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD); + if (!SD) + return; + + auto From = SD->getSpecializedTemplateOrPartial(); + if (auto *TD = From.dyn_cast<ClassTemplateDecl *>()) + checkTemplate(TD); + else if (auto *TD = + From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) { + if (!S.hasVisibleDeclaration(TD)) + diagnose(TD, true); + checkTemplate(TD); + } + } + + void checkInstantiated(VarDecl *RD) { + auto *SD = dyn_cast<VarTemplateSpecializationDecl>(RD); + if (!SD) + return; + + auto From = SD->getSpecializedTemplateOrPartial(); + if (auto *TD = From.dyn_cast<VarTemplateDecl *>()) + checkTemplate(TD); + else if (auto *TD = + From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) { + if (!S.hasVisibleDeclaration(TD)) + diagnose(TD, true); + checkTemplate(TD); + } + } + + void checkInstantiated(EnumDecl *FD) {} + + template<typename TemplDecl> + void checkTemplate(TemplDecl *TD) { + if (TD->isMemberSpecialization()) { + if (!S.hasVisibleMemberSpecialization(TD, &Modules)) + diagnose(TD->getMostRecentDecl(), false); + } + } +}; + +void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) { + if (!getLangOpts().Modules) + return; + + ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec); +} + +/// \brief Check whether a template partial specialization that we've discovered +/// is hidden, and produce suitable diagnostics if so. +void Sema::checkPartialSpecializationVisibility(SourceLocation Loc, + NamedDecl *Spec) { + llvm::SmallVector<Module *, 8> Modules; + if (!hasVisibleDeclaration(Spec, &Modules)) + diagnoseMissingImport(Loc, Spec, Spec->getLocation(), Modules, + MissingImportKind::PartialSpecialization, + /*Recover*/true); +} diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp index 71faafc6bc12..5740bc712e86 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp @@ -103,12 +103,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, bool PartialOrdering = false); static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced); + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + bool NumberOfArgumentsMustMatch); /// \brief If the given expression is of a form that permits the deduction /// of a non-type template parameter, return the declaration of that @@ -286,13 +286,10 @@ checkDeducedTemplateArguments(ASTContext &Context, /// \brief Deduce the value of the given non-type template parameter /// from the given constant. -static Sema::TemplateDeductionResult -DeduceNonTypeTemplateArgument(Sema &S, - NonTypeTemplateParmDecl *NTTP, - llvm::APSInt Value, QualType ValueType, - bool DeducedFromArrayBound, - TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced) { +static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument( + Sema &S, NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value, + QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info, + SmallVectorImpl<DeducedTemplateArgument> &Deduced) { assert(NTTP->getDepth() == 0 && "Cannot deduce non-type template argument with depth > 0"); @@ -456,10 +453,10 @@ 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->getArgs(), + Param->getNumArgs(), SpecArg->getArgs(), + SpecArg->getNumArgs(), Info, Deduced, + /*NumberOfArgumentsMustMatch=*/false); } // If the argument type is a class template specialization, we @@ -490,11 +487,10 @@ 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); + return DeduceTemplateArguments( + S, TemplateParams, Param->getArgs(), Param->getNumArgs(), + SpecArg->getTemplateArgs().data(), SpecArg->getTemplateArgs().size(), + Info, Deduced, /*NumberOfArgumentsMustMatch=*/true); } /// \brief Determines whether the given type is an opaque type that @@ -1418,85 +1414,101 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S, // TT<i> // TT<> case Type::TemplateSpecialization: { - const TemplateSpecializationType *SpecParam - = cast<TemplateSpecializationType>(Param); - - // Try to deduce template arguments from the template-id. - Sema::TemplateDeductionResult Result - = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, - Info, Deduced); - - if (Result && (TDF & TDF_DerivedClass)) { - // C++ [temp.deduct.call]p3b3: - // If P is a class, and P has the form template-id, then A can be a - // derived class of the deduced A. Likewise, if P is a pointer to a - // class of the form template-id, A can be a pointer to a derived - // class pointed to by the deduced A. - // - // More importantly: - // These alternatives are considered only if type deduction would - // otherwise fail. - if (const RecordType *RecordT = Arg->getAs<RecordType>()) { - // We cannot inspect base classes as part of deduction when the type - // is incomplete, so either instantiate any templates necessary to - // complete the type, or skip over it if it cannot be completed. - if (!S.isCompleteType(Info.getLocation(), Arg)) - return Result; - - // Use data recursion to crawl through the list of base classes. - // Visited contains the set of nodes we have already visited, while - // ToVisit is our stack of records that we still need to visit. - llvm::SmallPtrSet<const RecordType *, 8> Visited; - SmallVector<const RecordType *, 8> ToVisit; - ToVisit.push_back(RecordT); - bool Successful = false; - SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), - Deduced.end()); - while (!ToVisit.empty()) { - // Retrieve the next class in the inheritance hierarchy. - const RecordType *NextT = ToVisit.pop_back_val(); - - // If we have already seen this type, skip it. - if (!Visited.insert(NextT).second) - continue; - - // If this is a base class, try to perform template argument - // deduction from it. - if (NextT != RecordT) { - TemplateDeductionInfo BaseInfo(Info.getLocation()); - Sema::TemplateDeductionResult BaseResult - = DeduceTemplateArguments(S, TemplateParams, SpecParam, - QualType(NextT, 0), BaseInfo, - Deduced); - - // If template argument deduction for this base was successful, - // note that we had some success. Otherwise, ignore any deductions - // from this base class. - if (BaseResult == Sema::TDK_Success) { - Successful = true; - DeducedOrig.clear(); - DeducedOrig.append(Deduced.begin(), Deduced.end()); - Info.Param = BaseInfo.Param; - Info.FirstArg = BaseInfo.FirstArg; - Info.SecondArg = BaseInfo.SecondArg; - } - else - Deduced = DeducedOrig; - } - - // Visit base classes - CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); - for (const auto &Base : Next->bases()) { - assert(Base.getType()->isRecordType() && - "Base class that isn't a record?"); - ToVisit.push_back(Base.getType()->getAs<RecordType>()); - } + const TemplateSpecializationType *SpecParam = + cast<TemplateSpecializationType>(Param); + + // When Arg cannot be a derived class, we can just try to deduce template + // arguments from the template-id. + const RecordType *RecordT = Arg->getAs<RecordType>(); + if (!(TDF & TDF_DerivedClass) || !RecordT) + return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info, + Deduced); + + SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(), + Deduced.end()); + + Sema::TemplateDeductionResult Result = DeduceTemplateArguments( + S, TemplateParams, SpecParam, Arg, Info, Deduced); + + if (Result == Sema::TDK_Success) + return Result; + + // We cannot inspect base classes as part of deduction when the type + // is incomplete, so either instantiate any templates necessary to + // complete the type, or skip over it if it cannot be completed. + if (!S.isCompleteType(Info.getLocation(), Arg)) + return Result; + + // C++14 [temp.deduct.call] p4b3: + // 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 derived class pointed to by the + // deduced A. + // + // These alternatives are considered only if type deduction would + // otherwise fail. If they yield more than one possible deduced A, the + // type deduction fails. + + // Reset the incorrectly deduced argument from above. + Deduced = DeducedOrig; + + // Use data recursion to crawl through the list of base classes. + // Visited contains the set of nodes we have already visited, while + // ToVisit is our stack of records that we still need to visit. + llvm::SmallPtrSet<const RecordType *, 8> Visited; + SmallVector<const RecordType *, 8> ToVisit; + ToVisit.push_back(RecordT); + bool Successful = false; + SmallVector<DeducedTemplateArgument, 8> SuccessfulDeduced; + while (!ToVisit.empty()) { + // Retrieve the next class in the inheritance hierarchy. + const RecordType *NextT = ToVisit.pop_back_val(); + + // If we have already seen this type, skip it. + if (!Visited.insert(NextT).second) + continue; + + // If this is a base class, try to perform template argument + // deduction from it. + if (NextT != RecordT) { + TemplateDeductionInfo BaseInfo(Info.getLocation()); + Sema::TemplateDeductionResult BaseResult = + DeduceTemplateArguments(S, TemplateParams, SpecParam, + QualType(NextT, 0), BaseInfo, Deduced); + + // If template argument deduction for this base was successful, + // note that we had some success. Otherwise, ignore any deductions + // from this base class. + if (BaseResult == Sema::TDK_Success) { + // If we've already seen some success, then deduction fails due to + // an ambiguity (temp.deduct.call p5). + if (Successful) + return Sema::TDK_MiscellaneousDeductionFailure; + + Successful = true; + std::swap(SuccessfulDeduced, Deduced); + + Info.Param = BaseInfo.Param; + Info.FirstArg = BaseInfo.FirstArg; + Info.SecondArg = BaseInfo.SecondArg; } - if (Successful) - return Sema::TDK_Success; + Deduced = DeducedOrig; } + // Visit base classes + CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl()); + for (const auto &Base : Next->bases()) { + assert(Base.getType()->isRecordType() && + "Base class that isn't a record?"); + ToVisit.push_back(Base.getType()->getAs<RecordType>()); + } + } + + if (Successful) { + std::swap(SuccessfulDeduced, Deduced); + return Sema::TDK_Success; } return Result; @@ -1821,12 +1833,12 @@ static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args, } static Sema::TemplateDeductionResult -DeduceTemplateArguments(Sema &S, - TemplateParameterList *TemplateParams, +DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams, const TemplateArgument *Params, unsigned NumParams, const TemplateArgument *Args, unsigned NumArgs, TemplateDeductionInfo &Info, - SmallVectorImpl<DeducedTemplateArgument> &Deduced) { + SmallVectorImpl<DeducedTemplateArgument> &Deduced, + bool NumberOfArgumentsMustMatch) { // C++0x [temp.deduct.type]p9: // 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 @@ -1846,7 +1858,8 @@ DeduceTemplateArguments(Sema &S, // Check whether we have enough arguments. if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs)) - return Sema::TDK_Success; + 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, @@ -1917,7 +1930,7 @@ DeduceTemplateArguments(Sema &S, return DeduceTemplateArguments(S, TemplateParams, ParamList.data(), ParamList.size(), ArgList.data(), ArgList.size(), - Info, Deduced); + Info, Deduced, false); } /// \brief Determine whether two template arguments are the same. @@ -2060,11 +2073,45 @@ static bool ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, DeducedTemplateArgument Arg, NamedDecl *Template, - QualType NTTPType, - unsigned ArgumentPackIndex, TemplateDeductionInfo &Info, bool InFunctionTemplate, 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()); + + // Check the template argument, converting it as necessary. + return S.CheckTemplateArgument( + Param, ArgLoc, Template, Template->getLocation(), + Template->getSourceRange().getEnd(), ArgumentPackIndex, Output, + InFunctionTemplate + ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound + : Sema::CTAK_Deduced) + : Sema::CTAK_Specified); + }; + if (Arg.getKind() == TemplateArgument::Pack) { // This is a template argument pack, so check each of its arguments against // the template parameter. @@ -2075,39 +2122,41 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param, // checking logic has all of the prior template arguments available. DeducedTemplateArgument InnerArg(P); InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound()); - if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template, - NTTPType, PackedArgsBuilder.size(), - Info, InFunctionTemplate, Output)) + assert(InnerArg.getKind() != TemplateArgument::Pack && + "deduced nested pack"); + if (ConvertArg(InnerArg, PackedArgsBuilder.size())) return true; // Move the converted template argument into our argument pack. PackedArgsBuilder.push_back(Output.pop_back_val()); } + // 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. + 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; + } + // Create the resulting argument pack. Output.push_back( TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder)); return false; } - // 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()); - - // Check the template argument, converting it as necessary. - return S.CheckTemplateArgument(Param, ArgLoc, - Template, - Template->getLocation(), - Template->getSourceRange().getEnd(), - ArgumentPackIndex, - Output, - InFunctionTemplate - ? (Arg.wasDeducedFromArrayBound() - ? Sema::CTAK_DeducedFromArrayBound - : Sema::CTAK_Deduced) - : Sema::CTAK_Specified); + return ConvertArg(Arg, 0); } /// Complete template argument deduction for a class template partial @@ -2138,47 +2187,19 @@ FinishTemplateArgumentDeduction(Sema &S, // We have deduced this argument, so it still needs to be // checked and converted. - - // 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, - Builder.data(), Builder.size()); - NTTPType = S.SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - if (NTTPType.isNull()) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, - Builder.data(), - Builder.size())); - return Sema::TDK_SubstitutionFailure; - } - } - } - if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], - Partial, NTTPType, 0, Info, false, + Partial, Info, false, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), - Builder.size())); + 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.data(), - Builder.size()); + = TemplateArgumentList::CreateCopy(S.Context, Builder); Info.reset(DeducedArgumentList); @@ -2306,43 +2327,18 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction( // We have deduced this argument, so it still needs to be // checked and converted. - - // 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, - Builder.data(), Builder.size()); - NTTPType = - S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), NTTP->getDeclName()); - if (NTTPType.isNull()) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(), - Builder.size())); - return Sema::TDK_SubstitutionFailure; - } - } - } - - if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType, - 0, Info, false, Builder)) { + 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.data(), - Builder.size())); + 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.data(), Builder.size()); + S.Context, Builder); Info.reset(DeducedArgumentList); @@ -2488,7 +2484,7 @@ Sema::SubstituteExplicitTemplateArguments( if (ExplicitTemplateArgs.size() == 0) { // No arguments to substitute; just copy over the parameter types and // fill in the function type. - for (auto P : Function->params()) + for (auto P : Function->parameters()) ParamTypes.push_back(P->getType()); if (FunctionType) @@ -2533,7 +2529,7 @@ Sema::SubstituteExplicitTemplateArguments( // Form the template argument list from the explicitly-specified // template arguments. TemplateArgumentList *ExplicitArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size()); + = TemplateArgumentList::CreateCopy(Context, Builder); Info.reset(ExplicitArgumentList); // Template argument deduction and the final substitution should be @@ -2564,15 +2560,17 @@ Sema::SubstituteExplicitTemplateArguments( // Isolate our substituted parameters from our caller. LocalInstantiationScope InstScope(*this, /*MergeWithOuterScope*/true); + ExtParameterInfoBuilder ExtParamInfos; + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments. If the function has a trailing // return type, substitute it after the arguments to ensure we substitute // in lexical order. if (Proto->hasTrailingReturn()) { - if (SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), + if (SubstParmTypes(Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) + ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; } @@ -2602,21 +2600,23 @@ Sema::SubstituteExplicitTemplateArguments( if (ResultType.isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; } - + // Instantiate the types of each of the function parameters given the // explicitly-specified template arguments if we didn't do so earlier. if (!Proto->hasTrailingReturn() && - SubstParmTypes(Function->getLocation(), - Function->param_begin(), Function->getNumParams(), + SubstParmTypes(Function->getLocation(), Function->parameters(), + Proto->getExtParameterInfosOrNull(), MultiLevelTemplateArgumentList(*ExplicitArgumentList), - ParamTypes)) + ParamTypes, /*params*/ nullptr, ExtParamInfos)) return TDK_SubstitutionFailure; if (FunctionType) { + auto EPI = Proto->getExtProtoInfo(); + EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size()); *FunctionType = BuildFunctionType(ResultType, ParamTypes, Function->getLocation(), Function->getDeclName(), - Proto->getExtProtoInfo()); + EPI); if (FunctionType->isNull() || Trap.hasErrorOccurred()) return TDK_SubstitutionFailure; } @@ -2804,41 +2804,15 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, } continue; } + // We have deduced this argument, so it still needs to be // checked and converted. - - // 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, - Builder.data(), Builder.size()); - NTTPType = SubstType(NTTPType, - MultiLevelTemplateArgumentList(TemplateArgs), - NTTP->getLocation(), - NTTP->getDeclName()); - if (NTTPType.isNull()) { - Info.Param = makeTemplateParameter(Param); - // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, - Builder.data(), - Builder.size())); - return TDK_SubstitutionFailure; - } - } - } - if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I], - FunctionTemplate, NTTPType, 0, Info, + FunctionTemplate, Info, true, Builder)) { Info.Param = makeTemplateParameter(Param); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), - Builder.size())); + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); return TDK_SubstitutionFailure; } @@ -2862,11 +2836,21 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Builder.push_back(TemplateArgument( llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs))); - // Forget the partially-substituted pack; it's substitution is now + // Forget the partially-substituted pack; its substitution is now // complete. CurrentInstantiationScope->ResetPartiallySubstitutedPack(); } else { - Builder.push_back(TemplateArgument::getEmptyPack()); + // 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; } @@ -2884,8 +2868,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, if (DefArg.getArgument().isNull()) { Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), - Builder.size())); + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); if (PartialOverloading) break; return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete; @@ -2901,8 +2884,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, Info.Param = makeTemplateParameter( const_cast<NamedDecl *>(TemplateParams->getParam(I))); // FIXME: These template arguments are temporary. Free them! - Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(), - Builder.size())); + Info.reset(TemplateArgumentList::CreateCopy(Context, Builder)); return TDK_SubstitutionFailure; } @@ -2911,7 +2893,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate, // Form the template argument list from the deduced template arguments. TemplateArgumentList *DeducedArgumentList - = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size()); + = TemplateArgumentList::CreateCopy(Context, Builder); Info.reset(DeducedArgumentList); // Substitute the deduced template arguments into the function template @@ -3036,6 +3018,11 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams, return GetTypeOfFunction(S, R, ExplicitSpec); } + DeclAccessPair DAP; + if (FunctionDecl *Viable = + S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP)) + return GetTypeOfFunction(S, R, Viable); + return QualType(); } @@ -4609,11 +4596,9 @@ Sema::getMoreSpecializedPartialSpecialization( TemplateName Name(PS1->getSpecializedTemplate()); TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name); QualType PT1 = Context.getTemplateSpecializationType( - CanonTemplate, PS1->getTemplateArgs().data(), - PS1->getTemplateArgs().size()); + CanonTemplate, PS1->getTemplateArgs().asArray()); QualType PT2 = Context.getTemplateSpecializationType( - CanonTemplate, PS2->getTemplateArgs().data(), - PS2->getTemplateArgs().size()); + CanonTemplate, PS2->getTemplateArgs().asArray()); // Determine whether PS1 is at least as specialized as PS2 Deduced.resize(PS2->getTemplateParameters()->size()); diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp index fb7fc109d2e9..48c6a506ee36 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -21,6 +21,7 @@ #include "clang/Sema/DeclSpec.h" #include "clang/Sema/Initialization.h" #include "clang/Sema/Lookup.h" +#include "clang/Sema/PrettyDeclStackTrace.h" #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" @@ -446,10 +447,8 @@ void Sema::PrintInstantiationStack() { SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); Template->printName(OS); - TemplateSpecializationType::PrintTemplateArgumentList(OS, - Active->TemplateArgs, - Active->NumTemplateArgs, - getPrintingPolicy()); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_arg_instantiation_here) << OS.str() @@ -500,10 +499,8 @@ void Sema::PrintInstantiationStack() { SmallVector<char, 128> TemplateArgsStr; llvm::raw_svector_ostream OS(TemplateArgsStr); FD->printName(OS); - TemplateSpecializationType::PrintTemplateArgumentList(OS, - Active->TemplateArgs, - Active->NumTemplateArgs, - getPrintingPolicy()); + TemplateSpecializationType::PrintTemplateArgumentList( + OS, Active->template_arguments(), getPrintingPolicy()); Diags.Report(Active->PointOfInstantiation, diag::note_default_function_arg_instantiation_here) << OS.str() @@ -729,6 +726,11 @@ namespace { } SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New); + + // We recreated a local declaration, but not by instantiating it. There + // may be pending dependent diagnostics to produce. + if (auto *DC = dyn_cast<DeclContext>(Old)) + SemaRef.PerformDependentDiagnostics(DC, TemplateArgs); } /// \brief Transform the definition of the given declaration by @@ -1512,7 +1514,7 @@ QualType Sema::SubstType(QualType T, } static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { - if (T->getType()->isInstantiationDependentType() || + if (T->getType()->isInstantiationDependentType() || T->getType()->isVariablyModifiedType()) return true; @@ -1521,23 +1523,13 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) { return false; FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>(); - for (unsigned I = 0, E = FP.getNumParams(); I != E; ++I) { - ParmVarDecl *P = FP.getParam(I); - + for (ParmVarDecl *P : FP.getParams()) { // This must be synthesized from a typedef. if (!P) continue; - // The parameter's type as written might be dependent even if the - // decayed type was not dependent. - if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo()) - if (TSInfo->getType()->isInstantiationDependentType()) - return true; - - // TODO: currently we always rebuild expressions. When we - // properly get lazier about this, we should use the same - // logic to avoid rebuilding prototypes here. - if (P->hasDefaultArg()) - return true; + // If there are any parameters, a new TypeSourceInfo that refers to the + // instantiated parameters must be built. + return true; } return false; @@ -1556,7 +1548,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T, assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); - + if (!NeedsInstantiationAsFunctionType(T)) return T; @@ -1718,20 +1710,21 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm, /// \brief Substitute the given template arguments into the given set of /// parameters, producing the set of parameter types that would be generated /// from such a substitution. -bool Sema::SubstParmTypes(SourceLocation Loc, - ParmVarDecl **Params, unsigned NumParams, - const MultiLevelTemplateArgumentList &TemplateArgs, - SmallVectorImpl<QualType> &ParamTypes, - SmallVectorImpl<ParmVarDecl *> *OutParams) { +bool Sema::SubstParmTypes( + SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, + const FunctionProtoType::ExtParameterInfo *ExtParamInfos, + const MultiLevelTemplateArgumentList &TemplateArgs, + SmallVectorImpl<QualType> &ParamTypes, + SmallVectorImpl<ParmVarDecl *> *OutParams, + ExtParameterInfoBuilder &ParamInfos) { assert(!ActiveTemplateInstantiations.empty() && "Cannot perform an instantiation without some context on the " "instantiation stack"); TemplateInstantiator Instantiator(*this, TemplateArgs, Loc, DeclarationName()); - return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams, - nullptr, ParamTypes, - OutParams); + return Instantiator.TransformFunctionTypeParams( + Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos); } /// \brief Perform substitution on the base class specifiers of the @@ -1861,8 +1854,19 @@ static bool DiagnoseUninstantiableTemplate(Sema &S, TagDecl *PatternDef, TemplateSpecializationKind TSK, bool Complain = true) { - if (PatternDef && !PatternDef->isBeingDefined()) + 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 @@ -1946,6 +1950,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + "instantiating class definition"); // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -1959,6 +1965,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod(); LocalInstantiationScope Scope(*this, MergeWithParentScope); + // All dllexported classes created during instantiation should be fully + // emitted after instantiation completes. We may not be ready to emit any + // delayed classes already on the stack, so save them away and put them back + // later. + decltype(DelayedDllExportClasses) ExportedClasses; + std::swap(ExportedClasses, DelayedDllExportClasses); + // Pull attributes from the pattern onto the instantiation. InstantiateAttrs(TemplateArgs, Pattern, Instantiation); @@ -2044,6 +2057,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, // default arg exprs for default constructors if necessary now. ActOnFinishCXXNonNestedClass(Instantiation); + // Put back the delayed exported classes that we moved out of the way. + std::swap(ExportedClasses, DelayedDllExportClasses); + // Instantiate late parsed attributes, and attach them to their decls. // See Sema::InstantiateAttrs for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(), @@ -2074,7 +2090,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, if (TSK == TSK_ImplicitInstantiation) { Instantiation->setLocation(Pattern->getLocation()); Instantiation->setLocStart(Pattern->getInnerLocStart()); - Instantiation->setRBraceLoc(Pattern->getRBraceLoc()); + Instantiation->setBraceRange(Pattern->getBraceRange()); } if (!Instantiation->isInvalidDecl()) { @@ -2159,6 +2175,8 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + "instantiating enum definition"); // The instantiation is visible here, even if it was first declared in an // unimported module. @@ -2231,6 +2249,8 @@ bool Sema::InstantiateInClassInitializer( InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(), + "instantiating default member init"); // Enter the scope of this instantiation. We don't use PushDeclContext because // we don't have a scope. @@ -2302,8 +2322,9 @@ bool Sema::InstantiateClassTemplateSpecialization( Info)) { // Store the failed-deduction information for use in diagnostics, later. // TODO: Actually use the failed-deduction info? - FailedCandidates.addCandidate() - .set(Partial, MakeDeductionFailureInfo(Context, Result, Info)); + FailedCandidates.addCandidate().set( + DeclAccessPair::make(Template, AS_public), Partial, + MakeDeductionFailureInfo(Context, Result, Info)); (void)Result; } else { Matched.push_back(PartialSpecMatchResult()); @@ -2495,8 +2516,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, // specialization and is only an explicit instantiation definition // of members whose definition is visible at the point of // instantiation. - if (!Var->getInstantiatedFromStaticDataMember() - ->getOutOfLineDefinition()) + if (!Var->getInstantiatedFromStaticDataMember()->getDefinition()) continue; Var->setTemplateSpecializationKind(TSK, PointOfInstantiation); @@ -2522,6 +2542,13 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, == TSK_ExplicitSpecialization) continue; + if (Context.getTargetInfo().getCXXABI().isMicrosoft() && + TSK == TSK_ExplicitInstantiationDeclaration) { + // In MSVC mode, explicit instantiation decl of the outer class doesn't + // affect the inner class. + continue; + } + if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK, Record, MSInfo->getTemplateSpecializationKind(), @@ -2583,7 +2610,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, if (Enum->getDefinition()) continue; - EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum(); + EnumDecl *Pattern = Enum->getTemplateInstantiationPattern(); assert(Pattern && "Missing instantiated-from-template information"); if (TSK == TSK_ExplicitInstantiationDefinition) { @@ -2603,8 +2630,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation, Instantiation->getTemplateInstantiationPattern(); DeclContext::lookup_result Lookup = ClassPattern->lookup(Field->getDeclName()); - assert(Lookup.size() == 1); - FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]); + FieldDecl *Pattern = cast<FieldDecl>(Lookup.front()); InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern, TemplateArgs); } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 7a452af77839..6a213953ec9a 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -227,6 +227,86 @@ static void instantiateDependentCUDALaunchBoundsAttr( Attr.getSpellingListIndex()); } +static void +instantiateDependentModeAttr(Sema &S, + const MultiLevelTemplateArgumentList &TemplateArgs, + const ModeAttr &Attr, Decl *New) { + S.AddModeAttr(Attr.getRange(), New, Attr.getMode(), + Attr.getSpellingListIndex(), /*InInstantiation=*/true); +} + +/// Instantiation of 'declare simd' attribute and its arguments. +static void instantiateOMPDeclareSimdDeclAttr( + Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs, + const OMPDeclareSimdDeclAttr &Attr, Decl *New) { + // Allow 'this' in clauses with varlists. + if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New)) + New = FTD->getTemplatedDecl(); + auto *FD = cast<FunctionDecl>(New); + auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext()); + SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps; + SmallVector<unsigned, 4> LinModifiers; + + auto &&Subst = [&](Expr *E) -> ExprResult { + if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts())) + if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) { + Sema::ContextRAII SavedContext(S, FD); + LocalInstantiationScope Local(S); + if (FD->getNumParams() > PVD->getFunctionScopeIndex()) + Local.InstantiatedLocal( + PVD, FD->getParamDecl(PVD->getFunctionScopeIndex())); + return S.SubstExpr(E, TemplateArgs); + } + Sema::CXXThisScopeRAII ThisScope(S, ThisContext, /*TypeQuals=*/0, + FD->isCXXInstanceMember()); + return S.SubstExpr(E, TemplateArgs); + }; + + ExprResult Simdlen; + if (auto *E = Attr.getSimdlen()) + Simdlen = Subst(E); + + if (Attr.uniforms_size() > 0) { + for(auto *E : Attr.uniforms()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Uniforms.push_back(Inst.get()); + } + } + + auto AI = Attr.alignments_begin(); + for (auto *E : Attr.aligneds()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Aligneds.push_back(Inst.get()); + Inst = ExprEmpty(); + if (*AI) + Inst = S.SubstExpr(*AI, TemplateArgs); + Alignments.push_back(Inst.get()); + ++AI; + } + + auto SI = Attr.steps_begin(); + for (auto *E : Attr.linears()) { + ExprResult Inst = Subst(E); + if (Inst.isInvalid()) + continue; + Linears.push_back(Inst.get()); + Inst = ExprEmpty(); + if (*SI) + Inst = S.SubstExpr(*SI, TemplateArgs); + Steps.push_back(Inst.get()); + ++SI; + } + LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end()); + (void)S.ActOnOpenMPDeclareSimdDirective( + S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(), + Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps, + Attr.getRange()); +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -265,6 +345,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) { + instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New); + continue; + } + + if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) { + instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New); + continue; + } + // Existing DLL attribute on the instantiation takes precedence. if (TmplAttr->getKind() == attr::DLLExport || TmplAttr->getKind() == attr::DLLImport) { @@ -273,6 +363,20 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, } } + if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) { + AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(), + ABIAttr->getSpellingListIndex()); + continue; + } + + if (isa<NSConsumedAttr>(TmplAttr) || isa<CFConsumedAttr>(TmplAttr)) { + AddNSConsumedAttr(TmplAttr->getRange(), New, + TmplAttr->getSpellingListIndex(), + isa<NSConsumedAttr>(TmplAttr), + /*template instantiation*/ true); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -321,6 +425,16 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) { } Decl * +TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) { + llvm_unreachable("pragma comment cannot be instantiated"); +} + +Decl *TemplateDeclInstantiator::VisitPragmaDetectMismatchDecl( + PragmaDetectMismatchDecl *D) { + llvm_unreachable("pragma comment cannot be instantiated"); +} + +Decl * TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) { llvm_unreachable("extern \"C\" context cannot be instantiated"); } @@ -491,13 +605,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) { Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D, bool InstantiatingVarTemplate) { - // If this is the variable for an anonymous struct or union, - // instantiate the anonymous struct/union type first. - if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -696,7 +803,7 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) { QualType T = cast<FieldDecl>(NamedChain[i-1])->getType(); IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create( SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T, - NamedChain, D->getChainingSize()); + {NamedChain, D->getChainingSize()}); for (const auto *Attr : D->attrs()) IndirectField->addAttr(Attr->clone(SemaRef.Context)); @@ -911,9 +1018,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition( } } - // FIXME: Fixup LBraceLoc - SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(), - Enum->getRBraceLoc(), Enum, + SemaRef.ActOnEnumBody(Enum->getLocation(), Enum->getBraceRange(), Enum, Enumerators, nullptr, nullptr); } @@ -1499,8 +1604,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D, ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Function->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.begin(), - Innermost.size()), + Innermost), /*InsertPos=*/nullptr); } else if (isFriend) { // Note, we need this connection even if the friend doesn't have a body. @@ -1736,36 +1840,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, Constructor->isExplicit(), Constructor->isInlineSpecified(), false, Constructor->isConstexpr()); - - // Claim that the instantiation of a constructor or constructor template - // inherits the same constructor that the template does. - if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>( - Constructor->getInheritedConstructor())) { - // If we're instantiating a specialization of a function template, our - // "inherited constructor" will actually itself be a function template. - // Instantiate a declaration of it, too. - if (FunctionTemplate) { - assert(!TemplateParams && Inh->getDescribedFunctionTemplate() && - !Inh->getParent()->isDependentContext() && - "inheriting constructor template in dependent context?"); - Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(), - Inh); - if (Inst.isInvalid()) - return nullptr; - Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext()); - LocalInstantiationScope LocalScope(SemaRef); - - // Use the same template arguments that we deduced for the inheriting - // constructor. There's no way they could be deduced differently. - MultiLevelTemplateArgumentList InheritedArgs; - InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost()); - Inh = cast_or_null<CXXConstructorDecl>( - SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs)); - if (!Inh) - return nullptr; - } - cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh); - } } else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) { Method = CXXDestructorDecl::Create(SemaRef.Context, Record, StartLoc, NameInfo, T, TInfo, @@ -1821,8 +1895,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D, ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost(); Method->setFunctionTemplateSpecialization(FunctionTemplate, TemplateArgumentList::CreateCopy(SemaRef.Context, - Innermost.begin(), - Innermost.size()), + Innermost), /*InsertPos=*/nullptr); } else if (!isFriend) { // Record that this is an instantiation of a member function. @@ -2080,16 +2153,11 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( NonTypeTemplateParmDecl *Param; if (IsExpandedParameterPack) - Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, - D->getInnerLocStart(), - D->getLocation(), - D->getDepth() - TemplateArgs.getNumLevels(), - D->getPosition(), - D->getIdentifier(), T, - DI, - ExpandedParameterPackTypes.data(), - ExpandedParameterPackTypes.size(), - ExpandedParameterPackTypesAsWritten.data()); + Param = NonTypeTemplateParmDecl::Create( + SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), + D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(), + D->getIdentifier(), T, DI, ExpandedParameterPackTypes, + ExpandedParameterPackTypesAsWritten); else Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner, D->getInnerLocStart(), @@ -2104,6 +2172,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl( Param->setInvalidDecl(); if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) { + EnterExpressionEvaluationContext ConstantEvaluated(SemaRef, + Sema::ConstantEvaluated); ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs); if (!Value.isInvalid()) Param->setDefaultArgument(Value.get()); @@ -2289,9 +2359,14 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (!QualifierLoc) return nullptr; - // The name info is non-dependent, so no transformation - // is required. + // 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. DeclarationNameInfo NameInfo = D->getNameInfo(); + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) + if (auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext)) + NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName( + SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD)))); // We only need to do redeclaration lookups if we're in a class // scope (in fact, it's not really even possible in non-class @@ -2334,18 +2409,23 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) { if (NewUD->isInvalidDecl()) return NewUD; - if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) { + if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) SemaRef.CheckInheritingConstructorUsingDecl(NewUD); - return NewUD; - } bool isFunctionScope = Owner->isFunctionOrMethod(); // Process the shadow decls. for (auto *Shadow : D->shadows()) { + // FIXME: UsingShadowDecl doesn't preserve its immediate target, so + // reconstruct it in the case where it matters. + NamedDecl *OldTarget = Shadow->getTargetDecl(); + if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow)) + if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl()) + OldTarget = BaseShadow; + NamedDecl *InstTarget = cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl( - Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs)); + Shadow->getLocation(), OldTarget, TemplateArgs)); if (!InstTarget) return nullptr; @@ -2376,6 +2456,12 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) { return nullptr; } +Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl( + ConstructorUsingShadowDecl *D) { + // Ignore these; we handle them in bulk when processing the UsingDecl. + return nullptr; +} + Decl * TemplateDeclInstantiator ::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) { NestedNameSpecifierLoc QualifierLoc @@ -2477,6 +2563,86 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl( return TD; } +Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl( + OMPDeclareReductionDecl *D) { + // Instantiate type and check if it is allowed. + QualType SubstReductionType = SemaRef.ActOnOpenMPDeclareReductionType( + D->getLocation(), + ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs, + D->getLocation(), DeclarationName()))); + if (SubstReductionType.isNull()) + return nullptr; + bool IsCorrect = !SubstReductionType.isNull(); + // Create instantiated copy. + std::pair<QualType, SourceLocation> ReductionTypes[] = { + std::make_pair(SubstReductionType, D->getLocation())}; + auto *PrevDeclInScope = D->getPrevDeclInScope(); + if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) { + PrevDeclInScope = cast<OMPDeclareReductionDecl>( + SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope) + ->get<Decl *>()); + } + auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart( + /*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(), + PrevDeclInScope); + auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl()); + if (isDeclWithinFunction(NewDRD)) + SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD); + Expr *SubstCombiner = nullptr; + Expr *SubstInitializer = nullptr; + // Combiners instantiation sequence. + if (D->getCombiner()) { + SemaRef.ActOnOpenMPDeclareReductionCombinerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_in", "omp_out"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldLookup.front(), + Lookup.front()); + } + } + SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner); + // Initializers instantiation sequence. + if (D->getInitializer()) { + SemaRef.ActOnOpenMPDeclareReductionInitializerStart( + /*S=*/nullptr, NewDRD); + const char *Names[] = {"omp_orig", "omp_priv"}; + for (auto &Name : Names) { + DeclarationName DN(&SemaRef.Context.Idents.get(Name)); + auto OldLookup = D->lookup(DN); + auto Lookup = NewDRD->lookup(DN); + if (!OldLookup.empty() && !Lookup.empty()) { + assert(Lookup.size() == 1 && OldLookup.size() == 1); + SemaRef.CurrentInstantiationScope->InstantiatedLocal( + OldLookup.front(), Lookup.front()); + } + } + SubstInitializer = + SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get(); + SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD, + SubstInitializer); + } + IsCorrect = IsCorrect && SubstCombiner && + (!D->getInitializer() || SubstInitializer); + } else + IsCorrect = false; + + (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD, + IsCorrect); + + return NewDRD; +} + +Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl( + OMPCapturedExprDecl * /*D*/) { + llvm_unreachable("Should not be met in templates"); +} + Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) { return VisitFunctionDecl(D, nullptr); } @@ -2580,8 +2746,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( D->getLocStart(), D->getLocation(), InstClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); // Add this partial specialization to the set of class template partial @@ -2596,7 +2761,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl( // Build the canonical type that describes the converted template // arguments of the class template explicit specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(InstClassTemplate), Converted.data(), Converted.size(), + TemplateName(InstClassTemplate), Converted, SemaRef.Context.getRecordType(InstD)); // Build the fully-sugared type for this class template @@ -2673,13 +2838,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( const TemplateArgumentListInfo &TemplateArgsInfo, ArrayRef<TemplateArgument> Converted) { - // If this is the variable for an anonymous struct or union, - // instantiate the anonymous struct/union type first. - if (const RecordType *RecordTy = D->getType()->getAs<RecordType>()) - if (RecordTy->getDecl()->isAnonymousStructOrUnion()) - if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl()))) - return nullptr; - // Do substitution on the type of the declaration TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs, @@ -2696,8 +2854,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl( // Build the instantiated declaration VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create( SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(), - VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(), - Converted.size()); + VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted); Var->setTemplateArgsInfo(TemplateArgsInfo); if (InsertPos) VarTemplate->AddSpecialization(Var, InsertPos); @@ -2830,8 +2987,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( // arguments of the class template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate), - Converted.data(), - Converted.size()); + Converted); // Build the fully-sugared type for this class template // specialization as the user wrote in the specialization @@ -2880,8 +3036,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization( PartialSpec->getLocation(), InstParams, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, InstTemplateArgs, CanonType, nullptr); @@ -2953,7 +3108,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( // Build the canonical type that describes the converted template // arguments of the variable template partial specialization. QualType CanonType = SemaRef.Context.getTemplateSpecializationType( - TemplateName(VarTemplate), Converted.data(), Converted.size()); + TemplateName(VarTemplate), Converted); // Build the fully-sugared type for this variable template // specialization as the user wrote in the specialization @@ -3009,8 +3164,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization( VarTemplatePartialSpecializationDecl::Create( SemaRef.Context, Owner, PartialSpec->getInnerLocStart(), PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(), - DI, PartialSpec->getStorageClass(), Converted.data(), - Converted.size(), InstTemplateArgs); + DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs); // Substitute the nested name specifier, if any. if (SubstQualifier(PartialSpec, InstPartialSpec)) @@ -3118,9 +3272,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D, // In this case, we'll just go instantiate the ParmVarDecls that we // synthesized in the method declaration. SmallVector<QualType, 4> ParamTypes; - if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(), - D->getNumParams(), TemplateArgs, ParamTypes, - &Params)) + Sema::ExtParameterInfoBuilder ExtParamInfos; + if (SemaRef.SubstParmTypes(D->getLocation(), D->parameters(), nullptr, + TemplateArgs, ParamTypes, &Params, + ExtParamInfos)) return nullptr; } @@ -3347,7 +3502,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New, void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, FunctionDecl *Function, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, + bool AtEndOfTU) { if (Function->isInvalidDecl() || Function->isDefined()) return; @@ -3401,6 +3557,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, 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()) @@ -3421,6 +3581,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, 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; @@ -3451,6 +3621,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), + "instantiating function definition"); // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); @@ -3681,11 +3853,12 @@ void Sema::BuildVariableInstantiation( Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar)); Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar)); - // Delay instantiation of the initializer for variable templates until a - // definition of the variable is needed. We need it right away if the type - // contains 'auto'. + // Delay instantiation of the initializer for variable templates or inline + // static data members until a definition of the variable is needed. We need + // it right away if the type contains 'auto'. if ((!isa<VarTemplateSpecializationDecl>(NewVar) && - !InstantiatingVarTemplate) || + !InstantiatingVarTemplate && + !(OldVar->isInline() && OldVar->isThisDeclarationADefinition())) || NewVar->getType()->isUndeducedType()) InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs); @@ -3701,6 +3874,13 @@ void Sema::BuildVariableInstantiation( void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { + // We propagate the 'inline' flag with the initializer, because it + // would otherwise imply that the variable is a definition for a + // non-static data member. + if (OldVar->isInlineSpecified()) + Var->setInlineSpecified(); + else if (OldVar->isInline()) + Var->setImplicitlyInline(); if (Var->getAnyInitializer()) // We already have an initializer in the class. @@ -3713,9 +3893,14 @@ void Sema::InstantiateVariableInitializer( PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar); // Instantiate the initializer. - ExprResult Init = - SubstInitializer(OldVar->getInit(), TemplateArgs, - OldVar->getInitStyle() == VarDecl::CallInit); + ExprResult Init; + + { + ContextRAII SwitchContext(*this, Var->getDeclContext()); + Init = SubstInitializer(OldVar->getInit(), TemplateArgs, + OldVar->getInitStyle() == VarDecl::CallInit); + } + if (!Init.isInvalid()) { bool TypeMayContainAuto = true; Expr *InitExpr = Init.get(); @@ -3768,7 +3953,7 @@ void Sema::InstantiateStaticDataMemberDefinition( void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, bool AtEndOfTU) { if (Var->isInvalidDecl()) return; @@ -3830,6 +4015,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable initializer"); // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate @@ -3876,9 +4063,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, assert(PatternDecl && "data member was not instantiated from a template?"); assert(PatternDecl->isStaticDataMember() && "not a static data member?"); - Def = PatternDecl->getOutOfLineDefinition(); + 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. + // 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 @@ -3900,6 +4091,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, == TSK_ExplicitInstantiationDefinition) { PendingInstantiations.push_back( std::make_pair(Var, PointOfInstantiation)); + } else if (Var->getTemplateSpecializationKind() + == TSK_ImplicitInstantiation) { + // Warn about missing definition at the end of translation unit. + if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) { + Diag(PointOfInstantiation, diag::warn_var_template_missing) + << Var; + Diag(PatternDecl->getLocation(), diag::note_forward_template_decl); + if (getLangOpts().CPlusPlus11) + Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var; + } } return; @@ -3943,6 +4144,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); if (Inst.isInvalid()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(), + "instantiating variable definition"); // If we're performing recursive template instantiation, create our own // queue of pending implicit instantiations that we will instantiate later, @@ -3958,11 +4161,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, LocalInstantiationScope Local(*this); VarDecl *OldVar = Var; - if (!VarSpec) + if (Def->isStaticDataMember() && !Def->isOutOfLine()) { + // We're instantiating an inline static data member whose definition was + // provided inside the class. + // FIXME: Update record? + InstantiateVariableInitializer(Var, Def, TemplateArgs); + } else if (!VarSpec) { Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(), TemplateArgs)); - else if (Var->isStaticDataMember() && - Var->getLexicalDeclContext()->isRecord()) { + } else if (Var->isStaticDataMember() && + Var->getLexicalDeclContext()->isRecord()) { // We need to instantiate the definition of a static data member template, // and all we have is the in-class declaration of it. Instantiate a separate // declaration of the definition. @@ -4664,12 +4872,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Instantiate function definitions if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) { - PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), - "instantiating function definition"); bool DefinitionRequired = Function->getTemplateSpecializationKind() == TSK_ExplicitInstantiationDefinition; InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true, - DefinitionRequired); + DefinitionRequired, true); continue; } @@ -4710,7 +4916,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) { // Instantiate static data member definitions or variable template // specializations. InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true, - DefinitionRequired); + DefinitionRequired, true); } } diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp index cb67d71f9e59..06afe87f515e 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp @@ -604,7 +604,7 @@ bool Sema::CheckParameterPacksForExpansion( // Template argument deduction can extend the sequence of template // arguments corresponding to a template parameter pack, even when the // sequence contains explicitly specified template arguments. - if (!IsFunctionParameterPack) { + if (!IsFunctionParameterPack && CurrentInstantiationScope) { if (NamedDecl *PartialPack = CurrentInstantiationScope->getPartiallySubstitutedPack()){ unsigned PartialDepth, PartialIndex; @@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_half: case TST_float: case TST_double: + case TST_float128: case TST_bool: case TST_decimal32: case TST_decimal64: @@ -739,6 +740,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) { case TST_auto: case TST_auto_type: case TST_decltype_auto: +#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t: +#include "clang/Basic/OpenCLImageTypes.def" case TST_unknown_anytype: case TST_error: break; @@ -996,10 +999,6 @@ ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, BinaryOperatorKind Operator) { // [temp.variadic]p9: // If N is zero for a unary fold-expression, the value of the expression is - // * -> 1 - // + -> int() - // & -> -1 - // | -> int() // && -> true // || -> false // , -> void() @@ -1009,17 +1008,6 @@ ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc, // prevent the result from being a null pointer constant. QualType ScalarType; switch (Operator) { - case BO_Add: - ScalarType = Context.IntTy; - break; - case BO_Mul: - return ActOnIntegerConstant(EllipsisLoc, 1); - case BO_Or: - ScalarType = Context.IntTy; - break; - case BO_And: - return CreateBuiltinUnaryOp(EllipsisLoc, UO_Minus, - ActOnIntegerConstant(EllipsisLoc, 1).get()); case BO_LOr: return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false); case BO_LAnd: diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp index f6ad132cde83..f3747eaa5cb5 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp @@ -11,7 +11,6 @@ // //===----------------------------------------------------------------------===// -#include "clang/Sema/SemaInternal.h" #include "TypeLocBuilder.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -22,7 +21,6 @@ #include "clang/AST/Expr.h" #include "clang/AST/TypeLoc.h" #include "clang/AST/TypeLocVisitor.h" -#include "clang/Lex/Preprocessor.h" #include "clang/Basic/PartialDiagnostic.h" #include "clang/Basic/TargetInfo.h" #include "clang/Lex/Preprocessor.h" @@ -30,9 +28,11 @@ #include "clang/Sema/DelayedDiagnostic.h" #include "clang/Sema/Lookup.h" #include "clang/Sema/ScopeInfo.h" +#include "clang/Sema/SemaInternal.h" #include "clang/Sema/Template.h" #include "llvm/ADT/SmallPtrSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/Support/ErrorHandling.h" using namespace clang; @@ -100,20 +100,27 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr, case AttributeList::AT_ObjCGC: \ case AttributeList::AT_ObjCOwnership -// Function type attributes. -#define FUNCTION_TYPE_ATTRS_CASELIST \ - case AttributeList::AT_NoReturn: \ +// Calling convention attributes. +#define CALLING_CONV_ATTRS_CASELIST \ case AttributeList::AT_CDecl: \ case AttributeList::AT_FastCall: \ case AttributeList::AT_StdCall: \ case AttributeList::AT_ThisCall: \ case AttributeList::AT_Pascal: \ + case AttributeList::AT_SwiftCall: \ case AttributeList::AT_VectorCall: \ case AttributeList::AT_MSABI: \ case AttributeList::AT_SysVABI: \ - case AttributeList::AT_Regparm: \ case AttributeList::AT_Pcs: \ - case AttributeList::AT_IntelOclBicc + case AttributeList::AT_IntelOclBicc: \ + case AttributeList::AT_PreserveMost: \ + case AttributeList::AT_PreserveAll + +// Function type attributes. +#define FUNCTION_TYPE_ATTRS_CASELIST \ + case AttributeList::AT_NoReturn: \ + case AttributeList::AT_Regparm: \ + CALLING_CONV_ATTRS_CASELIST // Microsoft-specific type qualifiers. #define MS_TYPE_ATTRS_CASELIST \ @@ -239,7 +246,7 @@ namespace { savedAttrs.back()->setNext(nullptr); } }; -} +} // end anonymous namespace static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) { attr.setNext(head); @@ -727,6 +734,7 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, // it; they probably didn't mean to specify a redundant qualifier. typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc; for (QualLoc Qual : {QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()), + QualLoc(DeclSpec::TQ_restrict, DS.getRestrictSpecLoc()), QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()), QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())}) { if (!(RemoveTQs & Qual.first)) @@ -743,6 +751,47 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS, } } +/// Return true if this is omitted block return type. Also check type +/// attributes and type qualifiers when returning true. +static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator, + QualType Result) { + if (!isOmittedBlockReturnType(declarator)) + return false; + + // Warn if we see type attributes for omitted return type on a block literal. + AttributeList *&attrs = + declarator.getMutableDeclSpec().getAttributes().getListRef(); + AttributeList *prev = nullptr; + for (AttributeList *cur = attrs; cur; cur = cur->getNext()) { + AttributeList &attr = *cur; + // Skip attributes that were marked to be invalid or non-type + // attributes. + if (attr.isInvalid() || !attr.isTypeAttr()) { + prev = cur; + continue; + } + S.Diag(attr.getLoc(), + diag::warn_block_literal_attributes_on_omitted_return_type) + << attr.getName(); + // Remove cur from the list. + if (prev) { + prev->setNext(cur->getNext()); + prev = cur; + } else { + attrs = cur->getNext(); + } + } + + // Warn if we see type qualifiers for omitted return type on a block literal. + const DeclSpec &DS = declarator.getDeclSpec(); + unsigned TypeQuals = DS.getTypeQualifiers(); + diagnoseAndRemoveTypeQualifiers(S, DS, TypeQuals, Result, (unsigned)-1, + diag::warn_block_literal_qualifiers_on_omitted_return_type); + declarator.getMutableDeclSpec().ClearTypeQualifiers(); + + return true; +} + /// Apply Objective-C type arguments to the given type. static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type, ArrayRef<TypeSourceInfo *> typeArgs, @@ -1171,6 +1220,21 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers( return CreateParsedType(Result, ResultTInfo); } +static StringRef getImageAccessAttrStr(AttributeList *attrs) { + if (attrs) { + + AttributeList *Next; + do { + AttributeList &Attr = *attrs; + Next = Attr.getNext(); + if (Attr.getKind() == AttributeList::AT_OpenCLAccess) { + return Attr.getName()->getName(); + } + } while (Next); + } + return ""; +} + /// \brief Convert the specified declspec to the appropriate type /// object. /// \param state Specifies the declarator containing the declaration specifier @@ -1244,7 +1308,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.getAutoDeductType(); break; } else if (declarator.getContext() == Declarator::LambdaExprContext || - isOmittedBlockReturnType(declarator)) { + checkOmittedBlockReturnType(S, declarator, + Context.DependentTy)) { Result = Context.DependentTy; break; } @@ -1332,7 +1397,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } case DeclSpec::TST_int128: if (!S.Context.getTargetInfo().hasInt128Type()) - S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported); + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__int128"; if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) Result = Context.UnsignedInt128Ty; else @@ -1354,7 +1420,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { declarator.setInvalidType(true); } break; + case DeclSpec::TST_float128: + if (!S.Context.getTargetInfo().hasFloat128Type()) + S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) + << "__float128"; + Result = Context.Float128Ty; + break; case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool + break; case DeclSpec::TST_decimal32: // _Decimal32 case DeclSpec::TST_decimal64: // _Decimal64 case DeclSpec::TST_decimal128: // _Decimal128 @@ -1423,9 +1496,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { declarator.setInvalidType(true); } } else if (!S.getOpenCLOptions().cl_khr_gl_msaa_sharing && - (Result->isImage2dMSAAT() || Result->isImage2dArrayMSAAT() || - Result->isImage2dArrayMSAATDepth() || - Result->isImage2dMSAATDepth())) { + (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); @@ -1539,6 +1621,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { } break; +#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); \ + break; +#include "clang/Basic/OpenCLImageTypes.def" + case DeclSpec::TST_error: Result = Context.IntTy; declarator.setInvalidType(true); @@ -1693,12 +1785,13 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, } QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, - unsigned CVRA, const DeclSpec *DS) { + unsigned CVRAU, const DeclSpec *DS) { if (T.isNull()) return QualType(); - // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic. - unsigned CVR = CVRA & ~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); // C11 6.7.3/5: // If the same qualifier appears more than once in the same @@ -1708,7 +1801,7 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, // It's not specified what happens when the _Atomic qualifier is applied to // a type specified with the _Atomic specifier, but we assume that this // should be treated as if the _Atomic qualifier appeared multiple times. - if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) { + if (CVRAU & DeclSpec::TQ_atomic && !T->isAtomicType()) { // C11 6.7.3/5: // If other qualifiers appear along with the _Atomic qualifier in a // specifier-qualifier-list, the resulting type is the so-qualified @@ -1725,7 +1818,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc, return BuildQualifiedType(T, Loc, Split.Quals); } - return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS); + Qualifiers Q = Qualifiers::fromCVRMask(CVR); + Q.setUnaligned(CVRAU & DeclSpec::TQ_unaligned); + return BuildQualifiedType(T, Loc, Q, DS); } /// \brief Build a paren type including \p T. @@ -1821,7 +1916,7 @@ namespace { /// /// The values of this enum are used in diagnostics. enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference }; -} +} // end anonymous namespace /// Check whether the type T is a qualified function type, and if it is, /// diagnose that it cannot be contained within the given kind of declarator. @@ -1968,10 +2063,10 @@ static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) { } Diagnoser; return S.VerifyIntegerConstantExpression(ArraySize, &SizeVal, Diagnoser, - S.LangOpts.GNUMode).isInvalid(); + S.LangOpts.GNUMode || + S.LangOpts.OpenCL).isInvalid(); } - /// \brief Build an array type. /// /// \param T The type of each element in the array. @@ -2150,15 +2245,8 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, // If this is not C99, extwarn about VLA's and C99 array size modifiers. if (!getLangOpts().C99) { if (T->isVariableArrayType()) { - // Prohibit the use of non-POD types in VLAs. - QualType BaseT = Context.getBaseElementType(T); - if (!T->isDependentType() && isCompleteType(Loc, BaseT) && - !BaseT.isPODType(Context) && !BaseT->isObjCLifetimeType()) { - Diag(Loc, diag::err_vla_non_pod) << BaseT; - return QualType(); - } // Prohibit the use of VLAs during template argument deduction. - else if (isSFINAEContext()) { + if (isSFINAEContext()) { Diag(Loc, diag::err_vla_in_sfinae); return QualType(); } @@ -2176,6 +2264,18 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, Diag(Loc, diag::warn_vla_used); } + // OpenCL v2.0 s6.12.5 - Arrays of blocks are not supported. + // OpenCL v2.0 s6.16.13.1 - Arrays of pipe type are not supported. + // OpenCL v2.0 s6.9.b - Arrays of image/sampler type are not supported. + if (getLangOpts().OpenCL) { + const QualType ArrType = Context.getBaseElementType(T); + if (ArrType->isBlockPointerType() || ArrType->isPipeType() || + ArrType->isSamplerT() || ArrType->isImageType()) { + Diag(Loc, diag::err_opencl_invalid_type_array) << ArrType; + return QualType(); + } + } + return T; } @@ -2184,10 +2284,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM, /// Run the required checks for the extended vector type. QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, SourceLocation AttrLoc) { - // unlike gcc's vector_size attribute, we do not allow vectors to be defined + // Unlike gcc's vector_size attribute, we do not allow vectors to be defined // in conjunction with complex types (pointers, arrays, functions, etc.). - if (!T->isDependentType() && - !T->isIntegerType() && !T->isRealFloatingType()) { + // + // Additionally, OpenCL prohibits vectors of booleans (they're considered a + // reserved data type under OpenCL v2.0 s6.1.4), we don't support selects + // on bitvectors, and we have no well-defined ABI for bitvectors, so vectors + // of bool aren't allowed. + if ((!T->isDependentType() && !T->isIntegerType() && + !T->isRealFloatingType()) || + T->isBooleanType()) { Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T; return QualType(); } @@ -2201,7 +2307,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize, return QualType(); } - // unlike gcc's vector_size attribute, the size is specified as the + // Unlike gcc's vector_size attribute, the size is specified as the // number of elements, not the number of bytes. unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue()); @@ -2247,6 +2353,74 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) { return false; } +/// Check the extended parameter information. Most of the necessary +/// checking should occur when applying the parameter attribute; the +/// only other checks required are positional restrictions. +static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes, + const FunctionProtoType::ExtProtoInfo &EPI, + llvm::function_ref<SourceLocation(unsigned)> getParamLoc) { + assert(EPI.ExtParameterInfos && "shouldn't get here without param infos"); + + bool hasCheckedSwiftCall = false; + auto checkForSwiftCC = [&](unsigned paramIndex) { + // Only do this once. + if (hasCheckedSwiftCall) return; + hasCheckedSwiftCall = true; + if (EPI.ExtInfo.getCC() == CC_Swift) return; + S.Diag(getParamLoc(paramIndex), diag::err_swift_param_attr_not_swiftcall) + << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI()); + }; + + for (size_t paramIndex = 0, numParams = paramTypes.size(); + paramIndex != numParams; ++paramIndex) { + switch (EPI.ExtParameterInfos[paramIndex].getABI()) { + // Nothing interesting to check for orindary-ABI parameters. + case ParameterABI::Ordinary: + continue; + + // swift_indirect_result parameters must be a prefix of the function + // arguments. + case ParameterABI::SwiftIndirectResult: + checkForSwiftCC(paramIndex); + if (paramIndex != 0 && + EPI.ExtParameterInfos[paramIndex - 1].getABI() + != ParameterABI::SwiftIndirectResult) { + S.Diag(getParamLoc(paramIndex), + diag::err_swift_indirect_result_not_first); + } + 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. + 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) { + S.Diag(getParamLoc(paramIndex), + diag::err_swift_error_result_not_after_swift_context); + } + continue; + } + llvm_unreachable("bad ABI kind"); + } +} + QualType Sema::BuildFunctionType(QualType T, MutableArrayRef<QualType> ParamTypes, SourceLocation Loc, DeclarationName Entity, @@ -2271,6 +2445,11 @@ QualType Sema::BuildFunctionType(QualType T, ParamTypes[Idx] = ParamType; } + if (EPI.ExtParameterInfos) { + checkExtParameterInfos(*this, ParamTypes, EPI, + [=](unsigned i) { return Loc; }); + } + if (Invalid) return QualType(); @@ -2477,7 +2656,8 @@ void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, SourceLocation ConstQualLoc, SourceLocation VolatileQualLoc, SourceLocation RestrictQualLoc, - SourceLocation AtomicQualLoc) { + SourceLocation AtomicQualLoc, + SourceLocation UnalignedQualLoc) { if (!Quals) return; @@ -2485,26 +2665,27 @@ void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals, const char *Name; unsigned Mask; SourceLocation Loc; - } const QualKinds[4] = { + } const QualKinds[5] = { { "const", DeclSpec::TQ_const, ConstQualLoc }, { "volatile", DeclSpec::TQ_volatile, VolatileQualLoc }, { "restrict", DeclSpec::TQ_restrict, RestrictQualLoc }, + { "__unaligned", DeclSpec::TQ_unaligned, UnalignedQualLoc }, { "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc } }; SmallString<32> QualStr; unsigned NumQuals = 0; SourceLocation Loc; - FixItHint FixIts[4]; + FixItHint FixIts[5]; // Build a string naming the redundant qualifiers. - for (unsigned I = 0; I != 4; ++I) { - if (Quals & QualKinds[I].Mask) { + for (auto &E : QualKinds) { + if (Quals & E.Mask) { if (!QualStr.empty()) QualStr += ' '; - QualStr += QualKinds[I].Name; + QualStr += E.Name; // If we have a location for the qualifier, offer a fixit. - SourceLocation QualLoc = QualKinds[I].Loc; + SourceLocation QualLoc = E.Loc; if (QualLoc.isValid()) { FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc); if (Loc.isInvalid() || @@ -2550,7 +2731,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, SourceLocation::getFromRawEncoding(PTI.ConstQualLoc), SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc), SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc), - SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc)); + SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc), + SourceLocation::getFromRawEncoding(PTI.UnalignedQualLoc)); return; } @@ -2586,7 +2768,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy, D.getDeclSpec().getConstSpecLoc(), D.getDeclSpec().getVolatileSpecLoc(), D.getDeclSpec().getRestrictSpecLoc(), - D.getDeclSpec().getAtomicSpecLoc()); + D.getDeclSpec().getAtomicSpecLoc(), + D.getDeclSpec().getUnalignedSpecLoc()); } static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, @@ -2700,6 +2883,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case Declarator::FileContext: case Declarator::BlockContext: case Declarator::ForContext: + case Declarator::InitStmtContext: case Declarator::ConditionContext: break; case Declarator::CXXNewContext: @@ -2785,6 +2969,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state, case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: + case Declarator::InitStmtContext: case Declarator::BlockLiteralContext: case Declarator::LambdaExprContext: // C++11 [dcl.type]p3: @@ -2940,6 +3125,26 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, unsigned ChunkIndex) { assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function); + // Check for an explicit CC attribute. + for (auto Attr = FTI.AttrList; Attr; Attr = Attr->getNext()) { + switch (Attr->getKind()) { + CALLING_CONV_ATTRS_CASELIST: { + // Ignore attributes that don't validate or can't apply to the + // function type. We'll diagnose the failure to apply them in + // handleFunctionTypeAttr. + CallingConv CC; + if (!S.CheckCallingConvAttr(*Attr, CC) && + (!FTI.isVariadic || supportsVariadicCall(CC))) { + return CC; + } + break; + } + + default: + break; + } + } + bool IsCXXInstanceMethod = false; if (S.getLangOpts().CPlusPlus) { @@ -2979,15 +3184,19 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D, CallingConv CC = S.Context.getDefaultCallingConvention(FTI.isVariadic, IsCXXInstanceMethod); - // Attribute AT_OpenCLKernel affects the calling convention only on - // the SPIR target, hence it cannot be treated as a calling + // Attribute AT_OpenCLKernel affects the calling convention for SPIR + // and AMDGPU targets, hence it cannot be treated as a calling // convention attribute. This is the simplest place to infer - // "spir_kernel" for OpenCL kernels on SPIR. - if (CC == CC_SpirFunction) { + // calling convention for OpenCL kernels. + if (S.getLangOpts().OpenCL) { for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList(); Attr; Attr = Attr->getNext()) { if (Attr->getKind() == AttributeList::AT_OpenCLKernel) { - CC = CC_SpirKernel; + llvm::Triple::ArchType arch = S.Context.getTargetInfo().getTriple().getArch(); + if (arch == llvm::Triple::spir || arch == llvm::Triple::spir64 || + arch == llvm::Triple::amdgcn) { + CC = CC_OpenCLKernel; + } break; } } @@ -3004,7 +3213,7 @@ namespace { BlockPointer, MemberPointer, }; -} +} // end anonymous namespace IdentifierInfo *Sema::getNullabilityKeyword(NullabilityKind nullability) { switch (nullability) { @@ -3064,7 +3273,7 @@ namespace { // NSError** NSErrorPointerPointer, }; -} +} // end anonymous namespace /// Classify the given declarator, whose type-specified is \c type, based on /// what kind of pointer it refers to. @@ -3192,7 +3401,6 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S, break; } while (true); - switch (numNormalPointers) { case 0: return PointerDeclaratorKind::NonPointer; @@ -3509,6 +3717,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::CXXCatchContext: case Declarator::CXXNewContext: case Declarator::ForContext: + case Declarator::InitStmtContext: case Declarator::LambdaExprContext: case Declarator::LambdaExprParameterContext: case Declarator::ObjCCatchContext: @@ -3609,15 +3818,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case DeclaratorChunk::BlockPointer: // If blocks are disabled, emit an error. if (!LangOpts.Blocks) - S.Diag(DeclType.Loc, diag::err_blocks_disable); + S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL; // Handle pointer nullability. inferPointerNullability(SimplePointerKind::BlockPointer, DeclType.Loc, DeclType.getAttrListRef()); T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name); - if (DeclType.Cls.TypeQuals) + if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) { + // OpenCL v2.0, s6.12.5 - Block variable declarations are implicitly + // qualified with const. + if (LangOpts.OpenCL) + DeclType.Cls.TypeQuals |= DeclSpec::TQ_const; T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals); + } break; case DeclaratorChunk::Pointer: // Verify that we're not building a pointer to pointer to function with @@ -3638,10 +3852,21 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); break; } + + // OpenCL v2.0 s6.9b - Pointer to image/sampler cannot be used. + // OpenCL v2.0 s6.13.16.1 - Pointer to pipe cannot be used. + // OpenCL v2.0 s6.12.5 - Pointers to Blocks are not allowed. + if (LangOpts.OpenCL) { + if (T->isImageType() || T->isSamplerT() || T->isPipeType() || + T->isBlockPointerType()) { + S.Diag(D.getIdentifierLoc(), diag::err_opencl_pointer_to_type) << T; + D.setInvalidType(true); + } + } + T = S.BuildPointerType(T, DeclType.Loc, Name); if (DeclType.Ptr.TypeQuals) T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals); - break; case DeclaratorChunk::Reference: { // Verify that we're not building a reference to pointer to function with @@ -3808,7 +4033,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, if (T->isHalfType()) { if (S.getLangOpts().OpenCL) { if (!S.getOpenCLOptions().cl_khr_fp16) { - S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T; + S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return) + << T << 0 /*pointer hint*/; D.setInvalidType(true); } } else if (!S.getLangOpts().HalfArgsAndReturns) { @@ -3818,6 +4044,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } + // 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); + } + // Methods cannot return interface types. All ObjC objects are // passed by reference. if (T->isObjCObjectType()) { @@ -3967,9 +4202,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, SmallVector<QualType, 16> ParamTys; ParamTys.reserve(FTI.NumParams); - SmallVector<bool, 16> ConsumedParameters; - ConsumedParameters.reserve(FTI.NumParams); - bool HasAnyConsumedParameters = false; + SmallVector<FunctionProtoType::ExtParameterInfo, 16> + ExtParameterInfos(FTI.NumParams); + bool HasAnyInterestingExtParameterInfos = false; for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) { ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param); @@ -4027,17 +4262,25 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, } } - if (LangOpts.ObjCAutoRefCount) { - bool Consumed = Param->hasAttr<NSConsumedAttr>(); - ConsumedParameters.push_back(Consumed); - HasAnyConsumedParameters |= Consumed; + if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) { + ExtParameterInfos[i] = ExtParameterInfos[i].withIsConsumed(true); + HasAnyInterestingExtParameterInfos = true; + } + + if (auto attr = Param->getAttr<ParameterABIAttr>()) { + ExtParameterInfos[i] = + ExtParameterInfos[i].withABI(attr->getABI()); + HasAnyInterestingExtParameterInfos = true; } ParamTys.push_back(ParamTy); } - if (HasAnyConsumedParameters) - EPI.ConsumedParameters = ConsumedParameters.data(); + if (HasAnyInterestingExtParameterInfos) { + EPI.ExtParameterInfos = ExtParameterInfos.data(); + checkExtParameterInfos(S, ParamTys, EPI, + [&](unsigned i) { return FTI.Params[i].Param->getLocation(); }); + } SmallVector<QualType, 4> Exceptions; SmallVector<ParsedType, 2> DynamicExceptions; @@ -4068,7 +4311,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, T = Context.getFunctionType(T, ParamTys, EPI); } - break; } case DeclaratorChunk::MemberPointer: { @@ -4306,6 +4548,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state, case Declarator::MemberContext: case Declarator::BlockContext: case Declarator::ForContext: + case Declarator::InitStmtContext: case Declarator::ConditionContext: case Declarator::CXXCatchContext: case Declarator::ObjCCatchContext: @@ -4497,6 +4740,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_ThisCall; case AttributedType::attr_pascal: return AttributeList::AT_Pascal; + case AttributedType::attr_swiftcall: + return AttributeList::AT_SwiftCall; case AttributedType::attr_vectorcall: return AttributeList::AT_VectorCall; case AttributedType::attr_pcs: @@ -4508,6 +4753,10 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) { return AttributeList::AT_MSABI; case AttributedType::attr_sysv_abi: return AttributeList::AT_SysVABI; + case AttributedType::attr_preserve_most: + return AttributeList::AT_PreserveMost; + case AttributedType::attr_preserve_all: + return AttributeList::AT_PreserveAll; case AttributedType::attr_ptr32: return AttributeList::AT_Ptr32; case AttributedType::attr_ptr64: @@ -4725,7 +4974,7 @@ namespace { void VisitPipeTypeLoc(PipeTypeLoc TL) { TL.setKWLoc(DS.getTypeSpecTypeLoc()); - TypeSourceInfo *TInfo = 0; + TypeSourceInfo *TInfo = nullptr; Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo); TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc()); } @@ -4859,7 +5108,7 @@ namespace { llvm_unreachable("unsupported TypeLoc kind in declarator!"); } }; -} +} // end anonymous namespace static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) { SourceLocation Loc; @@ -4995,7 +5244,6 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) { return CreateParsedType(T, TInfo); } - //===----------------------------------------------------------------------===// // Type Attribute Processing //===----------------------------------------------------------------------===// @@ -5194,11 +5442,13 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state, } // Otherwise, if the qualifiers actually conflict, pull sugar off - // until we reach a type that is directly qualified. + // and remove the ObjCLifetime qualifiers. if (previousLifetime != lifetime) { - // This should always terminate: the canonical type is - // qualified, so some bit of sugar must be hiding it. - while (!underlyingType.Quals.hasObjCLifetime()) { + // It's possible to have multiple local ObjCLifetime qualifiers. We + // can't stop after we reach a type that is directly qualified. + const Type *prevTy = nullptr; + while (!prevTy || prevTy != underlyingType.Ty) { + prevTy = underlyingType.Ty; underlyingType = underlyingType.getSingleStepDesugaredType(); } underlyingType.Quals.removeObjCLifetime(); @@ -5369,6 +5619,7 @@ namespace { struct FunctionTypeUnwrapper { enum WrapKind { Desugar, + Attributed, Parens, Pointer, BlockPointer, @@ -5401,6 +5652,9 @@ namespace { } else if (isa<ReferenceType>(Ty)) { T = cast<ReferenceType>(Ty)->getPointeeType(); Stack.push_back(Reference); + } else if (isa<AttributedType>(Ty)) { + T = cast<AttributedType>(Ty)->getEquivalentType(); + Stack.push_back(Attributed); } else { const Type *DTy = Ty->getUnqualifiedDesugaredType(); if (Ty == DTy) { @@ -5449,6 +5703,9 @@ namespace { // information. return wrap(C, Old->getUnqualifiedDesugaredType(), I); + case Attributed: + return wrap(C, cast<AttributedType>(Old)->getEquivalentType(), I); + case Parens: { QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I); return C.getParenType(New); @@ -5483,7 +5740,7 @@ namespace { llvm_unreachable("unknown wrapping kind"); } }; -} +} // end anonymous namespace static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, AttributeList &Attr, @@ -5672,10 +5929,11 @@ bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) { // Rebuild the "equivalent" type, which pushes __kindof down into // the object type. - QualType equivType = Context.getObjCObjectType(objType->getBaseType(), - objType->getTypeArgsAsWritten(), - objType->getProtocols(), - /*isKindOf=*/true); + // There is no need to apply kindof on an unqualified id type. + QualType equivType = Context.getObjCObjectType( + objType->getBaseType(), objType->getTypeArgsAsWritten(), + objType->getProtocols(), + /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true); // If we started with an object pointer type, rebuild it. if (ptrType) { @@ -5814,6 +6072,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { return AttributedType::attr_thiscall; case AttributeList::AT_Pascal: return AttributedType::attr_pascal; + case AttributeList::AT_SwiftCall: + return AttributedType::attr_swiftcall; case AttributeList::AT_VectorCall: return AttributedType::attr_vectorcall; case AttributeList::AT_Pcs: { @@ -5835,6 +6095,10 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) { return AttributedType::attr_ms_abi; case AttributeList::AT_SysVABI: return AttributedType::attr_sysv_abi; + case AttributeList::AT_PreserveMost: + return AttributedType::attr_preserve_most; + case AttributeList::AT_PreserveAll: + return AttributedType::attr_preserve_all; } llvm_unreachable("unexpected attribute kind!"); } @@ -5930,18 +6194,28 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, } } - // Diagnose use of callee-cleanup calling convention on variadic functions. + // Diagnose use of variadic functions with calling conventions that + // don't support them (e.g. because they're callee-cleanup). + // We delay warning about this on unprototyped function declarations + // until after redeclaration checking, just in case we pick up a + // prototype that way. And apparently we also "delay" warning about + // unprototyped function types in general, despite not necessarily having + // much ability to diagnose it later. if (!supportsVariadicCall(CC)) { const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn); if (FnP && FnP->isVariadic()) { unsigned DiagID = diag::err_cconv_varargs; + // stdcall and fastcall are ignored with a warning for GCC and MS // compatibility. - if (CC == CC_X86StdCall || CC == CC_X86FastCall) + bool IsInvalid = true; + if (CC == CC_X86StdCall || CC == CC_X86FastCall) { DiagID = diag::warn_cconv_varargs; + IsInvalid = false; + } S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC); - attr.setInvalid(); + if (IsInvalid) attr.setInvalid(); return true; } } @@ -5957,9 +6231,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, // Modify the CC from the wrapped function type, wrap it all back, and then // wrap the whole thing in an AttributedType as written. The modified type // might have a different CC if we ignored the attribute. - FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC); - QualType Equivalent = + QualType Equivalent; + if (CCOld == CC) { + Equivalent = type; + } else { + auto EI = unwrapped.get()->getExtInfo().withCallingConv(CC); + Equivalent = unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI)); + } type = S.Context.getAttributedType(CCAttrKind, type, Equivalent); return true; } @@ -6217,6 +6496,36 @@ static void HandleNeonVectorTypeAttr(QualType& CurType, CurType = S.Context.getVectorType(CurType, numElts, VecKind); } +/// Handle OpenCL Access Qualifier Attribute. +static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr, + Sema &S) { + // OpenCL v2.0 s6.6 - Access qualifier can be used only for image and pipe type. + if (!(CurType->isImageType() || CurType->isPipeType())) { + S.Diag(Attr.getLoc(), diag::err_opencl_invalid_access_qualifier); + Attr.setInvalid(); + return; + } + + if (const TypedefType* TypedefTy = CurType->getAs<TypedefType>()) { + QualType PointeeTy = TypedefTy->desugar(); + S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers); + + std::string PrevAccessQual; + switch (cast<BuiltinType>(PointeeTy.getTypePtr())->getKind()) { + #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ + case BuiltinType::Id: \ + PrevAccessQual = #Access; \ + break; + #include "clang/Basic/OpenCLImageTypes.def" + default: + assert(0 && "Unable to find corresponding image type."); + } + + S.Diag(TypedefTy->getDecl()->getLocStart(), + diag::note_opencl_typedef_access_qualifier) << PrevAccessQual; + } +} + static void processTypeAttrs(TypeProcessingState &state, QualType &type, TypeAttrLocation TAL, AttributeList *attrs) { // Scan through and apply attributes to this type where it makes sense. Some @@ -6312,9 +6621,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, VectorType::NeonPolyVector); attr.setUsedAsTypeAttr(); break; - case AttributeList::AT_OpenCLImageAccess: - // FIXME: there should be some type checking happening here, I would - // imagine, but the original handler's checking was entirely superfluous. + case AttributeList::AT_OpenCLAccess: + HandleOpenCLAccessAttr(type, attr, state.getSema()); attr.setUsedAsTypeAttr(); break; @@ -6554,8 +6862,8 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested, RD = Pattern; D = RD->getDefinition(); } else if (auto *ED = dyn_cast<EnumDecl>(D)) { - while (auto *NewED = ED->getInstantiatedFromMemberEnum()) - ED = NewED; + if (auto *Pattern = ED->getTemplateInstantiationPattern()) + ED = Pattern; if (OnlyNeedComplete && ED->isFixed()) { // If the enum has a fixed underlying type, and we're only looking for a // complete type (not a definition), any visible declaration of it will @@ -6616,6 +6924,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) { S.ImplicitMSInheritanceAttrLoc.isValid() ? S.ImplicitMSInheritanceAttrLoc : RD->getSourceRange())); + S.Consumer.AssignInheritanceModel(RD); } } @@ -6641,9 +6950,16 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } } - // If we have a complete type, we're done. NamedDecl *Def = nullptr; - if (!T->isIncompleteType(&Def)) { + bool Incomplete = T->isIncompleteType(&Def); + + // Check that any necessary explicit specializations are visible. For an + // enum, we just need the declaration, so don't check this. + if (Def && !isa<EnumDecl>(Def)) + checkSpecializationVisibility(Loc, Def); + + // If we have a complete type, we're done. + if (!Incomplete) { // If we know about the definition but it is not visible, complain. NamedDecl *SuggestedDef = nullptr; if (Def && @@ -6652,7 +6968,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, // definition visible. bool TreatAsComplete = Diagnoser && !isSFINAEContext(); if (Diagnoser) - diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true, + diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition, /*Recover*/TreatAsComplete); return !TreatAsComplete; } @@ -6745,15 +7061,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T, } } - if (!Diagnoser) - return true; + // FIXME: If we didn't instantiate a definition because of an explicit + // specialization declaration, check that it's visible. - // We have an incomplete type. Produce a diagnostic. - if (Ident___float128 && - T == Context.getTypeDeclType(Context.getFloat128StubType())) { - Diag(Loc, diag::err_typecheck_decl_incomplete_type___float128); + if (!Diagnoser) return true; - } Diagnoser->diagnose(*this, Loc, T); diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h index 935304fe4076..36859f61d387 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h +++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h @@ -410,6 +410,14 @@ public: return D; } + /// \brief Transform the specified condition. + /// + /// By default, this transforms the variable and expression and rebuilds + /// the condition. + Sema::ConditionResult TransformCondition(SourceLocation Loc, VarDecl *Var, + Expr *Expr, + Sema::ConditionKind Kind); + /// \brief Transform the attributes associated with the given declaration and /// place them on the new declaration. /// @@ -604,11 +612,12 @@ public: /// variables vector are acceptable. /// /// Return true on error. - bool TransformFunctionTypeParams(SourceLocation Loc, - ParmVarDecl **Params, unsigned NumParams, - const QualType *ParamTypes, - SmallVectorImpl<QualType> &PTypes, - SmallVectorImpl<ParmVarDecl*> *PVars); + bool TransformFunctionTypeParams( + SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, + const QualType *ParamTypes, + const FunctionProtoType::ExtParameterInfo *ParamInfos, + SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars, + Sema::ExtParameterInfoBuilder &PInfos); /// \brief Transforms a single function-type parameter. Return null /// on error. @@ -1164,20 +1173,20 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Then, + StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr, + Sema::ConditionResult Cond, Stmt *Init, Stmt *Then, SourceLocation ElseLoc, Stmt *Else) { - return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else); + return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then, + ElseLoc, Else); } /// \brief Start building a new switch statement. /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, - Expr *Cond, VarDecl *CondVar) { - return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond, - CondVar); + StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init, + Sema::ConditionResult Cond) { + return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond); } /// \brief Attach the body to the switch statement. @@ -1193,9 +1202,9 @@ public: /// /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. - StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond, - VarDecl *CondVar, Stmt *Body) { - return getSema().ActOnWhileStmt(WhileLoc, Cond, CondVar, Body); + StmtResult RebuildWhileStmt(SourceLocation WhileLoc, + Sema::ConditionResult Cond, Stmt *Body) { + return getSema().ActOnWhileStmt(WhileLoc, Cond, Body); } /// \brief Build a new do-while statement. @@ -1214,11 +1223,11 @@ public: /// By default, performs semantic analysis to build the new statement. /// Subclasses may override this routine to provide different behavior. StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc, - Stmt *Init, Sema::FullExprArg Cond, - VarDecl *CondVar, Sema::FullExprArg Inc, - SourceLocation RParenLoc, Stmt *Body) { + Stmt *Init, Sema::ConditionResult Cond, + Sema::FullExprArg Inc, SourceLocation RParenLoc, + Stmt *Body) { return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond, - CondVar, Inc, RParenLoc, Body); + Inc, RParenLoc, Body); } /// \brief Build a new goto statement. @@ -1559,10 +1568,11 @@ public: SourceLocation ColonLoc, SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec, - const DeclarationNameInfo &ReductionId) { + const DeclarationNameInfo &ReductionId, + ArrayRef<Expr *> UnresolvedReductions) { return getSema().ActOnOpenMPReductionClause( VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec, - ReductionId); + ReductionId, UnresolvedReductions); } /// \brief Build a new OpenMP 'linear' clause. @@ -1658,14 +1668,15 @@ public: /// /// By default, performs semantic analysis to build the new OpenMP clause. /// Subclasses may override this routine to provide different behavior. - OMPClause *RebuildOMPMapClause( - OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType, - SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList, - SourceLocation StartLoc, SourceLocation LParenLoc, - SourceLocation EndLoc) { - return getSema().ActOnOpenMPMapClause(MapTypeModifier, MapType, MapLoc, - ColonLoc, VarList,StartLoc, - LParenLoc, EndLoc); + OMPClause * + RebuildOMPMapClause(OpenMPMapClauseKind MapTypeModifier, + OpenMPMapClauseKind MapType, bool IsMapTypeImplicit, + SourceLocation MapLoc, SourceLocation ColonLoc, + ArrayRef<Expr *> VarList, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPMapClause(MapTypeModifier, MapType, + IsMapTypeImplicit, MapLoc, ColonLoc, + VarList, StartLoc, LParenLoc, EndLoc); } /// \brief Build a new OpenMP 'num_teams' clause. @@ -1734,6 +1745,66 @@ public: return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc); } + /// \brief Build a new OpenMP 'dist_schedule' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause * + RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind, + Expr *ChunkSize, SourceLocation StartLoc, + SourceLocation LParenLoc, SourceLocation KindLoc, + SourceLocation CommaLoc, SourceLocation EndLoc) { + return getSema().ActOnOpenMPDistScheduleClause( + Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'to' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPToClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc); + } + + /// \brief Build a new OpenMP 'from' clause. + /// + /// By default, performs semantic analysis to build the new statement. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPFromClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'use_device_ptr' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPUseDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + + /// Build a new OpenMP 'is_device_ptr' clause. + /// + /// By default, performs semantic analysis to build the new OpenMP clause. + /// Subclasses may override this routine to provide different behavior. + OMPClause *RebuildOMPIsDevicePtrClause(ArrayRef<Expr *> VarList, + SourceLocation StartLoc, + SourceLocation LParenLoc, + SourceLocation EndLoc) { + return getSema().ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, + EndLoc); + } + /// \brief Rebuild the operand to an Objective-C \@synchronized statement. /// /// By default, performs semantic analysis to build the new statement. @@ -1823,7 +1894,7 @@ public: StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc, SourceLocation ColonLoc, - Stmt *Range, Stmt *BeginEnd, + Stmt *Range, Stmt *Begin, Stmt *End, Expr *Cond, Expr *Inc, Stmt *LoopVar, SourceLocation RParenLoc) { @@ -1845,7 +1916,7 @@ public: } return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, - Range, BeginEnd, + Range, Begin, End, Cond, Inc, LoopVar, RParenLoc, Sema::BFRK_Rebuild); } @@ -2634,7 +2705,8 @@ public: ConvertedArgs)) return ExprError(); - return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable, + return getSema().BuildCXXConstructExpr(Loc, T, Constructor, + IsElidable, ConvertedArgs, HadMultipleCandidates, ListInitialization, @@ -2643,6 +2715,16 @@ public: ParenRange); } + /// \brief Build a new implicit construction via inherited constructor + /// expression. + ExprResult RebuildCXXInheritedCtorInitExpr(QualType T, SourceLocation Loc, + CXXConstructorDecl *Constructor, + bool ConstructsVBase, + bool InheritedFromVBase) { + return new (getSema().Context) CXXInheritedCtorInitExpr( + Loc, T, Constructor, ConstructsVBase, InheritedFromVBase); + } + /// \brief Build a new object-construction expression. /// /// By default, performs semantic analysis to build the new expression. @@ -3269,8 +3351,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs, if (Out.isInvalid()) return true; - // FIXME: Can this happen? We should not try to expand the pack - // in this case. if (Out.get()->containsUnexpandedParameterPack()) { Out = getDerived().RebuildPackExpansion( Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions); @@ -3316,6 +3396,31 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs, return false; } +template <typename Derived> +Sema::ConditionResult TreeTransform<Derived>::TransformCondition( + SourceLocation Loc, VarDecl *Var, Expr *Expr, Sema::ConditionKind Kind) { + if (Var) { + VarDecl *ConditionVar = cast_or_null<VarDecl>( + getDerived().TransformDefinition(Var->getLocation(), Var)); + + if (!ConditionVar) + return Sema::ConditionError(); + + return getSema().ActOnConditionVariable(ConditionVar, Loc, Kind); + } + + if (Expr) { + ExprResult CondExpr = getDerived().TransformExpr(Expr); + + if (CondExpr.isInvalid()) + return Sema::ConditionError(); + + return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind); + } + + return Sema::ConditionResult(); +} + template<typename Derived> NestedNameSpecifierLoc TreeTransform<Derived>::TransformNestedNameSpecifierLoc( @@ -4590,15 +4695,17 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam( return newParm; } -template<typename Derived> -bool TreeTransform<Derived>:: - TransformFunctionTypeParams(SourceLocation Loc, - ParmVarDecl **Params, unsigned NumParams, - const QualType *ParamTypes, - SmallVectorImpl<QualType> &OutParamTypes, - SmallVectorImpl<ParmVarDecl*> *PVars) { +template <typename Derived> +bool TreeTransform<Derived>::TransformFunctionTypeParams( + SourceLocation Loc, ArrayRef<ParmVarDecl *> Params, + const QualType *ParamTypes, + const FunctionProtoType::ExtParameterInfo *ParamInfos, + SmallVectorImpl<QualType> &OutParamTypes, + SmallVectorImpl<ParmVarDecl *> *PVars, + Sema::ExtParameterInfoBuilder &PInfos) { int indexAdjustment = 0; + unsigned NumParams = Params.size(); for (unsigned i = 0; i != NumParams; ++i) { if (ParmVarDecl *OldParm = Params[i]) { assert(OldParm->getFunctionScopeIndex() == i); @@ -4645,6 +4752,8 @@ bool TreeTransform<Derived>:: if (!NewParm) return true; + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); @@ -4662,6 +4771,8 @@ bool TreeTransform<Derived>:: if (!NewParm) return true; + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); @@ -4692,6 +4803,8 @@ bool TreeTransform<Derived>:: if (!NewParm) return true; + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewParm->getType()); if (PVars) PVars->push_back(NewParm); @@ -4731,6 +4844,16 @@ bool TreeTransform<Derived>:: if (NewType.isNull()) return true; + if (NewType->containsUnexpandedParameterPack()) { + NewType = + getSema().getASTContext().getPackExpansionType(NewType, None); + + if (NewType.isNull()) + return true; + } + + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); @@ -4748,6 +4871,8 @@ bool TreeTransform<Derived>:: if (NewType.isNull()) return true; + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); @@ -4770,6 +4895,8 @@ bool TreeTransform<Derived>:: NewType = getSema().Context.getPackExpansionType(NewType, NumExpansions); + if (ParamInfos) + PInfos.set(OutParamTypes.size(), ParamInfos[i]); OutParamTypes.push_back(NewType); if (PVars) PVars->push_back(nullptr); @@ -4804,6 +4931,7 @@ template<typename Derived> template<typename Fn> QualType TreeTransform<Derived>::TransformFunctionProtoType( TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext, unsigned ThisTypeQuals, Fn TransformExceptionSpec) { + // Transform the parameters and return type. // // We are required to instantiate the params and return type in source order. @@ -4813,14 +4941,17 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( // SmallVector<QualType, 4> ParamTypes; SmallVector<ParmVarDecl*, 4> ParamDecls; + Sema::ExtParameterInfoBuilder ExtParamInfos; const FunctionProtoType *T = TL.getTypePtr(); QualType ResultType; if (T->hasTrailingReturn()) { if (getDerived().TransformFunctionTypeParams( - TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(), - TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls)) + TL.getBeginLoc(), TL.getParams(), + TL.getTypePtr()->param_type_begin(), + T->getExtParameterInfosOrNull(), + ParamTypes, &ParamDecls, ExtParamInfos)) return QualType(); { @@ -4843,8 +4974,10 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( return QualType(); if (getDerived().TransformFunctionTypeParams( - TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(), - TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls)) + TL.getBeginLoc(), TL.getParams(), + TL.getTypePtr()->param_type_begin(), + T->getExtParameterInfosOrNull(), + ParamTypes, &ParamDecls, ExtParamInfos)) return QualType(); } @@ -4854,8 +4987,19 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType( if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged)) return QualType(); - // FIXME: Need to transform ConsumedParameters for variadic template - // expansion. + // Handle extended parameter information. + if (auto NewExtParamInfos = + ExtParamInfos.getPointerOrNull(ParamTypes.size())) { + if (!EPI.ExtParameterInfos || + llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams()) + != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) { + EPIChanged = true; + } + EPI.ExtParameterInfos = NewExtParamInfos; + } else if (EPI.ExtParameterInfos) { + EPIChanged = true; + EPI.ExtParameterInfos = nullptr; + } QualType Result = TL.getType(); if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() || @@ -4890,8 +5034,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec( if (NoexceptExpr.isInvalid()) return true; - NoexceptExpr = getSema().CheckBooleanCondition( - NoexceptExpr.get(), NoexceptExpr.get()->getLocStart()); + // FIXME: This is bogus, a noexcept expression is not a condition. + NoexceptExpr = getSema().CheckBooleanCondition(Loc, NoexceptExpr.get()); if (NoexceptExpr.isInvalid()) return true; @@ -5918,7 +6062,6 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB, } ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result); - assert(TL.hasBaseTypeAsWritten() && "Can't be dependent"); NewT.setHasBaseTypeAsWritten(true); NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc()); for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i) @@ -6123,85 +6266,73 @@ StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) { template<typename Derived> StmtResult TreeTransform<Derived>::TransformIfStmt(IfStmt *S) { - // Transform the condition - ExprResult Cond; - VarDecl *ConditionVar = nullptr; - if (S->getConditionVariable()) { - ConditionVar - = cast_or_null<VarDecl>( - getDerived().TransformDefinition( - S->getConditionVariable()->getLocation(), - S->getConditionVariable())); - if (!ConditionVar) - return StmtError(); - } else { - Cond = getDerived().TransformExpr(S->getCond()); - - if (Cond.isInvalid()) - return StmtError(); - - // Convert the condition to a boolean value. - if (S->getCond()) { - ExprResult CondE = getSema().ActOnBooleanCondition(nullptr, S->getIfLoc(), - Cond.get()); - if (CondE.isInvalid()) - return StmtError(); - - Cond = CondE.get(); - } - } + // Transform the initialization statement + StmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) + return StmtError(); - Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get(), S->getIfLoc())); - if (!S->getConditionVariable() && S->getCond() && !FullCond.get()) + // Transform the condition + Sema::ConditionResult Cond = getDerived().TransformCondition( + S->getIfLoc(), S->getConditionVariable(), S->getCond(), + S->isConstexpr() ? Sema::ConditionKind::ConstexprIf + : Sema::ConditionKind::Boolean); + if (Cond.isInvalid()) return StmtError(); + // If this is a constexpr if, determine which arm we should instantiate. + llvm::Optional<bool> ConstexprConditionValue; + if (S->isConstexpr()) + ConstexprConditionValue = Cond.getKnownValue(); + // Transform the "then" branch. - StmtResult Then = getDerived().TransformStmt(S->getThen()); - if (Then.isInvalid()) - return StmtError(); + StmtResult Then; + if (!ConstexprConditionValue || *ConstexprConditionValue) { + Then = getDerived().TransformStmt(S->getThen()); + if (Then.isInvalid()) + return StmtError(); + } else { + Then = new (getSema().Context) NullStmt(S->getThen()->getLocStart()); + } // Transform the "else" branch. - StmtResult Else = getDerived().TransformStmt(S->getElse()); - if (Else.isInvalid()) - return StmtError(); + StmtResult Else; + if (!ConstexprConditionValue || !*ConstexprConditionValue) { + Else = getDerived().TransformStmt(S->getElse()); + if (Else.isInvalid()) + return StmtError(); + } if (!getDerived().AlwaysRebuild() && - FullCond.get() == S->getCond() && - ConditionVar == S->getConditionVariable() && + Init.get() == S->getInit() && + Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Then.get() == S->getThen() && Else.get() == S->getElse()) return S; - return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar, - Then.get(), - S->getElseLoc(), Else.get()); + return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond, + Init.get(), Then.get(), S->getElseLoc(), + Else.get()); } template<typename Derived> StmtResult TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) { - // Transform the condition. - ExprResult Cond; - VarDecl *ConditionVar = nullptr; - if (S->getConditionVariable()) { - ConditionVar - = cast_or_null<VarDecl>( - getDerived().TransformDefinition( - S->getConditionVariable()->getLocation(), - S->getConditionVariable())); - if (!ConditionVar) - return StmtError(); - } else { - Cond = getDerived().TransformExpr(S->getCond()); + // Transform the initialization statement + StmtResult Init = getDerived().TransformStmt(S->getInit()); + if (Init.isInvalid()) + return StmtError(); - if (Cond.isInvalid()) - return StmtError(); - } + // Transform the condition. + Sema::ConditionResult Cond = getDerived().TransformCondition( + S->getSwitchLoc(), S->getConditionVariable(), S->getCond(), + Sema::ConditionKind::Switch); + if (Cond.isInvalid()) + return StmtError(); // Rebuild the switch statement. StmtResult Switch - = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond.get(), - ConditionVar); + = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), + S->getInit(), Cond); if (Switch.isInvalid()) return StmtError(); @@ -6219,36 +6350,10 @@ template<typename Derived> StmtResult TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { // Transform the condition - ExprResult Cond; - VarDecl *ConditionVar = nullptr; - if (S->getConditionVariable()) { - ConditionVar - = cast_or_null<VarDecl>( - getDerived().TransformDefinition( - S->getConditionVariable()->getLocation(), - S->getConditionVariable())); - if (!ConditionVar) - return StmtError(); - } else { - Cond = getDerived().TransformExpr(S->getCond()); - - if (Cond.isInvalid()) - return StmtError(); - - if (S->getCond()) { - // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(nullptr, - S->getWhileLoc(), - Cond.get()); - if (CondE.isInvalid()) - return StmtError(); - Cond = CondE; - } - } - - Sema::FullExprArg FullCond( - getSema().MakeFullExpr(Cond.get(), S->getWhileLoc())); - if (!S->getConditionVariable() && S->getCond() && !FullCond.get()) + Sema::ConditionResult Cond = getDerived().TransformCondition( + S->getWhileLoc(), S->getConditionVariable(), S->getCond(), + Sema::ConditionKind::Boolean); + if (Cond.isInvalid()) return StmtError(); // Transform the body @@ -6257,13 +6362,11 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) { return StmtError(); if (!getDerived().AlwaysRebuild() && - FullCond.get() == S->getCond() && - ConditionVar == S->getConditionVariable() && + Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Body.get() == S->getBody()) return Owned(S); - return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond, - ConditionVar, Body.get()); + return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get()); } template<typename Derived> @@ -6303,37 +6406,10 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { getSema().ActOnOpenMPLoopInitialization(S->getForLoc(), Init.get()); // Transform the condition - ExprResult Cond; - VarDecl *ConditionVar = nullptr; - if (S->getConditionVariable()) { - ConditionVar - = cast_or_null<VarDecl>( - getDerived().TransformDefinition( - S->getConditionVariable()->getLocation(), - S->getConditionVariable())); - if (!ConditionVar) - return StmtError(); - } else { - Cond = getDerived().TransformExpr(S->getCond()); - - if (Cond.isInvalid()) - return StmtError(); - - if (S->getCond()) { - // Convert the condition to a boolean value. - ExprResult CondE = getSema().ActOnBooleanCondition(nullptr, - S->getForLoc(), - Cond.get()); - if (CondE.isInvalid()) - return StmtError(); - - Cond = CondE.get(); - } - } - - Sema::FullExprArg FullCond( - getSema().MakeFullExpr(Cond.get(), S->getForLoc())); - if (!S->getConditionVariable() && S->getCond() && !FullCond.get()) + Sema::ConditionResult Cond = getDerived().TransformCondition( + S->getForLoc(), S->getConditionVariable(), S->getCond(), + Sema::ConditionKind::Boolean); + if (Cond.isInvalid()) return StmtError(); // Transform the increment @@ -6352,14 +6428,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) { if (!getDerived().AlwaysRebuild() && Init.get() == S->getInit() && - FullCond.get() == S->getCond() && + Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) && Inc.get() == S->getInc() && Body.get() == S->getBody()) return S; return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(), - Init.get(), FullCond, ConditionVar, - FullInc, S->getRParenLoc(), Body.get()); + Init.get(), Cond, FullInc, + S->getRParenLoc(), Body.get()); } template<typename Derived> @@ -6842,15 +6918,18 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { if (Range.isInvalid()) return StmtError(); - StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt()); - if (BeginEnd.isInvalid()) + StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt()); + if (Begin.isInvalid()) + return StmtError(); + StmtResult End = getDerived().TransformStmt(S->getEndStmt()); + if (End.isInvalid()) return StmtError(); ExprResult Cond = getDerived().TransformExpr(S->getCond()); if (Cond.isInvalid()) return StmtError(); if (Cond.get()) - Cond = SemaRef.CheckBooleanCondition(Cond.get(), S->getColonLoc()); + Cond = SemaRef.CheckBooleanCondition(S->getColonLoc(), Cond.get()); if (Cond.isInvalid()) return StmtError(); if (Cond.get()) @@ -6869,14 +6948,16 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { StmtResult NewStmt = S; if (getDerived().AlwaysRebuild() || Range.get() != S->getRangeStmt() || - BeginEnd.get() != S->getBeginEndStmt() || + Begin.get() != S->getBeginStmt() || + End.get() != S->getEndStmt() || Cond.get() != S->getCond() || Inc.get() != S->getInc() || LoopVar.get() != S->getLoopVarStmt()) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getCoawaitLoc(), S->getColonLoc(), Range.get(), - BeginEnd.get(), Cond.get(), + Begin.get(), End.get(), + Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); if (NewStmt.isInvalid()) @@ -6893,7 +6974,8 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) { NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(), S->getCoawaitLoc(), S->getColonLoc(), Range.get(), - BeginEnd.get(), Cond.get(), + Begin.get(), End.get(), + Cond.get(), Inc.get(), LoopVar.get(), S->getRParenLoc()); if (NewStmt.isInvalid()) @@ -7378,6 +7460,61 @@ StmtResult TreeTransform<Derived>::TransformOMPTargetDataDirective( } template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetEnterDataDirective( + OMPTargetEnterDataDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_enter_data, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetExitDataDirective( + OMPTargetExitDataDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_exit_data, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetParallelDirective( + OMPTargetParallelDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetParallelForDirective( + OMPTargetParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_for, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetUpdateDirective( + OMPTargetUpdateDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_update, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> StmtResult TreeTransform<Derived>::TransformOMPTeamsDirective(OMPTeamsDirective *D) { DeclarationNameInfo DirName; @@ -7443,6 +7580,52 @@ StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective( return Res; } +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPDistributeParallelForDirective( + OMPDistributeParallelForDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_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>::TransformOMPDistributeParallelForSimdDirective( + OMPDistributeParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock( + OMPD_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>::TransformOMPDistributeSimdDirective( + OMPDistributeSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_simd, DirName, + nullptr, D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + +template <typename Derived> +StmtResult TreeTransform<Derived>::TransformOMPTargetParallelForSimdDirective( + OMPTargetParallelForSimdDirective *D) { + DeclarationNameInfo DirName; + getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_for_simd, + DirName, nullptr, + D->getLocStart()); + StmtResult Res = getDerived().TransformOMPExecutableDirective(D); + getDerived().getSema().EndOpenMPDSABlock(Res.get()); + return Res; +} + //===----------------------------------------------------------------------===// // OpenMP clause transformation //===----------------------------------------------------------------------===// @@ -7701,9 +7884,31 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) { if (!NameInfo.getName()) return nullptr; } + // Build a list of all UDR decls with the same names ranged by the Scopes. + // The Scope boundary is a duplication of the previous decl. + llvm::SmallVector<Expr *, 16> UnresolvedReductions; + for (auto *E : C->reduction_ops()) { + // Transform all the decls. + if (E) { + auto *ULE = cast<UnresolvedLookupExpr>(E); + UnresolvedSet<8> Decls; + for (auto *D : ULE->decls()) { + NamedDecl *InstD = + cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D)); + Decls.addDecl(InstD, InstD->getAccess()); + } + UnresolvedReductions.push_back( + UnresolvedLookupExpr::Create( + SemaRef.Context, /*NamingClass=*/nullptr, + ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), + NameInfo, /*ADL=*/true, ULE->isOverloaded(), + Decls.begin(), Decls.end())); + } else + UnresolvedReductions.push_back(nullptr); + } return getDerived().RebuildOMPReductionClause( Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(), - C->getLocEnd(), ReductionIdScopeSpec, NameInfo); + C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions); } template <typename Derived> @@ -7825,9 +8030,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) { Vars.push_back(EVar.get()); } return getDerived().RebuildOMPMapClause( - C->getMapTypeModifier(), C->getMapType(), C->getMapLoc(), - C->getColonLoc(), Vars, C->getLocStart(), C->getLParenLoc(), - C->getLocEnd()); + C->getMapTypeModifier(), C->getMapType(), C->isImplicitMapType(), + C->getMapLoc(), C->getColonLoc(), Vars, C->getLocStart(), + C->getLParenLoc(), C->getLocEnd()); } template <typename Derived> @@ -7889,6 +8094,81 @@ OMPClause *TreeTransform<Derived>::TransformOMPHintClause(OMPHintClause *C) { C->getLParenLoc(), C->getLocEnd()); } +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause( + OMPDistScheduleClause *C) { + ExprResult E = getDerived().TransformExpr(C->getChunkSize()); + if (E.isInvalid()) + return nullptr; + return getDerived().RebuildOMPDistScheduleClause( + C->getDistScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(), + C->getDistScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) { + return C; +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPToClause(OMPToClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPToClause(Vars, C->getLocStart(), + C->getLParenLoc(), C->getLocEnd()); +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPFromClause(OMPFromClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return 0; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPFromClause(Vars, C->getLocStart(), + C->getLParenLoc(), C->getLocEnd()); +} + +template <typename Derived> +OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause( + OMPUseDevicePtrClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPUseDevicePtrClause( + Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd()); +} + +template <typename Derived> +OMPClause * +TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) { + llvm::SmallVector<Expr *, 16> Vars; + Vars.reserve(C->varlist_size()); + for (auto *VE : C->varlists()) { + ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE)); + if (EVar.isInvalid()) + return nullptr; + Vars.push_back(EVar.get()); + } + return getDerived().RebuildOMPIsDevicePtrClause( + Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd()); +} + //===----------------------------------------------------------------------===// // Expression transformation //===----------------------------------------------------------------------===// @@ -8581,46 +8861,44 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) { // transform the designators. SmallVector<Expr*, 4> ArrayExprs; bool ExprChanged = false; - for (DesignatedInitExpr::designators_iterator D = E->designators_begin(), - DEnd = E->designators_end(); - D != DEnd; ++D) { - if (D->isFieldDesignator()) { - Desig.AddDesignator(Designator::getField(D->getFieldName(), - D->getDotLoc(), - D->getFieldLoc())); + for (const DesignatedInitExpr::Designator &D : E->designators()) { + if (D.isFieldDesignator()) { + Desig.AddDesignator(Designator::getField(D.getFieldName(), + D.getDotLoc(), + D.getFieldLoc())); continue; } - if (D->isArrayDesignator()) { - ExprResult Index = getDerived().TransformExpr(E->getArrayIndex(*D)); + if (D.isArrayDesignator()) { + ExprResult Index = getDerived().TransformExpr(E->getArrayIndex(D)); if (Index.isInvalid()) return ExprError(); - Desig.AddDesignator(Designator::getArray(Index.get(), - D->getLBracketLoc())); + Desig.AddDesignator( + Designator::getArray(Index.get(), D.getLBracketLoc())); - ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D); + ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(D); ArrayExprs.push_back(Index.get()); continue; } - assert(D->isArrayRangeDesignator() && "New kind of designator?"); + assert(D.isArrayRangeDesignator() && "New kind of designator?"); ExprResult Start - = getDerived().TransformExpr(E->getArrayRangeStart(*D)); + = getDerived().TransformExpr(E->getArrayRangeStart(D)); if (Start.isInvalid()) return ExprError(); - ExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(*D)); + ExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(D)); if (End.isInvalid()) return ExprError(); Desig.AddDesignator(Designator::getArrayRange(Start.get(), End.get(), - D->getLBracketLoc(), - D->getEllipsisLoc())); + D.getLBracketLoc(), + D.getEllipsisLoc())); - ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) || - End.get() != E->getArrayRangeEnd(*D); + ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(D) || + End.get() != E->getArrayRangeEnd(D); ArrayExprs.push_back(Start.get()); ArrayExprs.push_back(End.get()); @@ -9768,8 +10046,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { } return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(), - Constructor, E->isElidable(), - Args, + Constructor, + E->isElidable(), Args, E->hadMultipleCandidates(), E->isListInitialization(), E->isStdInitListInitialization(), @@ -9778,6 +10056,32 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) { E->getParenOrBraceRange()); } +template<typename Derived> +ExprResult TreeTransform<Derived>::TransformCXXInheritedCtorInitExpr( + CXXInheritedCtorInitExpr *E) { + QualType T = getDerived().TransformType(E->getType()); + if (T.isNull()) + return ExprError(); + + CXXConstructorDecl *Constructor = cast_or_null<CXXConstructorDecl>( + getDerived().TransformDecl(E->getLocStart(), E->getConstructor())); + if (!Constructor) + return ExprError(); + + if (!getDerived().AlwaysRebuild() && + T == E->getType() && + Constructor == E->getConstructor()) { + // Mark the constructor as referenced. + // FIXME: Instantiation-specific + SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor); + return E; + } + + return getDerived().RebuildCXXInheritedCtorInitExpr( + T, E->getLocation(), Constructor, + E->constructsVBase(), E->inheritedFromVBase()); +} + /// \brief Transform a C++ temporary-binding expression. /// /// Since CXXBindTemporaryExpr nodes are implicitly generated, we just @@ -9918,7 +10222,9 @@ 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; getDerived().transformAttrs(E->getCallOperator(), NewCallOperator); @@ -9953,7 +10259,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) { // Capturing 'this' is trivial. if (C->capturesThis()) { - getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit()); + getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(), + /*BuildAndDiagnose*/ true, nullptr, + C->getCaptureKind() == LCK_StarThis); continue; } // Captured expression will be recaptured during captured variables @@ -10804,6 +11112,12 @@ TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) { Result.get()); } +template <typename Derived> +ExprResult TreeTransform<Derived>::TransformObjCAvailabilityCheckExpr( + ObjCAvailabilityCheckExpr *E) { + return E; +} + template<typename Derived> ExprResult TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) { @@ -11039,22 +11353,26 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) { SmallVector<ParmVarDecl*, 4> params; SmallVector<QualType, 4> paramTypes; + const FunctionProtoType *exprFunctionType = E->getFunctionType(); + // Parameter substitution. - if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(), - oldBlock->param_begin(), - oldBlock->param_size(), - nullptr, paramTypes, ¶ms)) { + Sema::ExtParameterInfoBuilder extParamInfos; + if (getDerived().TransformFunctionTypeParams( + E->getCaretLocation(), oldBlock->parameters(), nullptr, + exprFunctionType->getExtParameterInfosOrNull(), paramTypes, ¶ms, + extParamInfos)) { getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr); return ExprError(); } - const FunctionProtoType *exprFunctionType = E->getFunctionType(); QualType exprResultType = getDerived().TransformType(exprFunctionType->getReturnType()); + auto epi = exprFunctionType->getExtProtoInfo(); + epi.ExtParameterInfos = extParamInfos.getPointerOrNull(paramTypes.size()); + QualType functionType = - getDerived().RebuildFunctionProtoType(exprResultType, paramTypes, - exprFunctionType->getExtProtoInfo()); + getDerived().RebuildFunctionProtoType(exprResultType, paramTypes, epi); blockScope->FunctionType = functionType; // Set the parameters on the block decl. diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp index be995400df6d..340b7fae78aa 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp @@ -115,11 +115,39 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli NumBytesAtAlign4 += LocalSize; } } else if (LocalAlignment == 8) { - if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) { - // No existing padding and misaligned members; add in 4 bytes padding - memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4); - Index -= 4; + if (NumBytesAtAlign8 == 0) { + // We have not seen any 8-byte aligned element yet. We insert a padding + // only if the new Index is not 8-byte-aligned. + if ((Index - LocalSize) % 8 != 0) { + memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4); + Index -= 4; + } + } else { + unsigned Padding = NumBytesAtAlign4 % 8; + if (Padding == 0) { + if (LocalSize % 8 == 0) { + // Everything is set: there's no padding and we don't need to add + // any. + } else { + assert(LocalSize % 8 == 4); + // No existing padding; add in 4 bytes padding + memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4); + Index -= 4; + } + } else { + assert(Padding == 4); + if (LocalSize % 8 == 0) { + // Everything is set: there's 4 bytes padding and we don't need + // to add any. + } else { + assert(LocalSize % 8 == 4); + // There are 4 bytes padding, but we don't need any; remove it. + memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4); + Index += 4; + } + } } + // Forget about any padding. NumBytesAtAlign4 = 0; NumBytesAtAlign8 += LocalSize; diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h index 82844b391467..382821859768 100644 --- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h +++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// // -// This files defines TypeLocBuilder, a class for building TypeLocs +// This file defines TypeLocBuilder, a class for building TypeLocs // bottom-up. // //===----------------------------------------------------------------------===// |