diff options
author | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2016-12-26 20:36:37 +0000 |
commit | 06210ae42d418d50d8d9365d5c9419308ae9e7ee (patch) | |
tree | ab60b4cdd6e430dda1f292a46a77ddb744723f31 /contrib/llvm/tools/clang/lib/Sema | |
parent | 2dd166267f53df1c3748b4325d294b9b839de74b (diff) | |
download | FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.zip FreeBSD-src-06210ae42d418d50d8d9365d5c9419308ae9e7ee.tar.gz |
MFC r309124:
Upgrade our copies of clang, llvm, lldb, compiler-rt and libc++ to 3.9.0
release, and add lld 3.9.0. Also completely revamp the build system for
clang, llvm, lldb and their related tools.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld are available here:
<http://llvm.org/releases/3.9.0/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/clang/docs/ReleaseNotes.html>
<http://llvm.org/releases/3.9.0/tools/lld/docs/ReleaseNotes.html>
Thanks to Ed Maste, Bryan Drewery, Andrew Turner, Antoine Brodin and Jan
Beich for their help.
Relnotes: yes
MFC r309147:
Pull in r282174 from upstream llvm trunk (by Krzysztof Parzyszek):
[PPC] Set SP after loading data from stack frame, if no red zone is
present
Follow-up to r280705: Make sure that the SP is only restored after
all data is loaded from the stack frame, if there is no red zone.
This completes the fix for
https://llvm.org/bugs/show_bug.cgi?id=26519.
Differential Revision: https://reviews.llvm.org/D24466
Reported by: Mark Millard
PR: 214433
MFC r309149:
Pull in r283060 from upstream llvm trunk (by Hal Finkel):
[PowerPC] Refactor soft-float support, and enable PPC64 soft float
This change enables soft-float for PowerPC64, and also makes
soft-float disable all vector instruction sets for both 32-bit and
64-bit modes. This latter part is necessary because the PPC backend
canonicalizes many Altivec vector types to floating-point types, and
so soft-float breaks scalarization support for many operations. Both
for embedded targets and for operating-system kernels desiring
soft-float support, it seems reasonable that disabling hardware
floating-point also disables vector instructions (embedded targets
without hardware floating point support are unlikely to have Altivec,
etc. and operating system kernels desiring not to use floating-point
registers to lower syscall cost are unlikely to want to use vector
registers either). If someone needs this to work, we'll need to
change the fact that we promote many Altivec operations to act on
v4f32. To make it possible to disable Altivec when soft-float is
enabled, hardware floating-point support needs to be expressed as a
positive feature, like the others, and not a negative feature,
because target features cannot have dependencies on the disabling of
some other feature. So +soft-float has now become -hard-float.
Fixes PR26970.
Pull in r283061 from upstream clang trunk (by Hal Finkel):
[PowerPC] Enable soft-float for PPC64, and +soft-float -> -hard-float
Enable soft-float support on PPC64, as the backend now supports it.
Also, the backend now uses -hard-float instead of +soft-float, so set
the target features accordingly.
Fixes PR26970.
Reported by: Mark Millard
PR: 214433
MFC r309212:
Add a few missed clang 3.9.0 files to OptionalObsoleteFiles.
MFC r309262:
Fix packaging for clang, lldb and lld 3.9.0
During the upgrade of clang/llvm etc to 3.9.0 in r309124, the PACKAGE
directive in the usr.bin/clang/*.mk files got dropped accidentally.
Restore it, with a few minor changes and additions:
* Correct license in clang.ucl to NCSA
* Add PACKAGE=clang for clang and most of the "ll" tools
* Put lldb in its own package
* Put lld in its own package
Reviewed by: gjb, jmallett
Differential Revision: https://reviews.freebsd.org/D8666
MFC r309656:
During the bootstrap phase, when building the minimal llvm library on
PowerPC, add lib/Support/Atomic.cpp. This is needed because upstream
llvm revision r271821 disabled the use of std::call_once, which causes
some fallback functions from Atomic.cpp to be used instead.
Reported by: Mark Millard
PR: 214902
MFC r309835:
Tentatively apply https://reviews.llvm.org/D18730 to work around gcc PR
70528 (bogus error: constructor required before non-static data member).
This should fix buildworld with the external gcc package.
Reported by: https://jenkins.freebsd.org/job/FreeBSD_HEAD_amd64_gcc/
MFC r310194:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
3.9.1 release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
Release notes for llvm, clang and lld will be available here:
<http://releases.llvm.org/3.9.1/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/3.9.1/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema')
46 files changed, 14913 insertions, 6269 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp index 5f74343..67762bd 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 3c61c95..cae9393 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 18e9a59..9a4f0d9 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 6f6c4ca..b9d2843 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 53263ba..0bdb194 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 c394d24..bdbe06c 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 0f93421..eee4c00 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 7c70048..ae5b181 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 cbd7ef7..4b2e13e 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 39b8cc9..7777476 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(); } @@ -1204,11 +1197,19 @@ BlockScopeInfo *Sema::getCurBlock() { return CurBSI; } -LambdaScopeInfo *Sema::getCurLambda() { +LambdaScopeInfo *Sema::getCurLambda(bool IgnoreCapturedRegions) { if (FunctionScopes.empty()) return nullptr; - auto CurLSI = dyn_cast<LambdaScopeInfo>(FunctionScopes.back()); + auto I = FunctionScopes.rbegin(); + if (IgnoreCapturedRegions) { + auto E = FunctionScopes.rend(); + while (I != E && isa<CapturedRegionScopeInfo>(*I)) + ++I; + if (I == E) + return nullptr; + } + auto *CurLSI = dyn_cast<LambdaScopeInfo>(*I); if (CurLSI && CurLSI->Lambda && !CurLSI->Lambda->Encloses(CurContext)) { // We have switched contexts due to template instantiation. @@ -1260,14 +1261,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 +1282,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 +1510,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 e9772bc..98a918b 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 5a29bad..0d7fba5 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 61dfdd3..90af6d5 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 f7aace6..949263d 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()); @@ -777,7 +806,7 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S, if (!Found.empty()) { if (TypeDecl *TD = Found.getAsSingle<TypeDecl>()) Diag(IdentifierLoc, diag::err_expected_class_or_namespace) - << QualType(TD->getTypeForDecl(), 0) << getLangOpts().CPlusPlus; + << Context.getTypeDeclType(TD) << getLangOpts().CPlusPlus; else { Diag(IdentifierLoc, diag::err_expected_class_or_namespace) << &Identifier << getLangOpts().CPlusPlus; diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp index ad1d7da..e83dd07 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 6c2834b..ef04d60 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 || @@ -955,8 +1454,17 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID, return SemaBuiltinConstantArgRange(TheCall, i, l, u + l); } +// CheckMipsBuiltinFunctionCall - Checks the constant value passed to the +// intrinsic is correct. The switch statement is ordered by DSP, MSA. The +// ordering for DSP is unspecified. MSA is ordered by the data format used +// by the underlying instruction i.e., df/m, df/n and then by size. +// +// FIXME: The size tests here should instead be tablegen'd along with the +// definitions from include/clang/Basic/BuiltinsMips.def. +// FIXME: GCC is strict on signedness for some of these intrinsics, we should +// be too. bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { - unsigned i = 0, l = 0, u = 0; + unsigned i = 0, l = 0, u = 0, m = 0; switch (BuiltinID) { default: return false; case Mips::BI__builtin_mips_wrdsp: i = 1; l = 0; u = 63; break; @@ -966,9 +1474,168 @@ bool Sema::CheckMipsBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { case Mips::BI__builtin_mips_precr_sra_ph_w: i = 2; l = 0; u = 31; break; case Mips::BI__builtin_mips_precr_sra_r_ph_w: i = 2; l = 0; u = 31; break; case Mips::BI__builtin_mips_prepend: i = 2; l = 0; u = 31; break; - } - - return SemaBuiltinConstantArgRange(TheCall, i, l, u); + // MSA instrinsics. Instructions (which the intrinsics maps to) which use the + // df/m field. + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_bclri_b: + case Mips::BI__builtin_msa_bnegi_b: + case Mips::BI__builtin_msa_bseti_b: + case Mips::BI__builtin_msa_sat_s_b: + case Mips::BI__builtin_msa_sat_u_b: + case Mips::BI__builtin_msa_slli_b: + case Mips::BI__builtin_msa_srai_b: + case Mips::BI__builtin_msa_srari_b: + case Mips::BI__builtin_msa_srli_b: + case Mips::BI__builtin_msa_srlri_b: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_binsli_b: + case Mips::BI__builtin_msa_binsri_b: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_bclri_h: + case Mips::BI__builtin_msa_bnegi_h: + case Mips::BI__builtin_msa_bseti_h: + case Mips::BI__builtin_msa_sat_s_h: + case Mips::BI__builtin_msa_sat_u_h: + case Mips::BI__builtin_msa_slli_h: + case Mips::BI__builtin_msa_srai_h: + case Mips::BI__builtin_msa_srari_h: + case Mips::BI__builtin_msa_srli_h: + case Mips::BI__builtin_msa_srlri_h: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_binsli_h: + case Mips::BI__builtin_msa_binsri_h: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 5 bit immedate. + // The first block of intrinsics actually have an unsigned 5 bit field, + // not a df/n field. + case Mips::BI__builtin_msa_clei_u_b: + case Mips::BI__builtin_msa_clei_u_h: + case Mips::BI__builtin_msa_clei_u_w: + case Mips::BI__builtin_msa_clei_u_d: + case Mips::BI__builtin_msa_clti_u_b: + case Mips::BI__builtin_msa_clti_u_h: + case Mips::BI__builtin_msa_clti_u_w: + case Mips::BI__builtin_msa_clti_u_d: + case Mips::BI__builtin_msa_maxi_u_b: + case Mips::BI__builtin_msa_maxi_u_h: + case Mips::BI__builtin_msa_maxi_u_w: + case Mips::BI__builtin_msa_maxi_u_d: + case Mips::BI__builtin_msa_mini_u_b: + case Mips::BI__builtin_msa_mini_u_h: + case Mips::BI__builtin_msa_mini_u_w: + case Mips::BI__builtin_msa_mini_u_d: + case Mips::BI__builtin_msa_addvi_b: + case Mips::BI__builtin_msa_addvi_h: + case Mips::BI__builtin_msa_addvi_w: + case Mips::BI__builtin_msa_addvi_d: + case Mips::BI__builtin_msa_bclri_w: + case Mips::BI__builtin_msa_bnegi_w: + case Mips::BI__builtin_msa_bseti_w: + case Mips::BI__builtin_msa_sat_s_w: + case Mips::BI__builtin_msa_sat_u_w: + case Mips::BI__builtin_msa_slli_w: + case Mips::BI__builtin_msa_srai_w: + case Mips::BI__builtin_msa_srari_w: + case Mips::BI__builtin_msa_srli_w: + case Mips::BI__builtin_msa_srlri_w: + case Mips::BI__builtin_msa_subvi_b: + case Mips::BI__builtin_msa_subvi_h: + case Mips::BI__builtin_msa_subvi_w: + case Mips::BI__builtin_msa_subvi_d: i = 1; l = 0; u = 31; break; + case Mips::BI__builtin_msa_binsli_w: + case Mips::BI__builtin_msa_binsri_w: i = 2; l = 0; u = 31; break; + // These intrinsics take an unsigned 6 bit immediate. + case Mips::BI__builtin_msa_bclri_d: + case Mips::BI__builtin_msa_bnegi_d: + case Mips::BI__builtin_msa_bseti_d: + case Mips::BI__builtin_msa_sat_s_d: + case Mips::BI__builtin_msa_sat_u_d: + case Mips::BI__builtin_msa_slli_d: + case Mips::BI__builtin_msa_srai_d: + case Mips::BI__builtin_msa_srari_d: + case Mips::BI__builtin_msa_srli_d: + case Mips::BI__builtin_msa_srlri_d: i = 1; l = 0; u = 63; break; + case Mips::BI__builtin_msa_binsli_d: + case Mips::BI__builtin_msa_binsri_d: i = 2; l = 0; u = 63; break; + // These intrinsics take a signed 5 bit immediate. + case Mips::BI__builtin_msa_ceqi_b: + case Mips::BI__builtin_msa_ceqi_h: + case Mips::BI__builtin_msa_ceqi_w: + case Mips::BI__builtin_msa_ceqi_d: + case Mips::BI__builtin_msa_clti_s_b: + case Mips::BI__builtin_msa_clti_s_h: + case Mips::BI__builtin_msa_clti_s_w: + case Mips::BI__builtin_msa_clti_s_d: + case Mips::BI__builtin_msa_clei_s_b: + case Mips::BI__builtin_msa_clei_s_h: + case Mips::BI__builtin_msa_clei_s_w: + case Mips::BI__builtin_msa_clei_s_d: + case Mips::BI__builtin_msa_maxi_s_b: + case Mips::BI__builtin_msa_maxi_s_h: + case Mips::BI__builtin_msa_maxi_s_w: + case Mips::BI__builtin_msa_maxi_s_d: + case Mips::BI__builtin_msa_mini_s_b: + case Mips::BI__builtin_msa_mini_s_h: + case Mips::BI__builtin_msa_mini_s_w: + case Mips::BI__builtin_msa_mini_s_d: i = 1; l = -16; u = 15; break; + // These intrinsics take an unsigned 8 bit immediate. + case Mips::BI__builtin_msa_andi_b: + case Mips::BI__builtin_msa_nori_b: + case Mips::BI__builtin_msa_ori_b: + case Mips::BI__builtin_msa_shf_b: + case Mips::BI__builtin_msa_shf_h: + case Mips::BI__builtin_msa_shf_w: + case Mips::BI__builtin_msa_xori_b: i = 1; l = 0; u = 255; break; + case Mips::BI__builtin_msa_bseli_b: + case Mips::BI__builtin_msa_bmnzi_b: + case Mips::BI__builtin_msa_bmzi_b: i = 2; l = 0; u = 255; break; + // df/n format + // These intrinsics take an unsigned 4 bit immediate. + case Mips::BI__builtin_msa_copy_s_b: + case Mips::BI__builtin_msa_copy_u_b: + case Mips::BI__builtin_msa_insve_b: + case Mips::BI__builtin_msa_splati_b: i = 1; l = 0; u = 15; break; + case Mips::BI__builtin_msa_sld_b: + case Mips::BI__builtin_msa_sldi_b: i = 2; l = 0; u = 15; break; + // These intrinsics take an unsigned 3 bit immediate. + case Mips::BI__builtin_msa_copy_s_h: + case Mips::BI__builtin_msa_copy_u_h: + case Mips::BI__builtin_msa_insve_h: + case Mips::BI__builtin_msa_splati_h: i = 1; l = 0; u = 7; break; + case Mips::BI__builtin_msa_sld_h: + case Mips::BI__builtin_msa_sldi_h: i = 2; l = 0; u = 7; break; + // These intrinsics take an unsigned 2 bit immediate. + case Mips::BI__builtin_msa_copy_s_w: + case Mips::BI__builtin_msa_copy_u_w: + case Mips::BI__builtin_msa_insve_w: + case Mips::BI__builtin_msa_splati_w: i = 1; l = 0; u = 3; break; + case Mips::BI__builtin_msa_sld_w: + case Mips::BI__builtin_msa_sldi_w: i = 2; l = 0; u = 3; break; + // These intrinsics take an unsigned 1 bit immediate. + case Mips::BI__builtin_msa_copy_s_d: + case Mips::BI__builtin_msa_copy_u_d: + case Mips::BI__builtin_msa_insve_d: + case Mips::BI__builtin_msa_splati_d: i = 1; l = 0; u = 1; break; + case Mips::BI__builtin_msa_sld_d: + case Mips::BI__builtin_msa_sldi_d: i = 2; l = 0; u = 1; break; + // Memory offsets and immediate loads. + // These intrinsics take a signed 10 bit immediate. + case Mips::BI__builtin_msa_ldi_b: i = 0; l = -128; u = 127; break; + case Mips::BI__builtin_msa_ldi_h: + case Mips::BI__builtin_msa_ldi_w: + case Mips::BI__builtin_msa_ldi_d: i = 0; l = -512; u = 511; break; + case Mips::BI__builtin_msa_ld_b: i = 1; l = -512; u = 511; m = 16; break; + case Mips::BI__builtin_msa_ld_h: i = 1; l = -1024; u = 1022; m = 16; break; + case Mips::BI__builtin_msa_ld_w: i = 1; l = -2048; u = 2044; m = 16; break; + case Mips::BI__builtin_msa_ld_d: i = 1; l = -4096; u = 4088; m = 16; break; + case Mips::BI__builtin_msa_st_b: i = 2; l = -512; u = 511; m = 16; break; + case Mips::BI__builtin_msa_st_h: i = 2; l = -1024; u = 1022; m = 16; break; + case Mips::BI__builtin_msa_st_w: i = 2; l = -2048; u = 2044; m = 16; break; + case Mips::BI__builtin_msa_st_d: i = 2; l = -4096; u = 4088; m = 16; break; + } + + if (!m) + return SemaBuiltinConstantArgRange(TheCall, i, l, u); + + return SemaBuiltinConstantArgRange(TheCall, i, l, u) || + SemaBuiltinConstantArgMultiple(TheCall, i, m); } bool Sema::CheckPPCBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) { @@ -1091,19 +1758,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 +1833,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 +2416,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 +2427,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 +2454,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 +2468,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 +2499,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 +2567,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 +2594,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 +2655,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 +2670,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 +2736,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 +2786,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 +3331,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 +3339,39 @@ 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->isSpecificBuiltinType(BuiltinType::Float) || [=] { + // Promotable integers are UB, but enumerations need a bit of + // extra checking to see what their promotable type actually is. + if (!Type->isPromotableIntegerType()) + return false; + if (!Type->isEnumeralType()) + return true; + const EnumDecl *ED = Type->getAs<EnumType>()->getDecl(); + return !(ED && + Context.typesAreCompatible(ED->getPromotionType(), Type)); + }()) { + unsigned Reason = 0; + if (Type->isReferenceType()) Reason = 1; + else if (IsCRegister) Reason = 2; + Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason; Diag(ParamLoc, diag::note_parameter_type) << Type; } @@ -2662,8 +3566,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; @@ -2879,6 +3782,28 @@ bool Sema::SemaBuiltinConstantArgRange(CallExpr *TheCall, int ArgNum, return false; } +/// SemaBuiltinConstantArgMultiple - Handle a check if argument ArgNum of CallExpr +/// TheCall is a constant expression is a multiple of Num.. +bool Sema::SemaBuiltinConstantArgMultiple(CallExpr *TheCall, int ArgNum, + unsigned Num) { + llvm::APSInt Result; + + // We can't check the value of a dependent argument. + Expr *Arg = TheCall->getArg(ArgNum); + if (Arg->isTypeDependent() || Arg->isValueDependent()) + return false; + + // Check constant-ness first. + if (SemaBuiltinConstantArg(TheCall, ArgNum, Result)) + return true; + + if (Result.getSExtValue() % Num != 0) + return Diag(TheCall->getLocStart(), diag::err_argument_not_multiple) + << Num << Arg->getSourceRange(); + + return false; +} + /// SemaBuiltinARMSpecialReg - Handle a check if argument ArgNum of CallExpr /// TheCall is an ARM/AArch64 special register string literal. bool Sema::SemaBuiltinARMSpecialReg(unsigned BuiltinID, CallExpr *TheCall, @@ -3002,7 +3927,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 +3937,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 +4009,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 +4031,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 +4114,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 +4170,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 +4179,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 +4197,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 +4267,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 +4294,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 +4342,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 +4351,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 +4394,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 +4427,7 @@ protected: bool IsStringLocation, Range StringRange, ArrayRef<FixItHint> Fixit = None); }; -} +} // end anonymous namespace SourceRange CheckFormatHandler::getFormatStringRange() { return OrigFormatExpr->getSourceRange(); @@ -3558,26 +4589,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 +4634,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 +4648,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 +4709,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 +4755,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 +4782,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 +4791,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 +4840,7 @@ public: const char *conversionPosition) override; }; -} +} // end anonymous namespace bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier( const analyze_printf::PrintfSpecifier &FS, @@ -3779,7 +4859,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 +5070,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 +5439,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 +5577,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 +5596,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 +5623,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 +5742,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 +5777,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 +5787,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 +6228,6 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call, emitReplacement(*this, Call->getExprLoc(), Call->getCallee()->getSourceRange(), NewAbsKind, ArgType); - return; } //===--- CHECK: Standard memory functions ---------------------------------===// @@ -5191,7 +6273,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 +6480,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 +6694,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 +6707,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. @@ -5639,6 +6722,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, if (!stackE) return; // Nothing suspicious was found. + // Parameters are initalized in the calling scope, so taking the address + // of a parameter reference doesn't need a warning. + for (auto *DRE : refVars) + if (isa<ParmVarDecl>(DRE->getDecl())) + return; + SourceLocation diagLoc; SourceRange diagRange; if (refVars.empty()) { @@ -5653,7 +6742,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. @@ -5661,6 +6751,13 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType, } else if (isa<AddrLabelExpr>(stackE)) { // address of label. S.Diag(diagLoc, diag::warn_ret_addr_label) << diagRange; } else { // local temporary. + // If there is an LValue->RValue conversion, then the value of the + // reference type is used, not the reference. + if (auto *ICE = dyn_cast<ImplicitCastExpr>(RetValExp)) { + if (ICE->getCastKind() == CK_LValueToRValue) { + return; + } + } S.Diag(diagLoc, diag::warn_ret_local_temp_addr_ref) << lhsType->isReferenceType() << diagRange; } @@ -5668,12 +6765,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 +6802,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 +6821,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 +6843,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 +6913,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 +6943,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 +7149,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 +7274,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 +7286,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 +7315,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 +7326,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 +7337,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 +7364,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 +7378,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 +7518,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 +7534,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 +7568,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 +7586,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 +7603,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 +7615,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 +7643,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 +7853,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 +7861,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 +7962,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; @@ -6889,6 +7988,12 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init, unsigned OriginalWidth = Value.getBitWidth(); unsigned FieldWidth = Bitfield->getBitWidthValue(S.Context); + if (Value.isSigned() && Value.isNegative()) + if (UnaryOperator *UO = dyn_cast<UnaryOperator>(OriginalInit)) + if (UO->getOpcode() == UO_Minus) + if (isa<IntegerLiteral>(UO->getSubExpr())) + OriginalWidth = Value.getMinSignedBits(); + if (OriginalWidth <= FieldWidth) return false; @@ -6918,7 +8023,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 +8042,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 +8057,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 +8138,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 +8165,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 +8205,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 +8227,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 +8254,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 +8291,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 +8319,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 +8346,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 +8476,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 +8487,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 +8539,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 +8564,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 +8634,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 +8649,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 +8681,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 +8785,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 +8904,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 +8913,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 +8942,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 +9042,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 +9076,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 +9107,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 +9219,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 +9426,7 @@ public: notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue : UK_ModAsSideEffect); } + void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) { VisitBinAssign(CAO); } @@ -8344,7 +9576,7 @@ public: Tree.merge(Elts[I]); } }; -} +} // end anonymous namespace void Sema::CheckUnsequencedOperations(Expr *E) { SmallVector<Expr *, 8> WorkList; @@ -8358,7 +9590,8 @@ void Sema::CheckUnsequencedOperations(Expr *E) { void Sema::CheckCompletedExpr(Expr *E, SourceLocation CheckLoc, bool IsConstexpr) { CheckImplicitConversions(E, CheckLoc); - CheckUnsequencedOperations(E); + if (!E->isInstantiationDependent()) + CheckUnsequencedOperations(E); if (!IsConstexpr && !E->isValueDependent()) CheckForIntOverflow(E); } @@ -8403,13 +9636,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 +9747,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 +9801,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 +9826,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 +9976,7 @@ namespace { Range = e->getSourceRange(); } }; -} +} // end anonymous namespace /// Consider whether capturing the given variable can possibly lead to /// a retain cycle. @@ -8900,7 +10122,7 @@ namespace { } } }; -} +} // end anonymous namespace /// Check whether the given argument is a block which captures a /// variable. @@ -9136,7 +10358,6 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) { } } } - } /// Check a message send to see if it's likely to cause a retain cycle. @@ -9340,7 +10561,7 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr, return true; } -} // Unnamed namespace +} // end anonymous namespace void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc, const Stmt *Body, @@ -9436,7 +10657,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 +10895,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 +11026,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 +11059,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 21cf625..36babc4 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 4b4fd6b..c8715ff 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 f95d106..41719d4 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, @@ -9292,9 +9615,10 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, } VarDecl *Def; - if ((Def = VDecl->getDefinition()) && Def != VDecl) { + if ((Def = VDecl->getDefinition()) && Def != VDecl && + (!VDecl->isStaticDataMember() || VDecl->isOutOfLine())) { NamedDecl *Hidden = nullptr; - if (!hasVisibleDefinition(Def, &Hidden) && + if (!hasVisibleDefinition(Def, &Hidden) && (VDecl->getFormalLinkage() == InternalLinkage || VDecl->getDescribedVarTemplate() || VDecl->getNumTemplateParameterLists() || @@ -9330,7 +9654,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, diag::note_previous_initializer) << 0; return; - } + } if (VDecl->hasLocalStorage()) getCurFunction()->setHasBranchProtectedScope(); @@ -9352,7 +9676,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 +9724,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 +9812,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 +9826,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 +9967,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 +10010,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 +10055,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 +10082,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 +10187,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 +10221,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 +10296,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 +10365,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 +10515,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 +10814,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 +10832,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 +10892,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 +10927,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 +10958,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 +10997,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 +11011,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 +11020,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 +11031,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc, Diag(NameLoc, diag::err_arg_with_address_space); New->setInvalidDecl(); } - } + } return New; } @@ -10686,11 +11085,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 +11185,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 +11202,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 +11216,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 +11237,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 +11258,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 +11297,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 +11364,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 +11432,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 +11452,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 +11515,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 +11524,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 +11587,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 +11648,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 +11661,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 +11695,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 +11714,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 +11721,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 +11874,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 +11891,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 +11955,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 +11965,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 +11990,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 +12417,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 +12441,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 +12518,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 +12834,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 +12934,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 +12951,6 @@ CreateNewDecl: ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0)); ED->setPromotionType(ED->getIntegerType()); } - } else { // struct/union/class @@ -12569,10 +12979,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 +13091,6 @@ CreateNewDecl: PushOnScopeChains(New, S, !IsForwardReference); if (IsForwardReference) SearchDC->makeDeclVisibleInContext(New); - } else { CurContext->addDecl(New); } @@ -12709,7 +13118,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 +13130,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 +13177,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 +13235,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 +13370,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 +13397,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 +13431,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 +13663,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 +13761,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 +13799,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 +13844,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 +13873,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 +13927,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 +13943,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 +14042,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 +14055,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 +14080,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 +14136,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl, } } } - + if (!Completed) Record->completeDefinition(); @@ -13812,7 +14225,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 +14236,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 +14272,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 +14358,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 +14397,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 +14423,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 +14444,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 +14470,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 +14530,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 +14776,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 +14846,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 +15062,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 +15079,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 +15092,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 +15116,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 +15134,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 +15154,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 f94c822..a5780a7 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 82d81a8..e161c87 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 a2f41a7..738de77 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 f12bf24..4a21eb3 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 5a2eb60..719e1e3 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); @@ -4427,6 +4522,11 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc, MutiLevelArgList.getInnermost()); if (Inst.isInvalid()) return ExprError(); + if (Inst.isAlreadyInstantiating()) { + Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD; + Param->setInvalidDecl(); + return ExprError(); + } ExprResult Result; { @@ -4466,6 +4566,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 +4580,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 +4973,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 +5105,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 +5150,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 +5242,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 +5315,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 +5603,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 +6251,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 +6599,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 +6660,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 +7018,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 +7147,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 +7399,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 +7789,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 +7954,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. @@ -8309,7 +8572,7 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS, // If LHS does not have a signed type and non-negative value // then, the behavior is undefined. Warn about it. - if (Left.isNegative()) { + if (Left.isNegative() && !S.getLangOpts().isSignedOverflowDefined()) { S.DiagRuntimeBehavior(Loc, LHS.get(), S.PDiag(diag::warn_shift_lhs_negative) << LHS.get()->getSourceRange()); @@ -9244,7 +9507,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 +9674,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 +9830,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 +10073,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 +10163,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 +10414,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 +10538,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 +10580,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 +10820,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 +10832,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 +11312,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 +11631,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 +12056,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 +12064,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 +12094,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 +12164,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 +12190,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 +12206,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 +12219,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 +12366,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 +12827,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 +12880,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 +12904,7 @@ void Sema::DiscardCleanupsInEvaluationContext() { ExprCleanupObjects.erase( ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects, ExprCleanupObjects.end()); - ExprNeedsCleanups = false; + Cleanup.reset(); MaybeODRUseExprs.clear(); } @@ -12563,6 +12929,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 +12952,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 +12963,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 +13044,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 +13069,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 +13116,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 +13132,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 +13320,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 +13389,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 +13435,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 +13529,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 +13585,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 +13601,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 +13666,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 +13689,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 @@ -13511,7 +13885,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc, (SemaRef.CurContext != Var->getDeclContext() && Var->getDeclContext()->isFunctionOrMethod() && Var->hasLocalStorage()); if (RefersToEnclosingScope) { - if (LambdaScopeInfo *const LSI = SemaRef.getCurLambda()) { + if (LambdaScopeInfo *const LSI = + SemaRef.getCurLambda(/*IgnoreCapturedRegions=*/true)) { // If a variable could potentially be odr-used, defer marking it so // until we finish analyzing the full expression for any // lvalue-to-rvalue @@ -13539,6 +13914,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 +13963,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 +13992,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 +14023,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 +14046,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 +14224,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 +14374,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 +14386,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 +14405,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(); + + 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(); - return CheckBooleanCondition(SubExpr, Loc); + // 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 +14869,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 +14977,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 +15049,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 +15089,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 38fbea1..dfdd367 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,27 +872,123 @@ 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; + if (CXXMethodDecl *method = dyn_cast<CXXMethodDecl>(DC)) { if (method && method->isInstance()) ThisTy = method->getThisType(Context); } - if (ThisTy.isNull()) { - if (isGenericLambdaCallOperatorSpecialization(CurContext) && - CurContext->getParent()->getParent()->isRecord()) { - // This is a generic lambda call operator that is being instantiated - // within a default initializer - so use the enclosing class as 'this'. - // There is no enclosing member function to retrieve the 'this' pointer - // from. - 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); - } + + if (ThisTy.isNull() && isLambdaCallOperator(CurContext) && + !ActiveTemplateInstantiations.empty()) { + + assert(isa<CXXRecordDecl>(DC) && + "Trying to get 'this' type from static method?"); + + // This is a lambda call operator that is being instantiated as a default + // initializer. DC must point to the enclosing class type, so we can recover + // the 'this' type from it. + + QualType ClassTy = Context.getTypeDeclType(cast<CXXRecordDecl>(DC)); + // There are no cv-qualifiers for 'this' within default initializers, + // per [expr.prim.general]p4. + 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 +1007,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 +1023,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 +1112,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 +1216,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 +1778,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 +2341,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 +2368,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 +2391,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 +2433,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 +2484,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 +2518,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 +2984,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 +3016,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 +3094,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 +3118,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 +3157,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 +3187,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 +3344,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()); @@ -3960,9 +4221,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, // A template constructor is never a copy constructor. // FIXME: However, it may actually be selected at the actual overload // resolution point. - if (isa<FunctionTemplateDecl>(ND)) + if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl())) continue; - const CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(ND); + // UsingDecl itself is not a constructor + if (isa<UsingDecl>(ND)) + continue; + auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isCopyConstructor(FoundTQs)) { FoundConstructor = true; const FunctionProtoType *CPT @@ -3996,9 +4260,12 @@ static bool EvaluateUnaryTypeTrait(Sema &Self, TypeTrait UTT, bool FoundConstructor = false; for (const auto *ND : Self.LookupConstructors(RD)) { // FIXME: In C++0x, a constructor template can be a default constructor. - if (isa<FunctionTemplateDecl>(ND)) + if (isa<FunctionTemplateDecl>(ND->getUnderlyingDecl())) + continue; + // UsingDecl itself is not a constructor + if (isa<UsingDecl>(ND)) continue; - const CXXConstructorDecl *Constructor = cast<CXXConstructorDecl>(ND); + auto *Constructor = cast<CXXConstructorDecl>(ND->getUnderlyingDecl()); if (Constructor->isDefaultConstructor()) { FoundConstructor = true; const FunctionProtoType *CPT @@ -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; @@ -6302,10 +6588,16 @@ static inline bool VariableCanNeverBeAConstantExpression(VarDecl *Var, static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures( Expr *const FE, LambdaScopeInfo *const CurrentLSI, Sema &S) { - assert(!S.isUnevaluatedContext()); - assert(S.CurContext->isDependentContext()); - assert(CurrentLSI->CallOperator == S.CurContext && + assert(!S.isUnevaluatedContext()); + assert(S.CurContext->isDependentContext()); +#ifndef NDEBUG + DeclContext *DC = S.CurContext; + while (DC && isa<CapturedDecl>(DC)) + DC = DC->getParent(); + assert( + CurrentLSI->CallOperator == DC && "The current call operator must be synchronized with Sema's CurContext"); +#endif // NDEBUG const bool IsFullExprInstantiationDependent = FE->isInstantiationDependent(); @@ -6390,7 +6682,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 +6859,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) { @@ -6763,7 +7063,8 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // and then the full-expression +n + ({ 0; }); ends, but it's too late // for us to see that we need to capture n after all. - LambdaScopeInfo *const CurrentLSI = getCurLambda(); + LambdaScopeInfo *const CurrentLSI = + getCurLambda(/*IgnoreCapturedRegions=*/true); // FIXME: PR 17877 showed that getCurLambda() can return a valid pointer // even if CurContext is not a lambda call operator. Refer to that Bug Report // for an example of the code that might cause this asynchrony. @@ -6778,7 +7079,10 @@ ExprResult Sema::ActOnFinishFullExpr(Expr *FE, SourceLocation CC, // constructor/destructor. // - Teach the handful of places that iterate over FunctionScopes to // stop at the outermost enclosing lexical scope." - const bool IsInLambdaDeclContext = isLambdaCallOperator(CurContext); + DeclContext *DC = CurContext; + while (DC && isa<CapturedDecl>(DC)) + DC = DC->getParent(); + const bool IsInLambdaDeclContext = isLambdaCallOperator(DC); if (IsInLambdaDeclContext && CurrentLSI && CurrentLSI->hasPotentialCaptures() && !FullExpr.isInvalid()) CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(FE, CurrentLSI, diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp index 9c345f8..2836218 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 c1fb906..8f0d4ff 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 c3a8946..060ee3e 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 884add2..0b3af26 100644 --- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp +++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp @@ -66,17 +66,20 @@ getStackIndexOfNearestEnclosingCaptureReadyLambda( // Label failure to capture. const Optional<unsigned> NoLambdaIsCaptureReady; + // Ignore all inner captured regions. + unsigned CurScopeIndex = FunctionScopes.size() - 1; + while (CurScopeIndex > 0 && isa<clang::sema::CapturedRegionScopeInfo>( + FunctionScopes[CurScopeIndex])) + --CurScopeIndex; assert( - isa<clang::sema::LambdaScopeInfo>( - FunctionScopes[FunctionScopes.size() - 1]) && + isa<clang::sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex]) && "The function on the top of sema's function-info stack must be a lambda"); - + // If VarToCapture is null, we are attempting to capture 'this'. const bool IsCapturingThis = !VarToCapture; const bool IsCapturingVariable = !IsCapturingThis; // Start with the current lambda at the top of the stack (highest index). - unsigned CurScopeIndex = FunctionScopes.size() - 1; DeclContext *EnclosingDC = cast<sema::LambdaScopeInfo>(FunctionScopes[CurScopeIndex])->CallOperator; @@ -311,18 +314,21 @@ Sema::getCurrentMangleNumberContext(const DeclContext *DC, bool IsInNonspecializedTemplate = !ActiveTemplateInstantiations.empty() || CurContext->isDependentContext(); switch (Kind) { - case Normal: + case Normal: { // -- the bodies of non-exported nonspecialized template functions // -- the bodies of inline functions if ((IsInNonspecializedTemplate && !(ManglingContextDecl && isa<ParmVarDecl>(ManglingContextDecl))) || isInInlineFunction(CurContext)) { ManglingContextDecl = nullptr; + while (auto *CD = dyn_cast<CapturedDecl>(DC)) + DC = CD->getParent(); return &Context.getManglingNumberContext(DC); } ManglingContextDecl = nullptr; return nullptr; + } case StaticDataMember: // -- the initializers of nonspecialized static members of template classes @@ -414,11 +420,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 +622,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 +814,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; @@ -922,7 +923,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 +940,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 +961,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 +1154,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 +1503,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 +1513,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 +1537,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 +1594,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, @@ -1619,6 +1627,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc, ExprEvalContexts.back().Lambdas.push_back(Lambda); break; + case DiscardedStatement: case PotentiallyEvaluated: case PotentiallyEvaluatedIfUsed: break; @@ -1697,7 +1706,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 45dc2e3..e255082 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 1cb84e4..5e38751 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 0d51ee1..b7ac485 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(); - Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get()); + 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()); + } 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 && VDDef->hasInit()) { 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)) { + if (CheckOpenMPLinearDecl(D, ELoc, LinKind, 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); - 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,969 @@ 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; + } + // Check if the extra components of the expressions in the enclosing + // data environment are redundant for the current base declaration. + // If they are, the maps completely overlap, which is legal. + for (; SI != SE; ++SI) { + QualType Type; + if (auto *ASE = + dyn_cast<ArraySubscriptExpr>(SI->getAssociatedExpression())) { + Type = ASE->getBase()->IgnoreParenImpCasts()->getType(); + } else if (auto *OASE = + dyn_cast<OMPArraySectionExpr>(SI->getAssociatedExpression())) { + auto *E = OASE->getBase()->IgnoreParenImpCasts(); + Type = + OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType(); + } + if (Type.isNull() || Type->isAnyPointerType() || + CheckArrayExpressionDoesNotReferToWholeSize( + SemaRef, SI->getAssociatedExpression(), Type)) + 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 +11365,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 d6a0ff7..40d6e91 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,32 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, SFINAETrap Trap(*this); SmallVector<Expr *, 16> ConvertedArgs; bool InitializationFailed = false; - bool ContainsValueDependentExpr = false; + + // Ignore any variadic parameters. Converting them is pointless, since the + // user can't refer to them in the enable_if condition. + unsigned ArgSizeNoVarargs = std::min(Function->param_size(), Args.size()); // Convert the arguments. - for (unsigned i = 0, e = Args.size(); i != e; ++i) { - if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) && + for (unsigned I = 0; I != ArgSizeNoVarargs; ++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 +6019,6 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args, InitializationFailed = true; break; } - ContainsValueDependentExpr |= R.get()->isValueDependent(); ConvertedArgs.push_back(R.get()); } @@ -6012,18 +6028,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 +6826,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 +6926,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 +6994,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 +7200,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 +7217,7 @@ class BuiltinOperatorOverloadBuilder { &ASTContext::FloatTy, &ASTContext::DoubleTy, &ASTContext::LongDoubleTy, + &ASTContext::Float128Ty, // Start of integral types. &ASTContext::IntTy, @@ -7246,7 +7260,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 +8490,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 +8522,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 +8537,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 +8650,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 +8770,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 +8817,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 +8860,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 +8877,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 +8915,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 +8960,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 +8995,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 +9024,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 +9052,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 +9077,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 +9095,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 +9108,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 +9126,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 +9137,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 +9148,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 +9175,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 +9186,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 +9197,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 +9243,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 +9255,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 +9268,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 +9290,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 +9324,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 +9355,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 +9366,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 +9402,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 +9427,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 +9446,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 +9469,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 +9518,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 +9590,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 +9604,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 +9617,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 +9695,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 +9717,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 +9741,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 +9789,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 +9818,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 +10186,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 +10349,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 +10439,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 +10447,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 +10487,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 +10555,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 +10606,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 +10719,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 +10842,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 +12407,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 +13024,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 e5d51f1..c93d800 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 e1b1a47..8e8104e 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 11a4f8b..cd4269c 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 984bd07..87fd889 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 138cee0..72e4993 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; } @@ -3214,13 +3256,12 @@ SubstDefaultTemplateArgument(Sema &SemaRef, // on the previously-computed template arguments. if (ArgType->getType()->isDependentType()) { Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted, + Param, Template, Converted, SourceRange(TemplateLoc, RAngleLoc)); 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; @@ -3267,13 +3308,12 @@ SubstDefaultTemplateArgument(Sema &SemaRef, NonTypeTemplateParmDecl *Param, SmallVectorImpl<TemplateArgument> &Converted) { Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, - Template, Converted, + Param, Template, Converted, SourceRange(TemplateLoc, RAngleLoc)); 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; @@ -3319,13 +3359,13 @@ SubstDefaultTemplateArgument(Sema &SemaRef, TemplateTemplateParmDecl *Param, SmallVectorImpl<TemplateArgument> &Converted, NestedNameSpecifierLoc &QualifierLoc) { - Sema::InstantiatingTemplate Inst(SemaRef, TemplateLoc, Template, Converted, - SourceRange(TemplateLoc, RAngleLoc)); + Sema::InstantiatingTemplate Inst( + SemaRef, TemplateLoc, TemplateParameter(Param), Template, Converted, + SourceRange(TemplateLoc, RAngleLoc)); 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 +3516,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 +3656,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 +3767,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; } @@ -3943,7 +3982,9 @@ bool Sema::CheckTemplateArgumentList(TemplateDecl *Template, } // Introduce an instantiation record that describes where we are using - // the default template argument. + // the default template argument. We're not actually instantiating a + // template here, we just create this object to put a note into the + // context stack. InstantiatingTemplate Inst(*this, RAngleLoc, Template, *Param, Converted, SourceRange(TemplateLoc, RAngleLoc)); if (Inst.isInvalid()) @@ -4014,7 +4055,7 @@ namespace { bool VisitTagDecl(const TagDecl *Tag); bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS); }; -} +} // end anonymous namespace bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) { return false; @@ -4229,7 +4270,6 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier( llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); } - /// \brief Check a template argument against its corresponding /// template type parameter. /// @@ -5340,10 +5380,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 +6322,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 +6355,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 +6386,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec, KWLoc, TemplateNameLoc, TemplateParams, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, TemplateArgs, CanonType, PrevPartial); @@ -6404,8 +6441,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 +6459,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 +6915,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 +6948,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 +7006,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 +7062,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 +7078,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 +7091,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 +7100,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 +7109,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 +7138,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) { } Previous.clear(); - Previous.addDecl(Instantiation); + Previous.addDecl(FoundInstantiation); return false; } @@ -7119,6 +7185,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 +7239,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 +7341,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 +7394,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 +7470,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 +7486,7 @@ Sema::ActOnExplicitInstantiation(Scope *S, ClassTemplate->getDeclContext(), KWLoc, TemplateNameLoc, ClassTemplate, - Converted.data(), - Converted.size(), + Converted, PrevDecl); SetNestedNameSpecifier(Specialization, SS); @@ -7405,7 +7512,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 +7552,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 +7569,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 +7786,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 +7866,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 +7987,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 +8089,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 +8435,7 @@ namespace { return E; } }; -} +} // end anonymous namespace /// \brief Rebuilds a type within the context of the current instantiation. /// @@ -8469,3 +8610,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 71faafc..5740bc7 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 fb7fc10..65a5633 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" @@ -224,6 +225,10 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( Inst.NumTemplateArgs = TemplateArgs.size(); Inst.DeductionInfo = DeductionInfo; Inst.InstantiationRange = InstantiationRange; + AlreadyInstantiating = + !SemaRef.InstantiatingSpecializations + .insert(std::make_pair(Inst.Entity->getCanonicalDecl(), Inst.Kind)) + .second; SemaRef.InNonInstantiationSFINAEContext = false; SemaRef.ActiveTemplateInstantiations.push_back(Inst); if (!Inst.isInstantiationRecord()) @@ -246,13 +251,14 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( PointOfInstantiation, InstantiationRange, Entity) {} Sema::InstantiatingTemplate::InstantiatingTemplate( - Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateDecl *Template, - ArrayRef<TemplateArgument> TemplateArgs, SourceRange InstantiationRange) + Sema &SemaRef, SourceLocation PointOfInstantiation, TemplateParameter Param, + TemplateDecl *Template, ArrayRef<TemplateArgument> TemplateArgs, + SourceRange InstantiationRange) : InstantiatingTemplate( SemaRef, ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation, - PointOfInstantiation, InstantiationRange, Template, nullptr, - TemplateArgs) {} + PointOfInstantiation, InstantiationRange, getAsNamedDecl(Param), + Template, TemplateArgs) {} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -262,7 +268,11 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( sema::TemplateDeductionInfo &DeductionInfo, SourceRange InstantiationRange) : InstantiatingTemplate(SemaRef, Kind, PointOfInstantiation, InstantiationRange, FunctionTemplate, nullptr, - TemplateArgs, &DeductionInfo) {} + TemplateArgs, &DeductionInfo) { + assert( + Kind == ActiveTemplateInstantiation::ExplicitTemplateArgumentSubstitution || + Kind == ActiveTemplateInstantiation::DeducedTemplateArgumentSubstitution); +} Sema::InstantiatingTemplate::InstantiatingTemplate( Sema &SemaRef, SourceLocation PointOfInstantiation, @@ -326,7 +336,8 @@ Sema::InstantiatingTemplate::InstantiatingTemplate( void Sema::InstantiatingTemplate::Clear() { if (!Invalid) { - if (!SemaRef.ActiveTemplateInstantiations.back().isInstantiationRecord()) { + auto &Active = SemaRef.ActiveTemplateInstantiations.back(); + if (!Active.isInstantiationRecord()) { assert(SemaRef.NonInstantiationEntries > 0); --SemaRef.NonInstantiationEntries; } @@ -344,6 +355,10 @@ void Sema::InstantiatingTemplate::Clear() { SemaRef.ActiveTemplateInstantiationLookupModules.pop_back(); } + if (!AlreadyInstantiating) + SemaRef.InstantiatingSpecializations.erase( + std::make_pair(Active.Entity, Active.Kind)); + SemaRef.ActiveTemplateInstantiations.pop_back(); Invalid = true; } @@ -442,14 +457,12 @@ void Sema::PrintInstantiationStack() { } case ActiveTemplateInstantiation::DefaultTemplateArgumentInstantiation: { - TemplateDecl *Template = cast<TemplateDecl>(Active->Entity); + TemplateDecl *Template = cast<TemplateDecl>(Active->Template); 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 +513,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 +740,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 +1528,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 +1537,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 +1562,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 +1724,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 +1868,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 +1964,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + assert(!Inst.isAlreadyInstantiating() && "should have been caught by caller"); + 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 +1980,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 +2072,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 +2105,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 +2190,10 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation, InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + if (Inst.isAlreadyInstantiating()) + return false; + 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 +2266,14 @@ bool Sema::InstantiateInClassInitializer( InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation); if (Inst.isInvalid()) return true; + if (Inst.isAlreadyInstantiating()) { + // Error out if we hit an instantiation cycle for this initializer. + Diag(PointOfInstantiation, diag::err_in_class_initializer_cycle) + << Instantiation; + 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 +2345,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 +2539,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 +2565,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 +2633,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 +2653,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 7a452af..dd3748f 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; } @@ -3205,6 +3360,13 @@ void Sema::InstantiateExceptionSpec(SourceLocation PointOfInstantiation, UpdateExceptionSpec(Decl, EST_None); return; } + if (Inst.isAlreadyInstantiating()) { + // This exception specification indirectly depends on itself. Reject. + // FIXME: Corresponding rule in the standard? + Diag(PointOfInstantiation, diag::err_exception_spec_cycle) << Decl; + UpdateExceptionSpec(Decl, EST_None); + return; + } // Enter the scope of this instantiation. We don't use // PushDeclContext because we don't have a scope. @@ -3347,7 +3509,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 +3564,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 +3588,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; @@ -3449,8 +3626,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Function); - if (Inst.isInvalid()) + if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) return; + PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(), + "instantiating function definition"); // Copy the inner loc start from the pattern. Function->setInnerLocStart(PatternDecl->getInnerLocStart()); @@ -3681,11 +3860,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,10 +3881,13 @@ void Sema::BuildVariableInstantiation( void Sema::InstantiateVariableInitializer( VarDecl *Var, VarDecl *OldVar, const MultiLevelTemplateArgumentList &TemplateArgs) { - - if (Var->getAnyInitializer()) - // We already have an initializer in the class. - return; + // 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 (OldVar->getInit()) { if (Var->isStaticDataMember() && !OldVar->isOutOfLine()) @@ -3713,9 +3896,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(); @@ -3736,9 +3924,23 @@ void Sema::InstantiateVariableInitializer( } PopExpressionEvaluationContext(); - } else if ((!Var->isStaticDataMember() || Var->isOutOfLine()) && - !Var->isCXXForRangeDecl()) + } else { + if (Var->isStaticDataMember()) { + if (!Var->isOutOfLine()) + return; + + // If the declaration inside the class had an initializer, don't add + // another one to the out-of-line definition. + if (OldVar->getFirstDecl()->hasInit()) + return; + } + + // We'll add an initializer to a for-range declaration later. + if (Var->isCXXForRangeDecl()) + return; + ActOnUninitializedDecl(Var, false); + } } /// \brief Instantiate the definition of the given variable from its @@ -3768,7 +3970,7 @@ void Sema::InstantiateStaticDataMemberDefinition( void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, VarDecl *Var, bool Recursive, - bool DefinitionRequired) { + bool DefinitionRequired, bool AtEndOfTU) { if (Var->isInvalidDecl()) return; @@ -3828,8 +4030,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, // FIXME: Factor out the duplicated instantiation context setup/tear down // code here. InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid()) + if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) 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 +4080,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 +4108,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; @@ -3941,8 +4159,10 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation, } InstantiatingTemplate Inst(*this, PointOfInstantiation, Var); - if (Inst.isInvalid()) + if (Inst.isInvalid() || Inst.isAlreadyInstantiating()) 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 +4178,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 +4889,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 +4933,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 cb67d71..06afe87 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 f6ad132..f3747ea 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 935304f..7224eef 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 @@ -9953,7 +10257,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 +11110,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 +11351,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 be99540..340b7fa 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 82844b3..3828218 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. // //===----------------------------------------------------------------------===// |