aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm/tools/clang/lib/Sema
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2016-08-16 21:17:51 +0000
committerDimitry Andric <dim@FreeBSD.org>2016-08-16 21:17:51 +0000
commite7145dcb9f6563389ebbfa0572ef7589bdd94b1b (patch)
treeb1b30c4998f6e9769784be87d402e4f8db13e34d /contrib/llvm/tools/clang/lib/Sema
parent3ca95b020283db6244cab92ede73c969253b6a31 (diff)
parent7fd6ba58d980ec2bf312a80444948501dd27d020 (diff)
Update clang to release_39 branch r276489, and resolve conflicts.
Notes
Notes: svn path=/projects/clang390-import/; revision=304241
Diffstat (limited to 'contrib/llvm/tools/clang/lib/Sema')
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp65
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp16
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp2
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp328
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp7
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/Scope.cpp8
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp13
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/Sema.cpp120
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp51
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp275
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp320
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp35
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp182
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp1891
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp67
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp4
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp1577
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp814
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp1414
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp228
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp17
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp808
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp542
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp83
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp215
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp571
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp94
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp299
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp316
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp6506
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp648
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp5
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp404
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp102
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp446
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp449
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp108
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp406
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp20
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/SemaType.cpp504
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TreeTransform.h750
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp36
-rw-r--r--contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h2
46 files changed, 14559 insertions, 6216 deletions
diff --git a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
index 5f74343fbd95..67762bde3439 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/AnalysisBasedWarnings.cpp
@@ -889,7 +889,7 @@ static bool DiagnoseUninitializedUse(Sema &S, const VarDecl *VD,
// the initializer of that declaration & we didn't already suggest
// an initialization fixit.
if (!SuggestInitializationFixit(S, VD))
- S.Diag(VD->getLocStart(), diag::note_uninit_var_def)
+ S.Diag(VD->getLocStart(), diag::note_var_declared_here)
<< VD->getDeclName();
return true;
@@ -1071,6 +1071,34 @@ namespace {
};
} // anonymous namespace
+static StringRef getFallthroughAttrSpelling(Preprocessor &PP,
+ SourceLocation Loc) {
+ TokenValue FallthroughTokens[] = {
+ tok::l_square, tok::l_square,
+ PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+
+ TokenValue ClangFallthroughTokens[] = {
+ tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
+ tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
+ tok::r_square, tok::r_square
+ };
+
+ bool PreferClangAttr = !PP.getLangOpts().CPlusPlus1z;
+
+ StringRef MacroName;
+ if (PreferClangAttr)
+ MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
+ if (MacroName.empty())
+ MacroName = PP.getLastMacroWithSpelling(Loc, FallthroughTokens);
+ if (MacroName.empty() && !PreferClangAttr)
+ MacroName = PP.getLastMacroWithSpelling(Loc, ClangFallthroughTokens);
+ if (MacroName.empty())
+ MacroName = PreferClangAttr ? "[[clang::fallthrough]]" : "[[fallthrough]]";
+ return MacroName;
+}
+
static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
bool PerFunction) {
// Only perform this analysis when using C++11. There is no good workflow
@@ -1129,15 +1157,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
if (!(B->empty() && Term && isa<BreakStmt>(Term))) {
Preprocessor &PP = S.getPreprocessor();
- TokenValue Tokens[] = {
- tok::l_square, tok::l_square, PP.getIdentifierInfo("clang"),
- tok::coloncolon, PP.getIdentifierInfo("fallthrough"),
- tok::r_square, tok::r_square
- };
- StringRef AnnotationSpelling = "[[clang::fallthrough]]";
- StringRef MacroName = PP.getLastMacroWithSpelling(L, Tokens);
- if (!MacroName.empty())
- AnnotationSpelling = MacroName;
+ StringRef AnnotationSpelling = getFallthroughAttrSpelling(PP, L);
SmallString<64> TextToInsert(AnnotationSpelling);
TextToInsert += "; ";
S.Diag(L, diag::note_insert_fallthrough_fixit) <<
@@ -1151,7 +1171,7 @@ static void DiagnoseSwitchLabelsFallthrough(Sema &S, AnalysisDeclContext &AC,
}
for (const auto *F : FM.getFallthroughStmts())
- S.Diag(F->getLocStart(), diag::warn_fallthrough_attr_invalid_placement);
+ S.Diag(F->getLocStart(), diag::err_fallthrough_attr_invalid_placement);
}
static bool isInLoop(const ASTContext &Ctx, const ParentMap &PM,
@@ -1302,21 +1322,27 @@ static void diagnoseRepeatedUseOfWeak(Sema &S,
Ivar
} ObjectKind;
- const NamedDecl *D = Key.getProperty();
- if (isa<VarDecl>(D))
+ const NamedDecl *KeyProp = Key.getProperty();
+ if (isa<VarDecl>(KeyProp))
ObjectKind = Variable;
- else if (isa<ObjCPropertyDecl>(D))
+ else if (isa<ObjCPropertyDecl>(KeyProp))
ObjectKind = Property;
- else if (isa<ObjCMethodDecl>(D))
+ else if (isa<ObjCMethodDecl>(KeyProp))
ObjectKind = ImplicitProperty;
- else if (isa<ObjCIvarDecl>(D))
+ else if (isa<ObjCIvarDecl>(KeyProp))
ObjectKind = Ivar;
else
llvm_unreachable("Unexpected weak object kind!");
+ // Do not warn about IBOutlet weak property receivers being set to null
+ // since they are typically only used from the main thread.
+ if (const ObjCPropertyDecl *Prop = dyn_cast<ObjCPropertyDecl>(KeyProp))
+ if (Prop->hasAttr<IBOutletAttr>())
+ continue;
+
// Show the first time the object was read.
S.Diag(FirstRead->getLocStart(), DiagKind)
- << int(ObjectKind) << D << int(FunctionKind)
+ << int(ObjectKind) << KeyProp << int(FunctionKind)
<< FirstRead->getSourceRange();
// Print all the other accesses as notes.
@@ -1871,7 +1897,7 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
if (cast<DeclContext>(D)->isDependentContext())
return;
- if (Diags.hasUncompilableErrorOccurred() || Diags.hasFatalErrorOccurred()) {
+ if (Diags.hasUncompilableErrorOccurred()) {
// Flush out any possibly unreachable diagnostics.
flushDiagnostics(S, fscope);
return;
@@ -2038,7 +2064,8 @@ AnalysisBasedWarnings::IssueWarnings(sema::AnalysisBasedWarnings::Policy P,
!Diags.isIgnored(diag::warn_unannotated_fallthrough, D->getLocStart());
bool FallThroughDiagPerFunction = !Diags.isIgnored(
diag::warn_unannotated_fallthrough_per_function, D->getLocStart());
- if (FallThroughDiagFull || FallThroughDiagPerFunction) {
+ if (FallThroughDiagFull || FallThroughDiagPerFunction ||
+ fscope->HasFallthroughStmt) {
DiagnoseSwitchLabelsFallthrough(S, AC, !FallThroughDiagFull);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
index 3c61c95ad8ec..cae9393f9f3a 100644
--- a/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/AttributeList.cpp
@@ -159,6 +159,7 @@ struct ParsedAttrInfo {
unsigned HasCustomParsing : 1;
unsigned IsTargetSpecific : 1;
unsigned IsType : 1;
+ unsigned IsStmt : 1;
unsigned IsKnownToGCC : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
@@ -204,6 +205,10 @@ bool AttributeList::isTypeAttr() const {
return getInfo(*this).IsType;
}
+bool AttributeList::isStmtAttr() const {
+ return getInfo(*this).IsStmt;
+}
+
bool AttributeList::existsInTarget(const TargetInfo &Target) const {
return getInfo(*this).ExistsInTarget(Target);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp
index 18e9a5911641..9a4f0d921bf4 100644
--- a/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/CodeCompleteConsumer.cpp
@@ -309,7 +309,7 @@ StringRef CodeCompletionTUInfo::getParentName(const DeclContext *DC) {
if (!Interface) {
// Assign an empty StringRef but with non-null data to distinguish
// between empty because we didn't process the DeclContext yet.
- CachedParentName = StringRef((const char *)~0U, 0);
+ CachedParentName = StringRef((const char *)(uintptr_t)~0U, 0);
return StringRef();
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
index 6f6c4ca5848f..b9d2843b0558 100644
--- a/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/DeclSpec.cpp
@@ -15,10 +15,10 @@
#include "clang/AST/ASTContext.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/Expr.h"
+#include "clang/AST/LocInfoType.h"
#include "clang/AST/TypeLoc.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Basic/TargetInfo.h"
-#include "clang/Sema/LocInfoType.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -289,6 +289,7 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_decimal32:
case TST_decimal64:
case TST_double:
+ case TST_float128:
case TST_enum:
case TST_error:
case TST_float:
@@ -302,6 +303,8 @@ bool Declarator::isDeclarationOfFunction() const {
case TST_unspecified:
case TST_void:
case TST_wchar:
+#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
+#include "clang/Basic/OpenCLImageTypes.def"
return false;
case TST_decltype_auto:
@@ -455,6 +458,7 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_half: return "half";
case DeclSpec::TST_float: return "float";
case DeclSpec::TST_double: return "double";
+ case DeclSpec::TST_float128: return "__float128";
case DeclSpec::TST_bool: return Policy.Bool ? "bool" : "_Bool";
case DeclSpec::TST_decimal32: return "_Decimal32";
case DeclSpec::TST_decimal64: return "_Decimal64";
@@ -474,6 +478,10 @@ const char *DeclSpec::getSpecifierName(DeclSpec::TST T,
case DeclSpec::TST_underlyingType: return "__underlying_type";
case DeclSpec::TST_unknown_anytype: return "__unknown_anytype";
case DeclSpec::TST_atomic: return "_Atomic";
+#define GENERIC_IMAGE_TYPE(ImgType, Id) \
+ case DeclSpec::TST_##ImgType##_t: \
+ return #ImgType "_t";
+#include "clang/Basic/OpenCLImageTypes.def"
case DeclSpec::TST_error: return "(error)";
}
llvm_unreachable("Unknown typespec!");
@@ -486,6 +494,7 @@ const char *DeclSpec::getSpecifierName(TQ T) {
case DeclSpec::TQ_restrict: return "restrict";
case DeclSpec::TQ_volatile: return "volatile";
case DeclSpec::TQ_atomic: return "_Atomic";
+ case DeclSpec::TQ_unaligned: return "__unaligned";
}
llvm_unreachable("Unknown typespec!");
}
@@ -787,6 +796,7 @@ bool DeclSpec::SetTypeQual(TQ T, SourceLocation Loc, const char *&PrevSpec,
case TQ_const: TQ_constLoc = Loc; return false;
case TQ_restrict: TQ_restrictLoc = Loc; return false;
case TQ_volatile: TQ_volatileLoc = Loc; return false;
+ case TQ_unaligned: TQ_unalignedLoc = Loc; return false;
case TQ_atomic: TQ_atomicLoc = Loc; return false;
}
@@ -953,10 +963,10 @@ void DeclSpec::Finish(Sema &S, const PrintingPolicy &Policy) {
TypeSpecSign != TSS_unspecified ||
TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool ||
TypeQualifiers)) {
- const unsigned NumLocs = 8;
+ const unsigned NumLocs = 9;
SourceLocation ExtraLocs[NumLocs] = {
TSWLoc, TSCLoc, TSSLoc, AltiVecLoc,
- TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc
+ TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc, TQ_unalignedLoc
};
FixItHint Hints[NumLocs];
SourceLocation FirstLoc;
diff --git a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp
index 53263bac546f..0bdb19490bc5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/IdentifierResolver.cpp
@@ -381,7 +381,7 @@ void IdentifierResolver::updatingIdentifier(IdentifierInfo &II) {
PP.getExternalSource()->updateOutOfDateIdentifier(II);
if (II.isFromAST())
- II.setChangedSinceDeserialization();
+ II.setFETokenInfoChangedSinceDeserialization();
}
//===----------------------------------------------------------------------===//
diff --git a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
index c394d24d5fdc..bdbe06c4969d 100644
--- a/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/JumpDiagnostics.cpp
@@ -270,7 +270,8 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
/// coherent VLA scope with a specified parent node. Walk through the
/// statements, adding any labels or gotos to LabelAndGotoScopes and recursively
/// walking the AST as needed.
-void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope) {
+void JumpScopeChecker::BuildScopeInformation(Stmt *S,
+ unsigned &origParentScope) {
// If this is a statement, rather than an expression, scopes within it don't
// propagate out into the enclosing scope. Otherwise we have to worry
// about block literals, which have the lifetime of their enclosing statement.
@@ -278,7 +279,7 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
unsigned &ParentScope = ((isa<Expr>(S) && !isa<StmtExpr>(S))
? origParentScope : independentParentScope);
- bool SkipFirstSubStmt = false;
+ unsigned StmtsToSkip = 0u;
// If we found a label, remember that it is in ParentScope scope.
switch (S->getStmtClass()) {
@@ -303,11 +304,15 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
break;
case Stmt::SwitchStmtClass:
- // Evaluate the condition variable before entering the scope of the switch
- // statement.
+ // Evaluate the C++17 init stmt and condition variable
+ // before entering the scope of the switch statement.
+ if (Stmt *Init = cast<SwitchStmt>(S)->getInit()) {
+ BuildScopeInformation(Init, ParentScope);
+ ++StmtsToSkip;
+ }
if (VarDecl *Var = cast<SwitchStmt>(S)->getConditionVariable()) {
BuildScopeInformation(Var, ParentScope);
- SkipFirstSubStmt = true;
+ ++StmtsToSkip;
}
// Fall through
@@ -318,199 +323,248 @@ void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned &origParentScope)
Jumps.push_back(S);
break;
+ case Stmt::IfStmtClass: {
+ IfStmt *IS = cast<IfStmt>(S);
+ if (!IS->isConstexpr())
+ break;
+
+ if (VarDecl *Var = IS->getConditionVariable())
+ BuildScopeInformation(Var, ParentScope);
+
+ // Cannot jump into the middle of the condition.
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_constexpr_if, 0,
+ IS->getLocStart()));
+ BuildScopeInformation(IS->getCond(), NewParentScope);
+
+ // Jumps into either arm of an 'if constexpr' are not allowed.
+ NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_constexpr_if, 0,
+ IS->getLocStart()));
+ BuildScopeInformation(IS->getThen(), NewParentScope);
+ if (Stmt *Else = IS->getElse()) {
+ NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_constexpr_if, 0,
+ IS->getLocStart()));
+ BuildScopeInformation(Else, NewParentScope);
+ }
+ return;
+ }
+
case Stmt::CXXTryStmtClass: {
CXXTryStmt *TS = cast<CXXTryStmt>(S);
- unsigned newParentScope;
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_cxx_try,
- diag::note_exits_cxx_try,
- TS->getSourceRange().getBegin()));
- if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
+ {
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_cxx_try,
+ diag::note_exits_cxx_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, NewParentScope);
+ }
// Jump from the catch into the try is not allowed either.
for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) {
CXXCatchStmt *CS = TS->getHandler(I);
+ unsigned NewParentScope = Scopes.size();
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_cxx_catch,
diag::note_exits_cxx_catch,
CS->getSourceRange().getBegin()));
- BuildScopeInformation(CS->getHandlerBlock(),
- (newParentScope = Scopes.size()-1));
+ BuildScopeInformation(CS->getHandlerBlock(), NewParentScope);
}
return;
}
case Stmt::SEHTryStmtClass: {
SEHTryStmt *TS = cast<SEHTryStmt>(S);
- unsigned newParentScope;
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_seh_try,
- diag::note_exits_seh_try,
- TS->getSourceRange().getBegin()));
- if (Stmt *TryBlock = TS->getTryBlock())
- BuildScopeInformation(TryBlock, (newParentScope = Scopes.size()-1));
+ {
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_seh_try,
+ diag::note_exits_seh_try,
+ TS->getSourceRange().getBegin()));
+ if (Stmt *TryBlock = TS->getTryBlock())
+ BuildScopeInformation(TryBlock, NewParentScope);
+ }
// Jump from __except or __finally into the __try are not allowed either.
if (SEHExceptStmt *Except = TS->getExceptHandler()) {
+ unsigned NewParentScope = Scopes.size();
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_seh_except,
diag::note_exits_seh_except,
Except->getSourceRange().getBegin()));
- BuildScopeInformation(Except->getBlock(),
- (newParentScope = Scopes.size()-1));
+ BuildScopeInformation(Except->getBlock(), NewParentScope);
} else if (SEHFinallyStmt *Finally = TS->getFinallyHandler()) {
+ unsigned NewParentScope = Scopes.size();
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_seh_finally,
diag::note_exits_seh_finally,
Finally->getSourceRange().getBegin()));
- BuildScopeInformation(Finally->getBlock(),
- (newParentScope = Scopes.size()-1));
+ BuildScopeInformation(Finally->getBlock(), NewParentScope);
}
return;
}
- default:
- break;
- }
-
- for (Stmt *SubStmt : S->children()) {
- if (SkipFirstSubStmt) {
- SkipFirstSubStmt = false;
- continue;
- }
-
- if (!SubStmt) continue;
-
- // Cases, labels, and defaults aren't "scope parents". It's also
- // important to handle these iteratively instead of recursively in
- // order to avoid blowing out the stack.
- while (true) {
- Stmt *Next;
- if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt))
- Next = CS->getSubStmt();
- else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt))
- Next = DS->getSubStmt();
- else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
- Next = LS->getSubStmt();
- else
- break;
-
- LabelAndGotoScopes[SubStmt] = ParentScope;
- SubStmt = Next;
- }
-
+ case Stmt::DeclStmtClass: {
// If this is a declstmt with a VLA definition, it defines a scope from here
// to the end of the containing context.
- if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) {
- // The decl statement creates a scope if any of the decls in it are VLAs
- // or have the cleanup attribute.
- for (auto *I : DS->decls())
- BuildScopeInformation(I, ParentScope);
- continue;
- }
+ DeclStmt *DS = cast<DeclStmt>(S);
+ // The decl statement creates a scope if any of the decls in it are VLAs
+ // or have the cleanup attribute.
+ for (auto *I : DS->decls())
+ BuildScopeInformation(I, origParentScope);
+ return;
+ }
+
+ case Stmt::ObjCAtTryStmtClass: {
// Disallow jumps into any part of an @try statement by pushing a scope and
// walking all sub-stmts in that scope.
- if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) {
- unsigned newParentScope;
- // Recursively walk the AST for the @try part.
+ ObjCAtTryStmt *AT = cast<ObjCAtTryStmt>(S);
+ // Recursively walk the AST for the @try part.
+ {
+ unsigned NewParentScope = Scopes.size();
Scopes.push_back(GotoScope(ParentScope,
diag::note_protected_by_objc_try,
diag::note_exits_objc_try,
AT->getAtTryLoc()));
if (Stmt *TryPart = AT->getTryBody())
- BuildScopeInformation(TryPart, (newParentScope = Scopes.size()-1));
-
- // Jump from the catch to the finally or try is not valid.
- for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
- ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_objc_catch,
- diag::note_exits_objc_catch,
- AC->getAtCatchLoc()));
- // @catches are nested and it isn't
- BuildScopeInformation(AC->getCatchBody(),
- (newParentScope = Scopes.size()-1));
- }
+ BuildScopeInformation(TryPart, NewParentScope);
+ }
- // Jump from the finally to the try or catch is not valid.
- if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_objc_finally,
- diag::note_exits_objc_finally,
- AF->getAtFinallyLoc()));
- BuildScopeInformation(AF, (newParentScope = Scopes.size()-1));
- }
+ // Jump from the catch to the finally or try is not valid.
+ for (unsigned I = 0, N = AT->getNumCatchStmts(); I != N; ++I) {
+ ObjCAtCatchStmt *AC = AT->getCatchStmt(I);
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_catch,
+ diag::note_exits_objc_catch,
+ AC->getAtCatchLoc()));
+ // @catches are nested and it isn't
+ BuildScopeInformation(AC->getCatchBody(), NewParentScope);
+ }
- continue;
+ // Jump from the finally to the try or catch is not valid.
+ if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) {
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_finally,
+ diag::note_exits_objc_finally,
+ AF->getAtFinallyLoc()));
+ BuildScopeInformation(AF, NewParentScope);
}
- unsigned newParentScope;
+ return;
+ }
+
+ case Stmt::ObjCAtSynchronizedStmtClass: {
// Disallow jumps into the protected statement of an @synchronized, but
// allow jumps into the object expression it protects.
- if (ObjCAtSynchronizedStmt *AS =
- dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)) {
- // Recursively walk the AST for the @synchronized object expr, it is
- // evaluated in the normal scope.
- BuildScopeInformation(AS->getSynchExpr(), ParentScope);
-
- // Recursively walk the AST for the @synchronized part, protected by a new
- // scope.
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_objc_synchronized,
- diag::note_exits_objc_synchronized,
- AS->getAtSynchronizedLoc()));
- BuildScopeInformation(AS->getSynchBody(),
- (newParentScope = Scopes.size()-1));
- continue;
- }
+ ObjCAtSynchronizedStmt *AS = cast<ObjCAtSynchronizedStmt>(S);
+ // Recursively walk the AST for the @synchronized object expr, it is
+ // evaluated in the normal scope.
+ BuildScopeInformation(AS->getSynchExpr(), ParentScope);
+
+ // Recursively walk the AST for the @synchronized part, protected by a new
+ // scope.
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_synchronized,
+ diag::note_exits_objc_synchronized,
+ AS->getAtSynchronizedLoc()));
+ BuildScopeInformation(AS->getSynchBody(), NewParentScope);
+ return;
+ }
+ case Stmt::ObjCAutoreleasePoolStmtClass: {
// Disallow jumps into the protected statement of an @autoreleasepool.
- if (ObjCAutoreleasePoolStmt *AS =
- dyn_cast<ObjCAutoreleasePoolStmt>(SubStmt)) {
- // Recursively walk the AST for the @autoreleasepool part, protected by a
- // new scope.
- Scopes.push_back(GotoScope(ParentScope,
- diag::note_protected_by_objc_autoreleasepool,
- diag::note_exits_objc_autoreleasepool,
- AS->getAtLoc()));
- BuildScopeInformation(AS->getSubStmt(),
- (newParentScope = Scopes.size() - 1));
- continue;
- }
+ ObjCAutoreleasePoolStmt *AS = cast<ObjCAutoreleasePoolStmt>(S);
+ // Recursively walk the AST for the @autoreleasepool part, protected by a
+ // new scope.
+ unsigned NewParentScope = Scopes.size();
+ Scopes.push_back(GotoScope(ParentScope,
+ diag::note_protected_by_objc_autoreleasepool,
+ diag::note_exits_objc_autoreleasepool,
+ AS->getAtLoc()));
+ BuildScopeInformation(AS->getSubStmt(), NewParentScope);
+ return;
+ }
+ case Stmt::ExprWithCleanupsClass: {
// Disallow jumps past full-expressions that use blocks with
// non-trivial cleanups of their captures. This is theoretically
// implementable but a lot of work which we haven't felt up to doing.
- if (ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(SubStmt)) {
- for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
- const BlockDecl *BDecl = EWC->getObject(i);
- for (const auto &CI : BDecl->captures()) {
- VarDecl *variable = CI.getVariable();
- BuildScopeInformation(variable, BDecl, ParentScope);
- }
+ ExprWithCleanups *EWC = cast<ExprWithCleanups>(S);
+ for (unsigned i = 0, e = EWC->getNumObjects(); i != e; ++i) {
+ const BlockDecl *BDecl = EWC->getObject(i);
+ for (const auto &CI : BDecl->captures()) {
+ VarDecl *variable = CI.getVariable();
+ BuildScopeInformation(variable, BDecl, origParentScope);
}
}
+ break;
+ }
+ case Stmt::MaterializeTemporaryExprClass: {
// Disallow jumps out of scopes containing temporaries lifetime-extended to
// automatic storage duration.
- if (MaterializeTemporaryExpr *MTE =
- dyn_cast<MaterializeTemporaryExpr>(SubStmt)) {
- if (MTE->getStorageDuration() == SD_Automatic) {
- SmallVector<const Expr *, 4> CommaLHS;
- SmallVector<SubobjectAdjustment, 4> Adjustments;
- const Expr *ExtendedObject =
- MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments(
- CommaLHS, Adjustments);
- if (ExtendedObject->getType().isDestructedType()) {
- Scopes.push_back(GotoScope(ParentScope, 0,
- diag::note_exits_temporary_dtor,
- ExtendedObject->getExprLoc()));
- ParentScope = Scopes.size()-1;
- }
+ MaterializeTemporaryExpr *MTE = cast<MaterializeTemporaryExpr>(S);
+ if (MTE->getStorageDuration() == SD_Automatic) {
+ SmallVector<const Expr *, 4> CommaLHS;
+ SmallVector<SubobjectAdjustment, 4> Adjustments;
+ const Expr *ExtendedObject =
+ MTE->GetTemporaryExpr()->skipRValueSubobjectAdjustments(
+ CommaLHS, Adjustments);
+ if (ExtendedObject->getType().isDestructedType()) {
+ Scopes.push_back(GotoScope(ParentScope, 0,
+ diag::note_exits_temporary_dtor,
+ ExtendedObject->getExprLoc()));
+ origParentScope = Scopes.size()-1;
}
}
+ break;
+ }
+
+ case Stmt::CaseStmtClass:
+ case Stmt::DefaultStmtClass:
+ case Stmt::LabelStmtClass:
+ LabelAndGotoScopes[S] = ParentScope;
+ break;
+
+ default:
+ break;
+ }
+
+ for (Stmt *SubStmt : S->children()) {
+ if (!SubStmt)
+ continue;
+ if (StmtsToSkip) {
+ --StmtsToSkip;
+ continue;
+ }
+
+ // Cases, labels, and defaults aren't "scope parents". It's also
+ // important to handle these iteratively instead of recursively in
+ // order to avoid blowing out the stack.
+ while (true) {
+ Stmt *Next;
+ if (CaseStmt *CS = dyn_cast<CaseStmt>(SubStmt))
+ Next = CS->getSubStmt();
+ else if (DefaultStmt *DS = dyn_cast<DefaultStmt>(SubStmt))
+ Next = DS->getSubStmt();
+ else if (LabelStmt *LS = dyn_cast<LabelStmt>(SubStmt))
+ Next = LS->getSubStmt();
+ else
+ break;
+
+ LabelAndGotoScopes[SubStmt] = ParentScope;
+ SubStmt = Next;
+ }
// Recursively walk the AST.
BuildScopeInformation(SubStmt, ParentScope);
diff --git a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
index 0f93421ac21b..eee4c00324ba 100644
--- a/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/MultiplexExternalSemaSource.cpp
@@ -197,6 +197,11 @@ void MultiplexExternalSemaSource::ReadMethodPool(Selector Sel) {
Sources[i]->ReadMethodPool(Sel);
}
+void MultiplexExternalSemaSource::updateOutOfDateSelector(Selector Sel) {
+ for(size_t i = 0; i < Sources.size(); ++i)
+ Sources[i]->updateOutOfDateSelector(Sel);
+}
+
void MultiplexExternalSemaSource::ReadKnownNamespaces(
SmallVectorImpl<NamespaceDecl*> &Namespaces){
for(size_t i = 0; i < Sources.size(); ++i)
@@ -204,7 +209,7 @@ void MultiplexExternalSemaSource::ReadKnownNamespaces(
}
void MultiplexExternalSemaSource::ReadUndefinedButUsed(
- llvm::DenseMap<NamedDecl*, SourceLocation> &Undefined){
+ llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {
for(size_t i = 0; i < Sources.size(); ++i)
Sources[i]->ReadUndefinedButUsed(Undefined);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp
index 7c70048acfbf..ae5b181c6728 100644
--- a/contrib/llvm/tools/clang/lib/Sema/Scope.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/Scope.cpp
@@ -18,7 +18,7 @@
using namespace clang;
-void Scope::Init(Scope *parent, unsigned flags) {
+void Scope::setFlags(Scope *parent, unsigned flags) {
AnyParent = parent;
Flags = flags;
@@ -83,6 +83,10 @@ void Scope::Init(Scope *parent, unsigned flags) {
else
incrementMSManglingNumber();
}
+}
+
+void Scope::Init(Scope *parent, unsigned flags) {
+ setFlags(parent, flags);
DeclsInScope.clear();
UsingDirectives.clear();
@@ -130,7 +134,7 @@ void Scope::mergeNRVOIntoParent() {
getParent()->addNRVOCandidate(NRVO.getPointer());
}
-void Scope::dump() const { dumpImpl(llvm::errs()); }
+LLVM_DUMP_METHOD void Scope::dump() const { dumpImpl(llvm::errs()); }
void Scope::dumpImpl(raw_ostream &OS) const {
unsigned Flags = getFlags();
diff --git a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
index cbd7ef7abb41..4b2e13e20deb 100644
--- a/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/ScopeInfo.cpp
@@ -28,6 +28,7 @@ void FunctionScopeInfo::Clear() {
HasBranchIntoScope = false;
HasIndirectGoto = false;
HasDroppedStmt = false;
+ HasOMPDeclareReductionCombiner = false;
ObjCShouldCallSuper = false;
ObjCIsDesignatedInit = false;
ObjCWarnForNoDesignatedInitChain = false;
@@ -85,11 +86,13 @@ FunctionScopeInfo::WeakObjectProfileTy::getBaseInfo(const Expr *E) {
if (BaseProp) {
D = getBestPropertyDecl(BaseProp);
- const Expr *DoubleBase = BaseProp->getBase();
- if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase))
- DoubleBase = OVE->getSourceExpr();
+ if (BaseProp->isObjectReceiver()) {
+ const Expr *DoubleBase = BaseProp->getBase();
+ if (const OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(DoubleBase))
+ DoubleBase = OVE->getSourceExpr();
- IsExact = DoubleBase->isObjCSelfExpr();
+ IsExact = DoubleBase->isObjCSelfExpr();
+ }
}
break;
}
@@ -212,7 +215,7 @@ void FunctionScopeInfo::markSafeWeakUse(const Expr *E) {
// Has there been a read from the object using this Expr?
FunctionScopeInfo::WeakUseVector::reverse_iterator ThisUse =
- std::find(Uses->second.rbegin(), Uses->second.rend(), WeakUseTy(E, true));
+ llvm::find(llvm::reverse(Uses->second), WeakUseTy(E, true));
if (ThisUse == Uses->second.rend())
return;
diff --git a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
index 39b8cc9f0c63..a242ace9f64e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/Sema.cpp
@@ -52,13 +52,14 @@ ModuleLoader &Sema::getModuleLoader() const { return PP.getModuleLoader(); }
PrintingPolicy Sema::getPrintingPolicy(const ASTContext &Context,
const Preprocessor &PP) {
PrintingPolicy Policy = Context.getPrintingPolicy();
+ // Our printing policy is copied over the ASTContext printing policy whenever
+ // a diagnostic is emitted, so recompute it.
Policy.Bool = Context.getLangOpts().Bool;
if (!Policy.Bool) {
- if (const MacroInfo *
- BoolMacro = PP.getMacroInfo(&Context.Idents.get("bool"))) {
+ if (const MacroInfo *BoolMacro = PP.getMacroInfo(Context.getBoolName())) {
Policy.Bool = BoolMacro->isObjectLike() &&
- BoolMacro->getNumTokens() == 1 &&
- BoolMacro->getReplacementToken(0).is(tok::kw__Bool);
+ BoolMacro->getNumTokens() == 1 &&
+ BoolMacro->getReplacementToken(0).is(tok::kw__Bool);
}
}
@@ -79,14 +80,15 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
Diags(PP.getDiagnostics()), SourceMgr(PP.getSourceManager()),
CollectStats(false), CodeCompleter(CodeCompleter),
CurContext(nullptr), OriginalLexicalContext(nullptr),
- PackContext(nullptr), MSStructPragmaOn(false),
+ MSStructPragmaOn(false),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
- VtorDispModeStack(1, MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
- DataSegStack(nullptr), BSSSegStack(nullptr), ConstSegStack(nullptr),
- CodeSegStack(nullptr), CurInitSeg(nullptr), VisContext(nullptr),
+ VtorDispStack(MSVtorDispAttr::Mode(LangOpts.VtorDispMode)),
+ PackStack(0), DataSegStack(nullptr), BSSSegStack(nullptr),
+ ConstSegStack(nullptr), CodeSegStack(nullptr), CurInitSeg(nullptr),
+ VisContext(nullptr),
IsBuildingRecoveryCallExpr(false),
- ExprNeedsCleanups(false), LateTemplateParser(nullptr),
+ Cleanup{}, LateTemplateParser(nullptr),
LateTemplateParserCleanup(nullptr),
OpaqueParser(nullptr), IdResolver(pp), StdInitializerList(nullptr),
CXXTypeInfoDecl(nullptr), MSVCGuidDecl(nullptr),
@@ -122,7 +124,8 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
// Tell diagnostics how to render things from the AST library.
Diags.SetArgToStringFn(&FormatASTNodeDiagnosticArgument, &Context);
- ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, false, nullptr, false);
+ ExprEvalContexts.emplace_back(PotentiallyEvaluated, 0, CleanupInfo{}, nullptr,
+ false);
FunctionScopes.push_back(new FunctionScopeInfo(Diags));
@@ -191,6 +194,11 @@ void Sema::Initialize() {
PushOnScopeChains(Context.getObjCProtocolDecl(), TUScope);
}
+ // Create the internal type for the *StringMakeConstantString builtins.
+ DeclarationName ConstantString = &Context.Idents.get("__NSConstantString");
+ if (IdResolver.begin(ConstantString) == IdResolver.end())
+ PushOnScopeChains(Context.getCFConstantStringDecl(), TUScope);
+
// Initialize Microsoft "predefined C++ types".
if (getLangOpts().MSVCCompat) {
if (getLangOpts().CPlusPlus &&
@@ -201,25 +209,17 @@ void Sema::Initialize() {
addImplicitTypedef("size_t", Context.getSizeType());
}
- // Initialize predefined OpenCL types.
+ // Initialize predefined OpenCL types and supported optional core features.
if (getLangOpts().OpenCL) {
- addImplicitTypedef("image1d_t", Context.OCLImage1dTy);
- addImplicitTypedef("image1d_array_t", Context.OCLImage1dArrayTy);
- addImplicitTypedef("image1d_buffer_t", Context.OCLImage1dBufferTy);
- addImplicitTypedef("image2d_t", Context.OCLImage2dTy);
- addImplicitTypedef("image2d_array_t", Context.OCLImage2dArrayTy);
- addImplicitTypedef("image3d_t", Context.OCLImage3dTy);
+#define OPENCLEXT(Ext) \
+ if (Context.getTargetInfo().getSupportedOpenCLOpts().is_##Ext##_supported_core( \
+ getLangOpts().OpenCLVersion)) \
+ getOpenCLOptions().Ext = 1;
+#include "clang/Basic/OpenCLExtensions.def"
+
addImplicitTypedef("sampler_t", Context.OCLSamplerTy);
addImplicitTypedef("event_t", Context.OCLEventTy);
if (getLangOpts().OpenCLVersion >= 200) {
- addImplicitTypedef("image2d_depth_t", Context.OCLImage2dDepthTy);
- addImplicitTypedef("image2d_array_depth_t",
- Context.OCLImage2dArrayDepthTy);
- addImplicitTypedef("image2d_msaa_t", Context.OCLImage2dMSAATy);
- addImplicitTypedef("image2d_array_msaa_t", Context.OCLImage2dArrayMSAATy);
- addImplicitTypedef("image2d_msaa_depth_t", Context.OCLImage2dMSAADepthTy);
- addImplicitTypedef("image2d_array_msaa_depth_t",
- Context.OCLImage2dArrayMSAADepthTy);
addImplicitTypedef("clk_event_t", Context.OCLClkEventTy);
addImplicitTypedef("queue_t", Context.OCLQueueTy);
addImplicitTypedef("ndrange_t", Context.OCLNDRangeTy);
@@ -261,7 +261,6 @@ void Sema::Initialize() {
Sema::~Sema() {
llvm::DeleteContainerSeconds(LateParsedTemplateMap);
- if (PackContext) FreePackedContext();
if (VisContext) FreeVisContext();
// Kill all the active scopes.
for (unsigned I = 1, E = FunctionScopes.size(); I != E; ++I)
@@ -470,13 +469,12 @@ static bool ShouldRemoveFromUnused(Sema *SemaRef, const DeclaratorDecl *D) {
return false;
}
-/// Obtains a sorted list of functions that are undefined but ODR-used.
+/// Obtains a sorted list of functions and variables that are undefined but
+/// ODR-used.
void Sema::getUndefinedButUsed(
SmallVectorImpl<std::pair<NamedDecl *, SourceLocation> > &Undefined) {
- for (llvm::DenseMap<NamedDecl *, SourceLocation>::iterator
- I = UndefinedButUsed.begin(), E = UndefinedButUsed.end();
- I != E; ++I) {
- NamedDecl *ND = I->first;
+ for (const auto &UndefinedUse : UndefinedButUsed) {
+ NamedDecl *ND = UndefinedUse.first;
// Ignore attributes that have become invalid.
if (ND->isInvalidDecl()) continue;
@@ -491,30 +489,15 @@ void Sema::getUndefinedButUsed(
!FD->getMostRecentDecl()->isInlined())
continue;
} else {
- if (cast<VarDecl>(ND)->hasDefinition() != VarDecl::DeclarationOnly)
+ auto *VD = cast<VarDecl>(ND);
+ if (VD->hasDefinition() != VarDecl::DeclarationOnly)
continue;
- if (ND->isExternallyVisible())
+ if (VD->isExternallyVisible() && !VD->getMostRecentDecl()->isInline())
continue;
}
- Undefined.push_back(std::make_pair(ND, I->second));
+ Undefined.push_back(std::make_pair(ND, UndefinedUse.second));
}
-
- // Sort (in order of use site) so that we're not dependent on the iteration
- // order through an llvm::DenseMap.
- SourceManager &SM = Context.getSourceManager();
- std::sort(Undefined.begin(), Undefined.end(),
- [&SM](const std::pair<NamedDecl *, SourceLocation> &l,
- const std::pair<NamedDecl *, SourceLocation> &r) {
- if (l.second.isValid() && !r.second.isValid())
- return true;
- if (!l.second.isValid() && r.second.isValid())
- return false;
- if (l.second != r.second)
- return SM.isBeforeInTranslationUnit(l.second, r.second);
- return SM.isBeforeInTranslationUnit(l.first->getLocation(),
- r.first->getLocation());
- });
}
/// checkUndefinedButUsed - Check for undefined objects with internal linkage
@@ -541,14 +524,22 @@ static void checkUndefinedButUsed(Sema &S) {
if (!ND->isExternallyVisible()) {
S.Diag(ND->getLocation(), diag::warn_undefined_internal)
<< isa<VarDecl>(ND) << ND;
- } else {
- assert(cast<FunctionDecl>(ND)->getMostRecentDecl()->isInlined() &&
+ } else if (auto *FD = dyn_cast<FunctionDecl>(ND)) {
+ (void)FD;
+ assert(FD->getMostRecentDecl()->isInlined() &&
"used object requires definition but isn't inline or internal?");
+ // FIXME: This is ill-formed; we should reject.
S.Diag(ND->getLocation(), diag::warn_undefined_inline) << ND;
+ } else {
+ assert(cast<VarDecl>(ND)->getMostRecentDecl()->isInline() &&
+ "used var requires definition but isn't inline or internal?");
+ S.Diag(ND->getLocation(), diag::err_undefined_inline_var) << ND;
}
if (I->second.isValid())
S.Diag(I->second, diag::note_used_here);
}
+
+ S.UndefinedButUsed.clear();
}
void Sema::LoadExternalWeakUndeclaredIdentifiers() {
@@ -744,6 +735,12 @@ void Sema::ActOnEndOfTranslationUnit() {
!Diags.isIgnored(diag::warn_delegating_ctor_cycle, SourceLocation()))
CheckDelegatingCtorCycles();
+ if (!Diags.hasErrorOccurred()) {
+ if (ExternalSource)
+ ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
+ checkUndefinedButUsed(*this);
+ }
+
if (TUKind == TU_Module) {
// If we are building a module, resolve all of the exported declarations
// now.
@@ -877,10 +874,6 @@ void Sema::ActOnEndOfTranslationUnit() {
}
}
- if (ExternalSource)
- ExternalSource->ReadUndefinedButUsed(UndefinedButUsed);
- checkUndefinedButUsed(*this);
-
emitAndClearUnusedLocalTypedefWarnings();
}
@@ -1260,14 +1253,14 @@ void Sema::ActOnComment(SourceRange Comment) {
ExternalSemaSource::~ExternalSemaSource() {}
void ExternalSemaSource::ReadMethodPool(Selector Sel) { }
+void ExternalSemaSource::updateOutOfDateSelector(Selector Sel) { }
void ExternalSemaSource::ReadKnownNamespaces(
SmallVectorImpl<NamespaceDecl *> &Namespaces) {
}
void ExternalSemaSource::ReadUndefinedButUsed(
- llvm::DenseMap<NamedDecl *, SourceLocation> &Undefined) {
-}
+ llvm::MapVector<NamedDecl *, SourceLocation> &Undefined) {}
void ExternalSemaSource::ReadMismatchingDeleteExpressions(llvm::MapVector<
FieldDecl *, llvm::SmallVector<std::pair<SourceLocation, bool>, 4>> &) {}
@@ -1281,10 +1274,10 @@ void PrettyDeclStackTraceEntry::print(raw_ostream &OS) const {
}
OS << Message;
- if (TheDecl && isa<NamedDecl>(TheDecl)) {
- std::string Name = cast<NamedDecl>(TheDecl)->getNameAsString();
- if (!Name.empty())
- OS << " '" << Name << '\'';
+ if (auto *ND = dyn_cast_or_null<NamedDecl>(TheDecl)) {
+ OS << " '";
+ ND->getNameForDiagnostic(OS, ND->getASTContext().getPrintingPolicy(), true);
+ OS << "'";
}
OS << '\n';
@@ -1509,7 +1502,8 @@ IdentifierInfo *Sema::getFloat128Identifier() const {
void Sema::PushCapturedRegionScope(Scope *S, CapturedDecl *CD, RecordDecl *RD,
CapturedRegionKind K) {
CapturingScopeInfo *CSI = new CapturedRegionScopeInfo(
- getDiagnostics(), S, CD, RD, CD->getContextParam(), K);
+ getDiagnostics(), S, CD, RD, CD->getContextParam(), K,
+ (getLangOpts().OpenMP && K == CR_OpenMP) ? getOpenMPNestingLevel() : 0);
CSI->ReturnType = Context.VoidTy;
FunctionScopes.push_back(CSI);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp
index e9772bc52049..98a918bd7d63 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaAccess.cpp
@@ -291,9 +291,10 @@ static AccessResult IsDerivedFromInclusive(const CXXRecordDecl *Derived,
SmallVector<const CXXRecordDecl*, 8> Queue; // actually a stack
while (true) {
- if (Derived->isDependentContext() && !Derived->hasDefinition())
+ if (Derived->isDependentContext() && !Derived->hasDefinition() &&
+ !Derived->isLambda())
return AR_dependent;
-
+
for (const auto &I : Derived->bases()) {
const CXXRecordDecl *RD;
@@ -410,14 +411,8 @@ static AccessResult MatchesFriend(Sema &S,
return AR_accessible;
if (EC.isDependent()) {
- CanQualType FriendTy
- = S.Context.getCanonicalType(S.Context.getTypeDeclType(Friend));
-
- for (EffectiveContext::record_iterator
- I = EC.Records.begin(), E = EC.Records.end(); I != E; ++I) {
- CanQualType ContextTy
- = S.Context.getCanonicalType(S.Context.getTypeDeclType(*I));
- if (MightInstantiateTo(S, ContextTy, FriendTy))
+ for (const CXXRecordDecl *Context : EC.Records) {
+ if (MightInstantiateTo(Context, Friend))
return AR_dependent;
}
}
@@ -1615,10 +1610,10 @@ Sema::AccessResult Sema::CheckDestructorAccess(SourceLocation Loc,
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ DeclAccessPair Found,
const InitializedEntity &Entity,
- AccessSpecifier Access,
bool IsCopyBindingRefToTemp) {
- if (!getLangOpts().AccessControl || Access == AS_public)
+ if (!getLangOpts().AccessControl || Found.getAccess() == AS_public)
return AR_accessible;
PartialDiagnostic PD(PDiag());
@@ -1652,17 +1647,17 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
}
- return CheckConstructorAccess(UseLoc, Constructor, Entity, Access, PD);
+ return CheckConstructorAccess(UseLoc, Constructor, Found, Entity, PD);
}
/// Checks access to a constructor.
Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
CXXConstructorDecl *Constructor,
+ DeclAccessPair Found,
const InitializedEntity &Entity,
- AccessSpecifier Access,
const PartialDiagnostic &PD) {
if (!getLangOpts().AccessControl ||
- Access == AS_public)
+ Found.getAccess() == AS_public)
return AR_accessible;
CXXRecordDecl *NamingClass = Constructor->getParent();
@@ -1670,16 +1665,28 @@ Sema::AccessResult Sema::CheckConstructorAccess(SourceLocation UseLoc,
// Initializing a base sub-object is an instance method call on an
// object of the derived class. Otherwise, we have an instance method
// call on an object of the constructed type.
+ //
+ // FIXME: If we have a parent, we're initializing the base class subobject
+ // in aggregate initialization. It's not clear whether the object class
+ // should be the base class or the derived class in that case.
CXXRecordDecl *ObjectClass;
- if (Entity.getKind() == InitializedEntity::EK_Base) {
+ if ((Entity.getKind() == InitializedEntity::EK_Base ||
+ Entity.getKind() == InitializedEntity::EK_Delegating) &&
+ !Entity.getParent()) {
ObjectClass = cast<CXXConstructorDecl>(CurContext)->getParent();
+ } else if (auto *Shadow =
+ dyn_cast<ConstructorUsingShadowDecl>(Found.getDecl())) {
+ // If we're using an inheriting constructor to construct an object,
+ // the object class is the derived class, not the base class.
+ ObjectClass = Shadow->getParent();
} else {
ObjectClass = NamingClass;
}
- AccessTarget AccessEntity(Context, AccessTarget::Member, NamingClass,
- DeclAccessPair::make(Constructor, Access),
- Context.getTypeDeclType(ObjectClass));
+ AccessTarget AccessEntity(
+ Context, AccessTarget::Member, NamingClass,
+ DeclAccessPair::make(Constructor, Found.getAccess()),
+ Context.getTypeDeclType(ObjectClass));
AccessEntity.setDiag(PD);
return CheckAccess(*this, UseLoc, AccessEntity);
@@ -1767,9 +1774,9 @@ Sema::AccessResult Sema::CheckFriendAccess(NamedDecl *target) {
// while the ParsingDeclarator is active.
EffectiveContext EC(CurContext);
switch (CheckEffectiveAccess(*this, EC, target->getLocation(), entity)) {
- case AR_accessible: return Sema::AR_accessible;
- case AR_inaccessible: return Sema::AR_inaccessible;
- case AR_dependent: return Sema::AR_dependent;
+ case ::AR_accessible: return Sema::AR_accessible;
+ case ::AR_inaccessible: return Sema::AR_inaccessible;
+ case ::AR_dependent: return Sema::AR_dependent;
}
llvm_unreachable("invalid access result");
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
index 5a29bad29f4d..0d7fba5c6709 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaAttr.cpp
@@ -25,103 +25,37 @@ using namespace clang;
// Pragma 'pack' and 'options align'
//===----------------------------------------------------------------------===//
-namespace {
- struct PackStackEntry {
- // We just use a sentinel to represent when the stack is set to mac68k
- // alignment.
- static const unsigned kMac68kAlignmentSentinel = ~0U;
-
- unsigned Alignment;
- IdentifierInfo *Name;
- };
-
- /// PragmaPackStack - Simple class to wrap the stack used by #pragma
- /// pack.
- class PragmaPackStack {
- typedef std::vector<PackStackEntry> stack_ty;
-
- /// Alignment - The current user specified alignment.
- unsigned Alignment;
-
- /// Stack - Entries in the #pragma pack stack, consisting of saved
- /// alignments and optional names.
- stack_ty Stack;
-
- public:
- PragmaPackStack() : Alignment(0) {}
-
- void setAlignment(unsigned A) { Alignment = A; }
- unsigned getAlignment() { return Alignment; }
-
- /// push - Push the current alignment onto the stack, optionally
- /// using the given \arg Name for the record, if non-zero.
- void push(IdentifierInfo *Name) {
- PackStackEntry PSE = { Alignment, Name };
- Stack.push_back(PSE);
- }
-
- /// pop - Pop a record from the stack and restore the current
- /// alignment to the previous value. If \arg Name is non-zero then
- /// the first such named record is popped, otherwise the top record
- /// is popped. Returns true if the pop succeeded.
- bool pop(IdentifierInfo *Name, bool IsReset);
- };
-} // end anonymous namespace.
-
-bool PragmaPackStack::pop(IdentifierInfo *Name, bool IsReset) {
- // If name is empty just pop top.
- if (!Name) {
- // An empty stack is a special case...
- if (Stack.empty()) {
- // If this isn't a reset, it is always an error.
- if (!IsReset)
- return false;
-
- // Otherwise, it is an error only if some alignment has been set.
- if (!Alignment)
- return false;
-
- // Otherwise, reset to the default alignment.
- Alignment = 0;
- } else {
- Alignment = Stack.back().Alignment;
- Stack.pop_back();
- }
-
- return true;
- }
-
- // Otherwise, find the named record.
- for (unsigned i = Stack.size(); i != 0; ) {
- --i;
- if (Stack[i].Name == Name) {
- // Found it, pop up to and including this record.
- Alignment = Stack[i].Alignment;
- Stack.erase(Stack.begin() + i, Stack.end());
- return true;
- }
+Sema::PragmaStackSentinelRAII::PragmaStackSentinelRAII(Sema &S,
+ StringRef SlotLabel,
+ bool ShouldAct)
+ : S(S), SlotLabel(SlotLabel), ShouldAct(ShouldAct) {
+ if (ShouldAct) {
+ S.VtorDispStack.SentinelAction(PSK_Push, SlotLabel);
+ S.DataSegStack.SentinelAction(PSK_Push, SlotLabel);
+ S.BSSSegStack.SentinelAction(PSK_Push, SlotLabel);
+ S.ConstSegStack.SentinelAction(PSK_Push, SlotLabel);
+ S.CodeSegStack.SentinelAction(PSK_Push, SlotLabel);
}
-
- return false;
}
-
-/// FreePackedContext - Deallocate and null out PackContext.
-void Sema::FreePackedContext() {
- delete static_cast<PragmaPackStack*>(PackContext);
- PackContext = nullptr;
+Sema::PragmaStackSentinelRAII::~PragmaStackSentinelRAII() {
+ if (ShouldAct) {
+ S.VtorDispStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.DataSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.BSSSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.ConstSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ S.CodeSegStack.SentinelAction(PSK_Pop, SlotLabel);
+ }
}
void Sema::AddAlignmentAttributesForRecord(RecordDecl *RD) {
- // If there is no pack context, we don't need any attributes.
- if (!PackContext)
+ // If there is no pack value, we don't need any attributes.
+ if (!PackStack.CurrentValue)
return;
- PragmaPackStack *Stack = static_cast<PragmaPackStack*>(PackContext);
-
// Otherwise, check to see if we need a max field alignment attribute.
- if (unsigned Alignment = Stack->getAlignment()) {
- if (Alignment == PackStackEntry::kMac68kAlignmentSentinel)
+ if (unsigned Alignment = PackStack.CurrentValue) {
+ if (Alignment == Sema::kMac68kAlignmentSentinel)
RD->addAttr(AlignMac68kAttr::CreateImplicit(Context));
else
RD->addAttr(MaxFieldAlignmentAttr::CreateImplicit(Context,
@@ -136,18 +70,15 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) {
// FIXME: We should merge AddAlignmentAttributesForRecord with
// AddMsStructLayoutForRecord into AddPragmaAttributesForRecord, which takes
// all active pragmas and applies them as attributes to class definitions.
- if (VtorDispModeStack.back() != getLangOpts().VtorDispMode)
+ if (VtorDispStack.CurrentValue != getLangOpts().VtorDispMode)
RD->addAttr(
- MSVtorDispAttr::CreateImplicit(Context, VtorDispModeStack.back()));
+ MSVtorDispAttr::CreateImplicit(Context, VtorDispStack.CurrentValue));
}
void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
SourceLocation PragmaLoc) {
- if (!PackContext)
- PackContext = new PragmaPackStack();
-
- PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
-
+ PragmaMsStackAction Action = Sema::PSK_Reset;
+ unsigned Alignment = 0;
switch (Kind) {
// For all targets we support native and natural are the same.
//
@@ -155,15 +86,15 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
case POAK_Native:
case POAK_Power:
case POAK_Natural:
- Context->push(nullptr);
- Context->setAlignment(0);
+ Action = Sema::PSK_Push_Set;
+ Alignment = 0;
break;
// Note that '#pragma options align=packed' is not equivalent to attribute
// packed, it has a different precedence relative to attribute aligned.
case POAK_Packed:
- Context->push(nullptr);
- Context->setAlignment(1);
+ Action = Sema::PSK_Push_Set;
+ Alignment = 1;
break;
case POAK_Mac68k:
@@ -172,24 +103,31 @@ void Sema::ActOnPragmaOptionsAlign(PragmaOptionsAlignKind Kind,
Diag(PragmaLoc, diag::err_pragma_options_align_mac68k_target_unsupported);
return;
}
- Context->push(nullptr);
- Context->setAlignment(PackStackEntry::kMac68kAlignmentSentinel);
+ Action = Sema::PSK_Push_Set;
+ Alignment = Sema::kMac68kAlignmentSentinel;
break;
case POAK_Reset:
// Reset just pops the top of the stack, or resets the current alignment to
// default.
- if (!Context->pop(nullptr, /*IsReset=*/true)) {
- Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
- << "stack empty";
+ Action = Sema::PSK_Pop;
+ if (PackStack.Stack.empty()) {
+ if (PackStack.CurrentValue) {
+ Action = Sema::PSK_Reset;
+ } else {
+ Diag(PragmaLoc, diag::warn_pragma_options_align_reset_failed)
+ << "stack empty";
+ return;
+ }
}
break;
}
+
+ PackStack.Act(PragmaLoc, Action, StringRef(), Alignment);
}
-void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
- Expr *alignment, SourceLocation PragmaLoc,
- SourceLocation LParenLoc, SourceLocation RParenLoc) {
+void Sema::ActOnPragmaPack(SourceLocation PragmaLoc, PragmaMsStackAction Action,
+ StringRef SlotLabel, Expr *alignment) {
Expr *Alignment = static_cast<Expr *>(alignment);
// If specified then alignment must be a "small" power of two.
@@ -210,87 +148,48 @@ void Sema::ActOnPragmaPack(PragmaPackKind Kind, IdentifierInfo *Name,
AlignmentVal = (unsigned) Val.getZExtValue();
}
-
- if (!PackContext)
- PackContext = new PragmaPackStack();
-
- PragmaPackStack *Context = static_cast<PragmaPackStack*>(PackContext);
-
- switch (Kind) {
- case Sema::PPK_Default: // pack([n])
- Context->setAlignment(AlignmentVal);
- break;
-
- case Sema::PPK_Show: // pack(show)
+ if (Action == Sema::PSK_Show) {
// Show the current alignment, making sure to show the right value
// for the default.
- AlignmentVal = Context->getAlignment();
// FIXME: This should come from the target.
+ AlignmentVal = PackStack.CurrentValue;
if (AlignmentVal == 0)
AlignmentVal = 8;
- if (AlignmentVal == PackStackEntry::kMac68kAlignmentSentinel)
+ if (AlignmentVal == Sema::kMac68kAlignmentSentinel)
Diag(PragmaLoc, diag::warn_pragma_pack_show) << "mac68k";
else
Diag(PragmaLoc, diag::warn_pragma_pack_show) << AlignmentVal;
- break;
-
- case Sema::PPK_Push: // pack(push [, id] [, [n])
- Context->push(Name);
- // Set the new alignment if specified.
- if (Alignment)
- Context->setAlignment(AlignmentVal);
- break;
-
- case Sema::PPK_Pop: // pack(pop [, id] [, n])
- // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
- // "#pragma pack(pop, identifier, n) is undefined"
- if (Alignment && Name)
+ }
+ // MSDN, C/C++ Preprocessor Reference > Pragma Directives > pack:
+ // "#pragma pack(pop, identifier, n) is undefined"
+ if (Action & Sema::PSK_Pop) {
+ if (Alignment && !SlotLabel.empty())
Diag(PragmaLoc, diag::warn_pragma_pack_pop_identifer_and_alignment);
-
- // Do the pop.
- if (!Context->pop(Name, /*IsReset=*/false)) {
- // If a name was specified then failure indicates the name
- // wasn't found. Otherwise failure indicates the stack was
- // empty.
- Diag(PragmaLoc, diag::warn_pragma_pop_failed)
- << "pack" << (Name ? "no record matching name" : "stack empty");
-
- // FIXME: Warn about popping named records as MSVC does.
- } else {
- // Pop succeeded, set the new alignment if specified.
- if (Alignment)
- Context->setAlignment(AlignmentVal);
- }
- break;
+ if (PackStack.Stack.empty())
+ Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "pack" << "stack empty";
}
+
+ PackStack.Act(PragmaLoc, Action, SlotLabel, AlignmentVal);
}
void Sema::ActOnPragmaMSStruct(PragmaMSStructKind Kind) {
MSStructPragmaOn = (Kind == PMSST_ON);
}
-void Sema::ActOnPragmaMSComment(PragmaMSCommentKind Kind, StringRef Arg) {
- // FIXME: Serialize this.
- switch (Kind) {
- case PCK_Unknown:
- llvm_unreachable("unexpected pragma comment kind");
- case PCK_Linker:
- Consumer.HandleLinkerOptionPragma(Arg);
- return;
- case PCK_Lib:
- Consumer.HandleDependentLibrary(Arg);
- return;
- case PCK_Compiler:
- case PCK_ExeStr:
- case PCK_User:
- return; // We ignore all of these.
- }
- llvm_unreachable("invalid pragma comment kind");
+void Sema::ActOnPragmaMSComment(SourceLocation CommentLoc,
+ PragmaMSCommentKind Kind, StringRef Arg) {
+ auto *PCD = PragmaCommentDecl::Create(
+ Context, Context.getTranslationUnitDecl(), CommentLoc, Kind, Arg);
+ Context.getTranslationUnitDecl()->addDecl(PCD);
+ Consumer.HandleTopLevelDecl(DeclGroupRef(PCD));
}
-void Sema::ActOnPragmaDetectMismatch(StringRef Name, StringRef Value) {
- // FIXME: Serialize this.
- Consumer.HandleDetectMismatch(Name, Value);
+void Sema::ActOnPragmaDetectMismatch(SourceLocation Loc, StringRef Name,
+ StringRef Value) {
+ auto *PDMD = PragmaDetectMismatchDecl::Create(
+ Context, Context.getTranslationUnitDecl(), Loc, Name, Value);
+ Context.getTranslationUnitDecl()->addDecl(PDMD);
+ Consumer.HandleTopLevelDecl(DeclGroupRef(PDMD));
}
void Sema::ActOnPragmaMSPointersToMembers(
@@ -300,29 +199,13 @@ void Sema::ActOnPragmaMSPointersToMembers(
ImplicitMSInheritanceAttrLoc = PragmaLoc;
}
-void Sema::ActOnPragmaMSVtorDisp(PragmaVtorDispKind Kind,
+void Sema::ActOnPragmaMSVtorDisp(PragmaMsStackAction Action,
SourceLocation PragmaLoc,
MSVtorDispAttr::Mode Mode) {
- switch (Kind) {
- case PVDK_Set:
- VtorDispModeStack.back() = Mode;
- break;
- case PVDK_Push:
- VtorDispModeStack.push_back(Mode);
- break;
- case PVDK_Reset:
- VtorDispModeStack.clear();
- VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
- break;
- case PVDK_Pop:
- VtorDispModeStack.pop_back();
- if (VtorDispModeStack.empty()) {
- Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
- << "stack empty";
- VtorDispModeStack.push_back(MSVtorDispAttr::Mode(LangOpts.VtorDispMode));
- }
- break;
- }
+ if (Action & PSK_Pop && VtorDispStack.Stack.empty())
+ Diag(PragmaLoc, diag::warn_pragma_pop_failed) << "vtordisp"
+ << "stack empty";
+ VtorDispStack.Act(PragmaLoc, Action, StringRef(), Mode);
}
template<typename ValueType>
@@ -331,7 +214,7 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
llvm::StringRef StackSlotLabel,
ValueType Value) {
if (Action == PSK_Reset) {
- CurrentValue = nullptr;
+ CurrentValue = DefaultValue;
return;
}
if (Action & PSK_Push)
@@ -339,8 +222,9 @@ void Sema::PragmaStack<ValueType>::Act(SourceLocation PragmaLocation,
else if (Action & PSK_Pop) {
if (!StackSlotLabel.empty()) {
// If we've got a label, try to find it and jump there.
- auto I = std::find_if(Stack.rbegin(), Stack.rend(),
- [&](const Slot &x) { return x.StackSlotLabel == StackSlotLabel; });
+ auto I = llvm::find_if(llvm::reverse(Stack), [&](const Slot &x) {
+ return x.StackSlotLabel == StackSlotLabel;
+ });
// If we found the label so pop from there.
if (I != Stack.rend()) {
CurrentValue = I->Value;
@@ -467,7 +351,8 @@ void Sema::ActOnPragmaUnused(const Token &IdTok, Scope *curScope,
if (VD->isUsed())
Diag(PragmaLoc, diag::warn_used_but_marked_unused) << Name;
- VD->addAttr(UnusedAttr::CreateImplicit(Context, IdTok.getLocation()));
+ VD->addAttr(UnusedAttr::CreateImplicit(Context, UnusedAttr::GNU_unused,
+ IdTok.getLocation()));
}
void Sema::AddCFAuditedAttribute(Decl *D) {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
index 61dfdd3f7206..90af6d5a927f 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCUDA.cpp
@@ -11,11 +11,14 @@
///
//===----------------------------------------------------------------------===//
-#include "clang/Sema/Sema.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
+#include "clang/AST/ExprCXX.h"
#include "clang/Lex/Preprocessor.h"
+#include "clang/Sema/Lookup.h"
+#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
+#include "clang/Sema/Template.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
using namespace clang;
@@ -67,33 +70,30 @@ Sema::CUDAFunctionTarget Sema::IdentifyCUDATarget(const FunctionDecl *D) {
// Ph - preference in host mode
// Pd - preference in device mode
// H - handled in (x)
-// Preferences: b-best, f-fallback, l-last resort, n-never.
+// Preferences: N:native, SS:same side, HD:host-device, WS:wrong side, --:never.
//
-// | F | T | Ph | Pd | H |
-// |----+----+----+----+-----+
-// | d | d | b | b | (b) |
-// | d | g | n | n | (a) |
-// | d | h | l | l | (e) |
-// | d | hd | f | f | (c) |
-// | g | d | b | b | (b) |
-// | g | g | n | n | (a) |
-// | g | h | l | l | (e) |
-// | g | hd | f | f | (c) |
-// | h | d | l | l | (e) |
-// | h | g | b | b | (b) |
-// | h | h | b | b | (b) |
-// | h | hd | f | f | (c) |
-// | hd | d | l | f | (d) |
-// | hd | g | f | n |(d/a)|
-// | hd | h | f | l | (d) |
-// | hd | hd | b | b | (b) |
+// | F | T | Ph | Pd | H |
+// |----+----+-----+-----+-----+
+// | d | d | N | N | (c) |
+// | d | g | -- | -- | (a) |
+// | d | h | -- | -- | (e) |
+// | d | hd | HD | HD | (b) |
+// | g | d | N | N | (c) |
+// | g | g | -- | -- | (a) |
+// | g | h | -- | -- | (e) |
+// | g | hd | HD | HD | (b) |
+// | h | d | -- | -- | (e) |
+// | h | g | N | N | (c) |
+// | h | h | N | N | (c) |
+// | h | hd | HD | HD | (b) |
+// | hd | d | WS | SS | (d) |
+// | hd | g | SS | -- |(d/a)|
+// | hd | h | SS | WS | (d) |
+// | hd | hd | HD | HD | (b) |
Sema::CUDAFunctionPreference
Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
const FunctionDecl *Callee) {
- assert(getLangOpts().CUDATargetOverloads &&
- "Should not be called w/o enabled target overloads.");
-
assert(Callee && "Callee must be valid.");
CUDAFunctionTarget CalleeTarget = IdentifyCUDATarget(Callee);
CUDAFunctionTarget CallerTarget =
@@ -111,130 +111,62 @@ Sema::IdentifyCUDAPreference(const FunctionDecl *Caller,
(CallerTarget == CFT_HostDevice && getLangOpts().CUDAIsDevice)))
return CFP_Never;
- // (b) Best case scenarios
+ // (b) Calling HostDevice is OK for everyone.
+ if (CalleeTarget == CFT_HostDevice)
+ return CFP_HostDevice;
+
+ // (c) Best case scenarios
if (CalleeTarget == CallerTarget ||
(CallerTarget == CFT_Host && CalleeTarget == CFT_Global) ||
(CallerTarget == CFT_Global && CalleeTarget == CFT_Device))
- return CFP_Best;
-
- // (c) Calling HostDevice is OK as a fallback that works for everyone.
- if (CalleeTarget == CFT_HostDevice)
- return CFP_Fallback;
-
- // Figure out what should be returned 'last resort' cases. Normally
- // those would not be allowed, but we'll consider them if
- // CUDADisableTargetCallChecks is true.
- CUDAFunctionPreference QuestionableResult =
- getLangOpts().CUDADisableTargetCallChecks ? CFP_LastResort : CFP_Never;
+ return CFP_Native;
// (d) HostDevice behavior depends on compilation mode.
if (CallerTarget == CFT_HostDevice) {
- // Calling a function that matches compilation mode is OK.
- // Calling a function from the other side is frowned upon.
- if (getLangOpts().CUDAIsDevice)
- return CalleeTarget == CFT_Device ? CFP_Fallback : QuestionableResult;
- else
- return (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)
- ? CFP_Fallback
- : QuestionableResult;
+ // It's OK to call a compilation-mode matching function from an HD one.
+ if ((getLangOpts().CUDAIsDevice && CalleeTarget == CFT_Device) ||
+ (!getLangOpts().CUDAIsDevice &&
+ (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global)))
+ return CFP_SameSide;
+
+ // Calls from HD to non-mode-matching functions (i.e., to host functions
+ // when compiling in device mode or to device functions when compiling in
+ // host mode) are allowed at the sema level, but eventually rejected if
+ // they're ever codegened. TODO: Reject said calls earlier.
+ return CFP_WrongSide;
}
// (e) Calling across device/host boundary is not something you should do.
if ((CallerTarget == CFT_Host && CalleeTarget == CFT_Device) ||
(CallerTarget == CFT_Device && CalleeTarget == CFT_Host) ||
(CallerTarget == CFT_Global && CalleeTarget == CFT_Host))
- return QuestionableResult;
+ return CFP_Never;
llvm_unreachable("All cases should've been handled by now.");
}
-bool Sema::CheckCUDATarget(const FunctionDecl *Caller,
- const FunctionDecl *Callee) {
- // With target overloads enabled, we only disallow calling
- // combinations with CFP_Never.
- if (getLangOpts().CUDATargetOverloads)
- return IdentifyCUDAPreference(Caller,Callee) == CFP_Never;
-
- // The CUDADisableTargetCallChecks short-circuits this check: we assume all
- // cross-target calls are valid.
- if (getLangOpts().CUDADisableTargetCallChecks)
- return false;
-
- CUDAFunctionTarget CallerTarget = IdentifyCUDATarget(Caller),
- CalleeTarget = IdentifyCUDATarget(Callee);
-
- // If one of the targets is invalid, the check always fails, no matter what
- // the other target is.
- if (CallerTarget == CFT_InvalidTarget || CalleeTarget == CFT_InvalidTarget)
- return true;
-
- // CUDA B.1.1 "The __device__ qualifier declares a function that is [...]
- // Callable from the device only."
- if (CallerTarget == CFT_Host && CalleeTarget == CFT_Device)
- return true;
-
- // CUDA B.1.2 "The __global__ qualifier declares a function that is [...]
- // Callable from the host only."
- // CUDA B.1.3 "The __host__ qualifier declares a function that is [...]
- // Callable from the host only."
- if ((CallerTarget == CFT_Device || CallerTarget == CFT_Global) &&
- (CalleeTarget == CFT_Host || CalleeTarget == CFT_Global))
- return true;
-
- // CUDA B.1.3 "The __device__ and __host__ qualifiers can be used together
- // however, in which case the function is compiled for both the host and the
- // device. The __CUDA_ARCH__ macro [...] can be used to differentiate code
- // paths between host and device."
- if (CallerTarget == CFT_HostDevice && CalleeTarget != CFT_HostDevice) {
- // If the caller is implicit then the check always passes.
- if (Caller->isImplicit()) return false;
-
- bool InDeviceMode = getLangOpts().CUDAIsDevice;
- if (!InDeviceMode && CalleeTarget != CFT_Host)
- return true;
- if (InDeviceMode && CalleeTarget != CFT_Device) {
- // Allow host device functions to call host functions if explicitly
- // requested.
- if (CalleeTarget == CFT_Host &&
- getLangOpts().CUDAAllowHostCallsFromHostDevice) {
- Diag(Caller->getLocation(),
- diag::warn_host_calls_from_host_device)
- << Callee->getNameAsString() << Caller->getNameAsString();
- return false;
- }
-
- return true;
- }
- }
-
- return false;
-}
-
-template <typename T, typename FetchDeclFn>
-static void EraseUnwantedCUDAMatchesImpl(Sema &S, const FunctionDecl *Caller,
- llvm::SmallVectorImpl<T> &Matches,
- FetchDeclFn FetchDecl) {
- assert(S.getLangOpts().CUDATargetOverloads &&
- "Should not be called w/o enabled target overloads.");
+template <typename T>
+static void EraseUnwantedCUDAMatchesImpl(
+ Sema &S, const FunctionDecl *Caller, llvm::SmallVectorImpl<T> &Matches,
+ std::function<const FunctionDecl *(const T &)> FetchDecl) {
if (Matches.size() <= 1)
return;
+ // Gets the CUDA function preference for a call from Caller to Match.
+ auto GetCFP = [&](const T &Match) {
+ return S.IdentifyCUDAPreference(Caller, FetchDecl(Match));
+ };
+
// Find the best call preference among the functions in Matches.
- Sema::CUDAFunctionPreference P, BestCFP = Sema::CFP_Never;
- for (auto const &Match : Matches) {
- P = S.IdentifyCUDAPreference(Caller, FetchDecl(Match));
- if (P > BestCFP)
- BestCFP = P;
- }
+ Sema::CUDAFunctionPreference BestCFP = GetCFP(*std::max_element(
+ Matches.begin(), Matches.end(),
+ [&](const T &M1, const T &M2) { return GetCFP(M1) < GetCFP(M2); }));
// Erase all functions with lower priority.
- for (unsigned I = 0, N = Matches.size(); I != N;)
- if (S.IdentifyCUDAPreference(Caller, FetchDecl(Matches[I])) < BestCFP) {
- Matches[I] = Matches[--N];
- Matches.resize(N);
- } else {
- ++I;
- }
+ Matches.erase(
+ llvm::remove_if(Matches,
+ [&](const T &Match) { return GetCFP(Match) < BestCFP; }),
+ Matches.end());
}
void Sema::EraseUnwantedCUDAMatches(const FunctionDecl *Caller,
@@ -273,12 +205,9 @@ static bool
resolveCalleeCUDATargetConflict(Sema::CUDAFunctionTarget Target1,
Sema::CUDAFunctionTarget Target2,
Sema::CUDAFunctionTarget *ResolvedTarget) {
- if (Target1 == Sema::CFT_Global && Target2 == Sema::CFT_Global) {
- // TODO: this shouldn't happen, really. Methods cannot be marked __global__.
- // Clang should detect this earlier and produce an error. Then this
- // condition can be changed to an assertion.
- return true;
- }
+ // Only free functions and static member functions may be global.
+ assert(Target1 != Sema::CFT_Global);
+ assert(Target2 != Sema::CFT_Global);
if (Target1 == Sema::CFT_HostDevice) {
*ResolvedTarget = Target2;
@@ -422,3 +351,132 @@ bool Sema::inferCUDATargetForImplicitSpecialMember(CXXRecordDecl *ClassDecl,
return false;
}
+
+bool Sema::isEmptyCudaConstructor(SourceLocation Loc, CXXConstructorDecl *CD) {
+ if (!CD->isDefined() && CD->isTemplateInstantiation())
+ InstantiateFunctionDefinition(Loc, CD->getFirstDecl());
+
+ // (E.2.3.1, CUDA 7.5) A constructor for a class type is considered
+ // empty at a point in the translation unit, if it is either a
+ // trivial constructor
+ if (CD->isTrivial())
+ return true;
+
+ // ... or it satisfies all of the following conditions:
+ // The constructor function has been defined.
+ // The constructor function has no parameters,
+ // and the function body is an empty compound statement.
+ if (!(CD->hasTrivialBody() && CD->getNumParams() == 0))
+ return false;
+
+ // Its class has no virtual functions and no virtual base classes.
+ if (CD->getParent()->isDynamicClass())
+ return false;
+
+ // The only form of initializer allowed is an empty constructor.
+ // This will recursively check all base classes and member initializers
+ if (!llvm::all_of(CD->inits(), [&](const CXXCtorInitializer *CI) {
+ if (const CXXConstructExpr *CE =
+ dyn_cast<CXXConstructExpr>(CI->getInit()))
+ return isEmptyCudaConstructor(Loc, CE->getConstructor());
+ return false;
+ }))
+ return false;
+
+ return true;
+}
+
+bool Sema::isEmptyCudaDestructor(SourceLocation Loc, CXXDestructorDecl *DD) {
+ // No destructor -> no problem.
+ if (!DD)
+ return true;
+
+ if (!DD->isDefined() && DD->isTemplateInstantiation())
+ InstantiateFunctionDefinition(Loc, DD->getFirstDecl());
+
+ // (E.2.3.1, CUDA 7.5) A destructor for a class type is considered
+ // empty at a point in the translation unit, if it is either a
+ // trivial constructor
+ if (DD->isTrivial())
+ return true;
+
+ // ... or it satisfies all of the following conditions:
+ // The destructor function has been defined.
+ // and the function body is an empty compound statement.
+ if (!DD->hasTrivialBody())
+ return false;
+
+ const CXXRecordDecl *ClassDecl = DD->getParent();
+
+ // Its class has no virtual functions and no virtual base classes.
+ if (ClassDecl->isDynamicClass())
+ return false;
+
+ // Only empty destructors are allowed. This will recursively check
+ // destructors for all base classes...
+ if (!llvm::all_of(ClassDecl->bases(), [&](const CXXBaseSpecifier &BS) {
+ if (CXXRecordDecl *RD = BS.getType()->getAsCXXRecordDecl())
+ return isEmptyCudaDestructor(Loc, RD->getDestructor());
+ return true;
+ }))
+ return false;
+
+ // ... and member fields.
+ if (!llvm::all_of(ClassDecl->fields(), [&](const FieldDecl *Field) {
+ if (CXXRecordDecl *RD = Field->getType()
+ ->getBaseElementTypeUnsafe()
+ ->getAsCXXRecordDecl())
+ return isEmptyCudaDestructor(Loc, RD->getDestructor());
+ return true;
+ }))
+ return false;
+
+ return true;
+}
+
+// With -fcuda-host-device-constexpr, an unattributed constexpr function is
+// treated as implicitly __host__ __device__, unless:
+// * it is a variadic function (device-side variadic functions are not
+// allowed), or
+// * a __device__ function with this signature was already declared, in which
+// case in which case we output an error, unless the __device__ decl is in a
+// system header, in which case we leave the constexpr function unattributed.
+void Sema::maybeAddCUDAHostDeviceAttrs(Scope *S, FunctionDecl *NewD,
+ const LookupResult &Previous) {
+ assert(getLangOpts().CUDA && "May be called only for CUDA compilations.");
+ if (!getLangOpts().CUDAHostDeviceConstexpr || !NewD->isConstexpr() ||
+ NewD->isVariadic() || NewD->hasAttr<CUDAHostAttr>() ||
+ NewD->hasAttr<CUDADeviceAttr>() || NewD->hasAttr<CUDAGlobalAttr>())
+ return;
+
+ // Is D a __device__ function with the same signature as NewD, ignoring CUDA
+ // attributes?
+ auto IsMatchingDeviceFn = [&](NamedDecl *D) {
+ if (UsingShadowDecl *Using = dyn_cast<UsingShadowDecl>(D))
+ D = Using->getTargetDecl();
+ FunctionDecl *OldD = D->getAsFunction();
+ return OldD && OldD->hasAttr<CUDADeviceAttr>() &&
+ !OldD->hasAttr<CUDAHostAttr>() &&
+ !IsOverload(NewD, OldD, /* UseMemberUsingDeclRules = */ false,
+ /* ConsiderCudaAttrs = */ false);
+ };
+ auto It = llvm::find_if(Previous, IsMatchingDeviceFn);
+ if (It != Previous.end()) {
+ // We found a __device__ function with the same name and signature as NewD
+ // (ignoring CUDA attrs). This is an error unless that function is defined
+ // in a system header, in which case we simply return without making NewD
+ // host+device.
+ NamedDecl *Match = *It;
+ if (!getSourceManager().isInSystemHeader(Match->getLocation())) {
+ Diag(NewD->getLocation(),
+ diag::err_cuda_unattributed_constexpr_cannot_overload_device)
+ << NewD->getName();
+ Diag(Match->getLocation(),
+ diag::note_cuda_conflicting_device_function_declared_here);
+ }
+ return;
+ }
+
+ NewD->addAttr(CUDAHostAttr::CreateImplicit(Context));
+ NewD->addAttr(CUDADeviceAttr::CreateImplicit(Context));
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
index f7aace625a92..ab0e709a97e7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCXXScopeSpec.cpp
@@ -117,8 +117,18 @@ DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS,
// specializations, we're entering into the definition of that
// class template partial specialization.
if (ClassTemplatePartialSpecializationDecl *PartialSpec
- = ClassTemplate->findPartialSpecialization(ContextType))
+ = ClassTemplate->findPartialSpecialization(ContextType)) {
+ // A declaration of the partial specialization must be visible.
+ // We can always recover here, because this only happens when we're
+ // entering the context, and that can't happen in a SFINAE context.
+ assert(!isSFINAEContext() &&
+ "partial specialization scope specifier in SFINAE context?");
+ if (!hasVisibleDeclaration(PartialSpec))
+ diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec,
+ MissingImportKind::PartialSpecialization,
+ /*Recover*/true);
return PartialSpec;
+ }
}
} else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) {
// The nested name specifier refers to a member of a class template.
@@ -195,6 +205,8 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
TagDecl *tag = dyn_cast<TagDecl>(DC);
// If this is a dependent type, then we consider it complete.
+ // FIXME: This is wrong; we should require a (visible) definition to
+ // exist in this case too.
if (!tag || tag->isDependentContext())
return false;
@@ -218,10 +230,23 @@ bool Sema::RequireCompleteDeclContext(CXXScopeSpec &SS,
// Fixed enum types are complete, but they aren't valid as scopes
// until we see a definition, so awkwardly pull out this special
// case.
- // FIXME: The definition might not be visible; complain if it is not.
const EnumType *enumType = dyn_cast_or_null<EnumType>(tagType);
- if (!enumType || enumType->getDecl()->isCompleteDefinition())
+ if (!enumType)
return false;
+ if (enumType->getDecl()->isCompleteDefinition()) {
+ // If we know about the definition but it is not visible, complain.
+ NamedDecl *SuggestedDef = nullptr;
+ if (!hasVisibleDefinition(enumType->getDecl(), &SuggestedDef,
+ /*OnlyNeedComplete*/false)) {
+ // If the user is going to see an error here, recover by making the
+ // definition visible.
+ bool TreatAsComplete = !isSFINAEContext();
+ diagnoseMissingImport(loc, SuggestedDef, MissingImportKind::Definition,
+ /*Recover*/TreatAsComplete);
+ return !TreatAsComplete;
+ }
+ return false;
+ }
// Try to instantiate the definition, if this is a specialization of an
// enumeration temploid.
@@ -606,6 +631,10 @@ bool Sema::BuildCXXNestedNameSpecifier(Scope *S,
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
<< Name);
+ if (Corrected.getCorrectionSpecifier())
+ SS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
+ SourceRange(Found.getNameLoc()));
+
if (NamedDecl *ND = Corrected.getFoundDecl())
Found.addDecl(ND);
Found.setLookupName(Corrected.getCorrection());
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
index ad1d7da4d070..e83dd0716780 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCast.cpp
@@ -22,6 +22,7 @@
#include "clang/AST/RecordLayout.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
+#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/Initialization.h"
#include "llvm/ADT/SmallVector.h"
#include <set>
@@ -640,8 +641,8 @@ void CastOperation::CheckDynamicCast() {
// If we're dynamic_casting from a prvalue to an rvalue reference, we need
// to materialize the prvalue before we bind the reference to it.
if (SrcExpr.get()->isRValue())
- SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
- SrcType, SrcExpr.get(), /*IsLValueReference*/false);
+ SrcExpr = Self.CreateMaterializeTemporaryExpr(
+ SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
SrcPointee = SrcType;
}
@@ -1313,16 +1314,13 @@ TryStaticDowncast(Sema &Self, CanQualType SrcType, CanQualType DestType,
}
std::string PathDisplayStr;
std::set<unsigned> DisplayedPaths;
- for (CXXBasePaths::paths_iterator PI = Paths.begin(), PE = Paths.end();
- PI != PE; ++PI) {
- if (DisplayedPaths.insert(PI->back().SubobjectNumber).second) {
+ for (clang::CXXBasePath &Path : Paths) {
+ if (DisplayedPaths.insert(Path.back().SubobjectNumber).second) {
// We haven't displayed a path to this particular base
// class subobject yet.
PathDisplayStr += "\n ";
- for (CXXBasePath::const_reverse_iterator EI = PI->rbegin(),
- EE = PI->rend();
- EI != EE; ++EI)
- PathDisplayStr += EI->Base->getType().getAsString() + " -> ";
+ for (CXXBasePathElement &PE : llvm::reverse(Path))
+ PathDisplayStr += PE.Base->getType().getAsString() + " -> ";
PathDisplayStr += QualType(DestType).getAsString();
}
}
@@ -1402,8 +1400,10 @@ TryStaticMemberPointerUpcast(Sema &Self, ExprResult &SrcExpr, QualType SrcType,
// Lock down the inheritance model right now in MS ABI, whether or not the
// pointee types are the same.
- if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft())
+ if (Self.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
(void)Self.isCompleteType(OpRange.getBegin(), SrcType);
+ (void)Self.isCompleteType(OpRange.getBegin(), DestType);
+ }
// T == T, modulo cv
if (!Self.Context.hasSameUnqualifiedType(SrcMemPtr->getPointeeType(),
@@ -1646,8 +1646,8 @@ static TryCastResult TryConstCast(Sema &Self, ExprResult &SrcExpr,
if (NeedToMaterializeTemporary)
// This is a const_cast from a class prvalue to an rvalue reference type.
// Materialize a temporary to store the result of the conversion.
- SrcExpr = new (Self.Context) MaterializeTemporaryExpr(
- SrcType, SrcExpr.get(), /*IsLValueReference*/ false);
+ SrcExpr = Self.CreateMaterializeTemporaryExpr(SrcType, SrcExpr.get(),
+ /*IsLValueReference*/ false);
return TC_Success;
}
@@ -1724,6 +1724,97 @@ static void DiagnoseCastOfObjCSEL(Sema &Self, const ExprResult &SrcExpr,
}
}
+/// Diagnose casts that change the calling convention of a pointer to a function
+/// defined in the current TU.
+static void DiagnoseCallingConvCast(Sema &Self, const ExprResult &SrcExpr,
+ QualType DstType, SourceRange OpRange) {
+ // Check if this cast would change the calling convention of a function
+ // pointer type.
+ QualType SrcType = SrcExpr.get()->getType();
+ if (Self.Context.hasSameType(SrcType, DstType) ||
+ !SrcType->isFunctionPointerType() || !DstType->isFunctionPointerType())
+ return;
+ const auto *SrcFTy =
+ SrcType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>();
+ const auto *DstFTy =
+ DstType->castAs<PointerType>()->getPointeeType()->castAs<FunctionType>();
+ CallingConv SrcCC = SrcFTy->getCallConv();
+ CallingConv DstCC = DstFTy->getCallConv();
+ if (SrcCC == DstCC)
+ return;
+
+ // We have a calling convention cast. Check if the source is a pointer to a
+ // known, specific function that has already been defined.
+ Expr *Src = SrcExpr.get()->IgnoreParenImpCasts();
+ if (auto *UO = dyn_cast<UnaryOperator>(Src))
+ if (UO->getOpcode() == UO_AddrOf)
+ Src = UO->getSubExpr()->IgnoreParenImpCasts();
+ auto *DRE = dyn_cast<DeclRefExpr>(Src);
+ if (!DRE)
+ return;
+ auto *FD = dyn_cast<FunctionDecl>(DRE->getDecl());
+ const FunctionDecl *Definition;
+ if (!FD || !FD->hasBody(Definition))
+ return;
+
+ // Only warn if we are casting from the default convention to a non-default
+ // convention. This can happen when the programmer forgot to apply the calling
+ // convention to the function definition and then inserted this cast to
+ // satisfy the type system.
+ CallingConv DefaultCC = Self.getASTContext().getDefaultCallingConvention(
+ FD->isVariadic(), FD->isCXXInstanceMember());
+ if (DstCC == DefaultCC || SrcCC != DefaultCC)
+ return;
+
+ // Diagnose this cast, as it is probably bad.
+ StringRef SrcCCName = FunctionType::getNameForCallConv(SrcCC);
+ StringRef DstCCName = FunctionType::getNameForCallConv(DstCC);
+ Self.Diag(OpRange.getBegin(), diag::warn_cast_calling_conv)
+ << SrcCCName << DstCCName << OpRange;
+
+ // The checks above are cheaper than checking if the diagnostic is enabled.
+ // However, it's worth checking if the warning is enabled before we construct
+ // a fixit.
+ if (Self.Diags.isIgnored(diag::warn_cast_calling_conv, OpRange.getBegin()))
+ return;
+
+ // Try to suggest a fixit to change the calling convention of the function
+ // whose address was taken. Try to use the latest macro for the convention.
+ // For example, users probably want to write "WINAPI" instead of "__stdcall"
+ // to match the Windows header declarations.
+ SourceLocation NameLoc = Definition->getNameInfo().getLoc();
+ Preprocessor &PP = Self.getPreprocessor();
+ SmallVector<TokenValue, 6> AttrTokens;
+ SmallString<64> CCAttrText;
+ llvm::raw_svector_ostream OS(CCAttrText);
+ if (Self.getLangOpts().MicrosoftExt) {
+ // __stdcall or __vectorcall
+ OS << "__" << DstCCName;
+ IdentifierInfo *II = PP.getIdentifierInfo(OS.str());
+ AttrTokens.push_back(II->isKeyword(Self.getLangOpts())
+ ? TokenValue(II->getTokenID())
+ : TokenValue(II));
+ } else {
+ // __attribute__((stdcall)) or __attribute__((vectorcall))
+ OS << "__attribute__((" << DstCCName << "))";
+ AttrTokens.push_back(tok::kw___attribute);
+ AttrTokens.push_back(tok::l_paren);
+ AttrTokens.push_back(tok::l_paren);
+ IdentifierInfo *II = PP.getIdentifierInfo(DstCCName);
+ AttrTokens.push_back(II->isKeyword(Self.getLangOpts())
+ ? TokenValue(II->getTokenID())
+ : TokenValue(II));
+ AttrTokens.push_back(tok::r_paren);
+ AttrTokens.push_back(tok::r_paren);
+ }
+ StringRef AttrSpelling = PP.getLastMacroWithSpelling(NameLoc, AttrTokens);
+ if (!AttrSpelling.empty())
+ CCAttrText = AttrSpelling;
+ OS << ' ';
+ Self.Diag(NameLoc, diag::note_change_calling_conv_fixit)
+ << FD << DstCCName << FixItHint::CreateInsertion(NameLoc, CCAttrText);
+}
+
static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
const Expr *SrcExpr, QualType DestType,
Sema &Self) {
@@ -1750,6 +1841,32 @@ static void checkIntToPointerCast(bool CStyle, SourceLocation Loc,
}
}
+static bool fixOverloadedReinterpretCastExpr(Sema &Self, QualType DestType,
+ ExprResult &Result) {
+ // We can only fix an overloaded reinterpret_cast if
+ // - it is a template with explicit arguments that resolves to an lvalue
+ // unambiguously, or
+ // - it is the only function in an overload set that may have its address
+ // taken.
+
+ Expr *E = Result.get();
+ // TODO: what if this fails because of DiagnoseUseOfDecl or something
+ // like it?
+ if (Self.ResolveAndFixSingleFunctionTemplateSpecialization(
+ Result,
+ Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
+ ) &&
+ Result.isUsable())
+ return true;
+
+ // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
+ // preserves Result.
+ Result = E;
+ if (!Self.resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ return false;
+ return Result.isUsable();
+}
+
static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType DestType, bool CStyle,
SourceRange OpRange,
@@ -1761,21 +1878,15 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
QualType SrcType = SrcExpr.get()->getType();
// Is the source an overloaded name? (i.e. &foo)
- // If so, reinterpret_cast can not help us here (13.4, p1, bullet 5) ...
+ // If so, reinterpret_cast generally can not help us here (13.4, p1, bullet 5)
if (SrcType == Self.Context.OverloadTy) {
- // ... unless foo<int> resolves to an lvalue unambiguously.
- // TODO: what if this fails because of DiagnoseUseOfDecl or something
- // like it?
- ExprResult SingleFunctionExpr = SrcExpr;
- if (Self.ResolveAndFixSingleFunctionTemplateSpecialization(
- SingleFunctionExpr,
- Expr::getValueKindForType(DestType) == VK_RValue // Convert Fun to Ptr
- ) && SingleFunctionExpr.isUsable()) {
- SrcExpr = SingleFunctionExpr;
- SrcType = SrcExpr.get()->getType();
- } else {
+ ExprResult FixedExpr = SrcExpr;
+ if (!fixOverloadedReinterpretCastExpr(Self, DestType, FixedExpr))
return TC_NotApplicable;
- }
+
+ assert(FixedExpr.isUsable() && "Invalid result fixing overloaded expr");
+ SrcExpr = FixedExpr;
+ SrcType = SrcExpr.get()->getType();
}
if (const ReferenceType *DestTypeTmp = DestType->getAs<ReferenceType>()) {
@@ -2008,7 +2119,9 @@ static TryCastResult TryReinterpretCast(Sema &Self, ExprResult &SrcExpr,
}
if (CStyle)
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
-
+
+ DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
+
// Not casting away constness, so the only remaining check is for compatible
// pointer categories.
@@ -2313,6 +2426,22 @@ void CastOperation::CheckCStyleCast() {
return;
}
+ // OpenCL v2.0 s6.13.10 - Allow casts from '0' to event_t type.
+ if (Self.getLangOpts().OpenCL && DestType->isEventT()) {
+ llvm::APSInt CastInt;
+ if (SrcExpr.get()->EvaluateAsInt(CastInt, Self.Context)) {
+ if (0 == CastInt) {
+ Kind = CK_ZeroToOCLEvent;
+ return;
+ }
+ Self.Diag(OpRange.getBegin(),
+ diag::error_opencl_cast_non_zero_to_event_t)
+ << CastInt.toString(10) << SrcExpr.get()->getSourceRange();
+ SrcExpr = ExprError();
+ return;
+ }
+ }
+
// Reject any other conversions to non-scalar types.
Self.Diag(OpRange.getBegin(), diag::err_typecheck_cond_expect_scalar)
<< DestType << SrcExpr.get()->getSourceRange();
@@ -2427,6 +2556,7 @@ void CastOperation::CheckCStyleCast() {
}
DiagnoseCastOfObjCSEL(Self, SrcExpr, DestType);
+ DiagnoseCallingConvCast(Self, SrcExpr, DestType, OpRange);
DiagnoseBadFunctionCast(Self, SrcExpr, DestType);
Kind = Self.PrepareScalarCast(SrcExpr, DestType);
if (SrcExpr.isInvalid())
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
index 6c2834b750ae..0c25e01787c1 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaChecking.cpp
@@ -36,9 +36,12 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Locale.h"
#include "llvm/Support/ConvertUTF.h"
#include "llvm/Support/raw_ostream.h"
#include <limits>
+
using namespace clang;
using namespace sema;
@@ -258,6 +261,459 @@ static bool SemaBuiltinSEHScopeCheck(Sema &SemaRef, CallExpr *TheCall,
return false;
}
+static inline bool isBlockPointer(Expr *Arg) {
+ return Arg->getType()->isBlockPointerType();
+}
+
+/// OpenCL C v2.0, s6.13.17.2 - Checks that the block parameters are all local
+/// void*, which is a requirement of device side enqueue.
+static bool checkOpenCLBlockArgs(Sema &S, Expr *BlockArg) {
+ const BlockPointerType *BPT =
+ cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
+ ArrayRef<QualType> Params =
+ BPT->getPointeeType()->getAs<FunctionProtoType>()->getParamTypes();
+ unsigned ArgCounter = 0;
+ bool IllegalParams = false;
+ // Iterate through the block parameters until either one is found that is not
+ // a local void*, or the block is valid.
+ for (ArrayRef<QualType>::iterator I = Params.begin(), E = Params.end();
+ I != E; ++I, ++ArgCounter) {
+ if (!(*I)->isPointerType() || !(*I)->getPointeeType()->isVoidType() ||
+ (*I)->getPointeeType().getQualifiers().getAddressSpace() !=
+ LangAS::opencl_local) {
+ // Get the location of the error. If a block literal has been passed
+ // (BlockExpr) then we can point straight to the offending argument,
+ // else we just point to the variable reference.
+ SourceLocation ErrorLoc;
+ if (isa<BlockExpr>(BlockArg)) {
+ BlockDecl *BD = cast<BlockExpr>(BlockArg)->getBlockDecl();
+ ErrorLoc = BD->getParamDecl(ArgCounter)->getLocStart();
+ } else if (isa<DeclRefExpr>(BlockArg)) {
+ ErrorLoc = cast<DeclRefExpr>(BlockArg)->getLocStart();
+ }
+ S.Diag(ErrorLoc,
+ diag::err_opencl_enqueue_kernel_blocks_non_local_void_args);
+ IllegalParams = true;
+ }
+ }
+
+ return IllegalParams;
+}
+
+/// OpenCL C v2.0, s6.13.17.6 - Check the argument to the
+/// get_kernel_work_group_size
+/// and get_kernel_preferred_work_group_size_multiple builtin functions.
+static bool SemaOpenCLBuiltinKernelWorkGroupSize(Sema &S, CallExpr *TheCall) {
+ if (checkArgCount(S, TheCall, 1))
+ return true;
+
+ Expr *BlockArg = TheCall->getArg(0);
+ if (!isBlockPointer(BlockArg)) {
+ S.Diag(BlockArg->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type) << "block";
+ return true;
+ }
+ return checkOpenCLBlockArgs(S, BlockArg);
+}
+
+static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall,
+ unsigned Start, unsigned End);
+
+/// OpenCL v2.0, s6.13.17.1 - Check that sizes are provided for all
+/// 'local void*' parameter of passed block.
+static bool checkOpenCLEnqueueVariadicArgs(Sema &S, CallExpr *TheCall,
+ Expr *BlockArg,
+ unsigned NumNonVarArgs) {
+ const BlockPointerType *BPT =
+ cast<BlockPointerType>(BlockArg->getType().getCanonicalType());
+ unsigned NumBlockParams =
+ BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams();
+ unsigned TotalNumArgs = TheCall->getNumArgs();
+
+ // For each argument passed to the block, a corresponding uint needs to
+ // be passed to describe the size of the local memory.
+ if (TotalNumArgs != NumBlockParams + NumNonVarArgs) {
+ S.Diag(TheCall->getLocStart(),
+ diag::err_opencl_enqueue_kernel_local_size_args);
+ return true;
+ }
+
+ // Check that the sizes of the local memory are specified by integers.
+ return checkOpenCLEnqueueLocalSizeArgs(S, TheCall, NumNonVarArgs,
+ TotalNumArgs - 1);
+}
+
+/// OpenCL C v2.0, s6.13.17 - Enqueue kernel function contains four different
+/// overload formats specified in Table 6.13.17.1.
+/// int enqueue_kernel(queue_t queue,
+/// kernel_enqueue_flags_t flags,
+/// const ndrange_t ndrange,
+/// void (^block)(void))
+/// int enqueue_kernel(queue_t queue,
+/// kernel_enqueue_flags_t flags,
+/// const ndrange_t ndrange,
+/// uint num_events_in_wait_list,
+/// clk_event_t *event_wait_list,
+/// clk_event_t *event_ret,
+/// void (^block)(void))
+/// int enqueue_kernel(queue_t queue,
+/// kernel_enqueue_flags_t flags,
+/// const ndrange_t ndrange,
+/// void (^block)(local void*, ...),
+/// uint size0, ...)
+/// int enqueue_kernel(queue_t queue,
+/// kernel_enqueue_flags_t flags,
+/// const ndrange_t ndrange,
+/// uint num_events_in_wait_list,
+/// clk_event_t *event_wait_list,
+/// clk_event_t *event_ret,
+/// void (^block)(local void*, ...),
+/// uint size0, ...)
+static bool SemaOpenCLBuiltinEnqueueKernel(Sema &S, CallExpr *TheCall) {
+ unsigned NumArgs = TheCall->getNumArgs();
+
+ if (NumArgs < 4) {
+ S.Diag(TheCall->getLocStart(), diag::err_typecheck_call_too_few_args);
+ return true;
+ }
+
+ Expr *Arg0 = TheCall->getArg(0);
+ Expr *Arg1 = TheCall->getArg(1);
+ Expr *Arg2 = TheCall->getArg(2);
+ Expr *Arg3 = TheCall->getArg(3);
+
+ // First argument always needs to be a queue_t type.
+ if (!Arg0->getType()->isQueueT()) {
+ S.Diag(TheCall->getArg(0)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << S.Context.OCLQueueTy;
+ return true;
+ }
+
+ // Second argument always needs to be a kernel_enqueue_flags_t enum value.
+ if (!Arg1->getType()->isIntegerType()) {
+ S.Diag(TheCall->getArg(1)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << "'kernel_enqueue_flags_t' (i.e. uint)";
+ return true;
+ }
+
+ // Third argument is always an ndrange_t type.
+ if (!Arg2->getType()->isNDRangeT()) {
+ S.Diag(TheCall->getArg(2)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << S.Context.OCLNDRangeTy;
+ return true;
+ }
+
+ // With four arguments, there is only one form that the function could be
+ // called in: no events and no variable arguments.
+ if (NumArgs == 4) {
+ // check that the last argument is the right block type.
+ if (!isBlockPointer(Arg3)) {
+ S.Diag(Arg3->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
+ << "block";
+ return true;
+ }
+ // we have a block type, check the prototype
+ const BlockPointerType *BPT =
+ cast<BlockPointerType>(Arg3->getType().getCanonicalType());
+ if (BPT->getPointeeType()->getAs<FunctionProtoType>()->getNumParams() > 0) {
+ S.Diag(Arg3->getLocStart(),
+ diag::err_opencl_enqueue_kernel_blocks_no_args);
+ return true;
+ }
+ return false;
+ }
+ // we can have block + varargs.
+ if (isBlockPointer(Arg3))
+ return (checkOpenCLBlockArgs(S, Arg3) ||
+ checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg3, 4));
+ // last two cases with either exactly 7 args or 7 args and varargs.
+ if (NumArgs >= 7) {
+ // check common block argument.
+ Expr *Arg6 = TheCall->getArg(6);
+ if (!isBlockPointer(Arg6)) {
+ S.Diag(Arg6->getLocStart(), diag::err_opencl_enqueue_kernel_expected_type)
+ << "block";
+ return true;
+ }
+ if (checkOpenCLBlockArgs(S, Arg6))
+ return true;
+
+ // Forth argument has to be any integer type.
+ if (!Arg3->getType()->isIntegerType()) {
+ S.Diag(TheCall->getArg(3)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << "integer";
+ return true;
+ }
+ // check remaining common arguments.
+ Expr *Arg4 = TheCall->getArg(4);
+ Expr *Arg5 = TheCall->getArg(5);
+
+ // Fith argument is always passed as pointers to clk_event_t.
+ if (!Arg4->getType()->getPointeeOrArrayElementType()->isClkEventT()) {
+ S.Diag(TheCall->getArg(4)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << S.Context.getPointerType(S.Context.OCLClkEventTy);
+ return true;
+ }
+
+ // Sixth argument is always passed as pointers to clk_event_t.
+ if (!(Arg5->getType()->isPointerType() &&
+ Arg5->getType()->getPointeeType()->isClkEventT())) {
+ S.Diag(TheCall->getArg(5)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_expected_type)
+ << S.Context.getPointerType(S.Context.OCLClkEventTy);
+ return true;
+ }
+
+ if (NumArgs == 7)
+ return false;
+
+ return checkOpenCLEnqueueVariadicArgs(S, TheCall, Arg6, 7);
+ }
+
+ // None of the specific case has been detected, give generic error
+ S.Diag(TheCall->getLocStart(),
+ diag::err_opencl_enqueue_kernel_incorrect_args);
+ return true;
+}
+
+/// Returns OpenCL access qual.
+static OpenCLAccessAttr *getOpenCLArgAccess(const Decl *D) {
+ return D->getAttr<OpenCLAccessAttr>();
+}
+
+/// Returns true if pipe element type is different from the pointer.
+static bool checkOpenCLPipeArg(Sema &S, CallExpr *Call) {
+ const Expr *Arg0 = Call->getArg(0);
+ // First argument type should always be pipe.
+ if (!Arg0->getType()->isPipeType()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg)
+ << Call->getDirectCallee() << Arg0->getSourceRange();
+ return true;
+ }
+ OpenCLAccessAttr *AccessQual =
+ getOpenCLArgAccess(cast<DeclRefExpr>(Arg0)->getDecl());
+ // Validates the access qualifier is compatible with the call.
+ // OpenCL v2.0 s6.13.16 - The access qualifiers for pipe should only be
+ // read_only and write_only, and assumed to be read_only if no qualifier is
+ // specified.
+ switch (Call->getDirectCallee()->getBuiltinID()) {
+ case Builtin::BIread_pipe:
+ case Builtin::BIreserve_read_pipe:
+ case Builtin::BIcommit_read_pipe:
+ case Builtin::BIwork_group_reserve_read_pipe:
+ case Builtin::BIsub_group_reserve_read_pipe:
+ case Builtin::BIwork_group_commit_read_pipe:
+ case Builtin::BIsub_group_commit_read_pipe:
+ if (!(!AccessQual || AccessQual->isReadOnly())) {
+ S.Diag(Arg0->getLocStart(),
+ diag::err_opencl_builtin_pipe_invalid_access_modifier)
+ << "read_only" << Arg0->getSourceRange();
+ return true;
+ }
+ break;
+ case Builtin::BIwrite_pipe:
+ case Builtin::BIreserve_write_pipe:
+ case Builtin::BIcommit_write_pipe:
+ case Builtin::BIwork_group_reserve_write_pipe:
+ case Builtin::BIsub_group_reserve_write_pipe:
+ case Builtin::BIwork_group_commit_write_pipe:
+ case Builtin::BIsub_group_commit_write_pipe:
+ if (!(AccessQual && AccessQual->isWriteOnly())) {
+ S.Diag(Arg0->getLocStart(),
+ diag::err_opencl_builtin_pipe_invalid_access_modifier)
+ << "write_only" << Arg0->getSourceRange();
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ return false;
+}
+
+/// Returns true if pipe element type is different from the pointer.
+static bool checkOpenCLPipePacketType(Sema &S, CallExpr *Call, unsigned Idx) {
+ const Expr *Arg0 = Call->getArg(0);
+ const Expr *ArgIdx = Call->getArg(Idx);
+ const PipeType *PipeTy = cast<PipeType>(Arg0->getType());
+ const QualType EltTy = PipeTy->getElementType();
+ const PointerType *ArgTy = ArgIdx->getType()->getAs<PointerType>();
+ // The Idx argument should be a pointer and the type of the pointer and
+ // the type of pipe element should also be the same.
+ if (!ArgTy ||
+ !S.Context.hasSameType(
+ EltTy, ArgTy->getPointeeType()->getCanonicalTypeInternal())) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg)
+ << Call->getDirectCallee() << S.Context.getPointerType(EltTy)
+ << ArgIdx->getType() << ArgIdx->getSourceRange();
+ return true;
+ }
+ return false;
+}
+
+// \brief Performs semantic analysis for the read/write_pipe call.
+// \param S Reference to the semantic analyzer.
+// \param Call A pointer to the builtin call.
+// \return True if a semantic error has been found, false otherwise.
+static bool SemaBuiltinRWPipe(Sema &S, CallExpr *Call) {
+ // OpenCL v2.0 s6.13.16.2 - The built-in read/write
+ // functions have two forms.
+ switch (Call->getNumArgs()) {
+ case 2: {
+ if (checkOpenCLPipeArg(S, Call))
+ return true;
+ // The call with 2 arguments should be
+ // read/write_pipe(pipe T, T*).
+ // Check packet type T.
+ if (checkOpenCLPipePacketType(S, Call, 1))
+ return true;
+ } break;
+
+ case 4: {
+ if (checkOpenCLPipeArg(S, Call))
+ return true;
+ // The call with 4 arguments should be
+ // read/write_pipe(pipe T, reserve_id_t, uint, T*).
+ // Check reserve_id_t.
+ if (!Call->getArg(1)->getType()->isReserveIDT()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg)
+ << Call->getDirectCallee() << S.Context.OCLReserveIDTy
+ << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange();
+ return true;
+ }
+
+ // Check the index.
+ const Expr *Arg2 = Call->getArg(2);
+ if (!Arg2->getType()->isIntegerType() &&
+ !Arg2->getType()->isUnsignedIntegerType()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg)
+ << Call->getDirectCallee() << S.Context.UnsignedIntTy
+ << Arg2->getType() << Arg2->getSourceRange();
+ return true;
+ }
+
+ // Check packet type T.
+ if (checkOpenCLPipePacketType(S, Call, 3))
+ return true;
+ } break;
+ default:
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_arg_num)
+ << Call->getDirectCallee() << Call->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
+// \brief Performs a semantic analysis on the {work_group_/sub_group_
+// /_}reserve_{read/write}_pipe
+// \param S Reference to the semantic analyzer.
+// \param Call The call to the builtin function to be analyzed.
+// \return True if a semantic error was found, false otherwise.
+static bool SemaBuiltinReserveRWPipe(Sema &S, CallExpr *Call) {
+ if (checkArgCount(S, Call, 2))
+ return true;
+
+ if (checkOpenCLPipeArg(S, Call))
+ return true;
+
+ // Check the reserve size.
+ if (!Call->getArg(1)->getType()->isIntegerType() &&
+ !Call->getArg(1)->getType()->isUnsignedIntegerType()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg)
+ << Call->getDirectCallee() << S.Context.UnsignedIntTy
+ << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
+// \brief Performs a semantic analysis on {work_group_/sub_group_
+// /_}commit_{read/write}_pipe
+// \param S Reference to the semantic analyzer.
+// \param Call The call to the builtin function to be analyzed.
+// \return True if a semantic error was found, false otherwise.
+static bool SemaBuiltinCommitRWPipe(Sema &S, CallExpr *Call) {
+ if (checkArgCount(S, Call, 2))
+ return true;
+
+ if (checkOpenCLPipeArg(S, Call))
+ return true;
+
+ // Check reserve_id_t.
+ if (!Call->getArg(1)->getType()->isReserveIDT()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_invalid_arg)
+ << Call->getDirectCallee() << S.Context.OCLReserveIDTy
+ << Call->getArg(1)->getType() << Call->getArg(1)->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+
+// \brief Performs a semantic analysis on the call to built-in Pipe
+// Query Functions.
+// \param S Reference to the semantic analyzer.
+// \param Call The call to the builtin function to be analyzed.
+// \return True if a semantic error was found, false otherwise.
+static bool SemaBuiltinPipePackets(Sema &S, CallExpr *Call) {
+ if (checkArgCount(S, Call, 1))
+ return true;
+
+ if (!Call->getArg(0)->getType()->isPipeType()) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_pipe_first_arg)
+ << Call->getDirectCallee() << Call->getArg(0)->getSourceRange();
+ return true;
+ }
+
+ return false;
+}
+// \brief OpenCL v2.0 s6.13.9 - Address space qualifier functions.
+// \brief Performs semantic analysis for the to_global/local/private call.
+// \param S Reference to the semantic analyzer.
+// \param BuiltinID ID of the builtin function.
+// \param Call A pointer to the builtin call.
+// \return True if a semantic error has been found, false otherwise.
+static bool SemaOpenCLBuiltinToAddr(Sema &S, unsigned BuiltinID,
+ CallExpr *Call) {
+ if (Call->getNumArgs() != 1) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_arg_num)
+ << Call->getDirectCallee() << Call->getSourceRange();
+ return true;
+ }
+
+ auto RT = Call->getArg(0)->getType();
+ if (!RT->isPointerType() || RT->getPointeeType()
+ .getAddressSpace() == LangAS::opencl_constant) {
+ S.Diag(Call->getLocStart(), diag::err_opencl_builtin_to_addr_invalid_arg)
+ << Call->getArg(0) << Call->getDirectCallee() << Call->getSourceRange();
+ return true;
+ }
+
+ RT = RT->getPointeeType();
+ auto Qual = RT.getQualifiers();
+ switch (BuiltinID) {
+ case Builtin::BIto_global:
+ Qual.setAddressSpace(LangAS::opencl_global);
+ break;
+ case Builtin::BIto_local:
+ Qual.setAddressSpace(LangAS::opencl_local);
+ break;
+ default:
+ Qual.removeAddressSpace();
+ }
+ Call->setType(S.Context.getPointerType(S.Context.getQualifiedType(
+ RT.getUnqualifiedType(), Qual)));
+
+ return false;
+}
+
ExprResult
Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
CallExpr *TheCall) {
@@ -530,27 +986,22 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
case Builtin::BI__builtin___vsnprintf_chk:
SemaBuiltinMemChkCall(*this, FDecl, TheCall, 1, 3);
break;
-
case Builtin::BI__builtin_call_with_static_chain:
if (SemaBuiltinCallWithStaticChain(*this, TheCall))
return ExprError();
break;
-
case Builtin::BI__exception_code:
- case Builtin::BI_exception_code: {
+ case Builtin::BI_exception_code:
if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHExceptScope,
diag::err_seh___except_block))
return ExprError();
break;
- }
case Builtin::BI__exception_info:
- case Builtin::BI_exception_info: {
+ case Builtin::BI_exception_info:
if (SemaBuiltinSEHScopeCheck(*this, TheCall, Scope::SEHFilterScope,
diag::err_seh___except_filter))
return ExprError();
break;
- }
-
case Builtin::BI__GetExceptionInfo:
if (checkArgCount(*this, TheCall, 1))
return ExprError();
@@ -563,7 +1014,56 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
TheCall->setType(Context.VoidPtrTy);
break;
-
+ // OpenCL v2.0, s6.13.16 - Pipe functions
+ case Builtin::BIread_pipe:
+ case Builtin::BIwrite_pipe:
+ // Since those two functions are declared with var args, we need a semantic
+ // check for the argument.
+ if (SemaBuiltinRWPipe(*this, TheCall))
+ return ExprError();
+ break;
+ case Builtin::BIreserve_read_pipe:
+ case Builtin::BIreserve_write_pipe:
+ case Builtin::BIwork_group_reserve_read_pipe:
+ case Builtin::BIwork_group_reserve_write_pipe:
+ case Builtin::BIsub_group_reserve_read_pipe:
+ case Builtin::BIsub_group_reserve_write_pipe:
+ if (SemaBuiltinReserveRWPipe(*this, TheCall))
+ return ExprError();
+ // Since return type of reserve_read/write_pipe built-in function is
+ // reserve_id_t, which is not defined in the builtin def file , we used int
+ // as return type and need to override the return type of these functions.
+ TheCall->setType(Context.OCLReserveIDTy);
+ break;
+ case Builtin::BIcommit_read_pipe:
+ case Builtin::BIcommit_write_pipe:
+ case Builtin::BIwork_group_commit_read_pipe:
+ case Builtin::BIwork_group_commit_write_pipe:
+ case Builtin::BIsub_group_commit_read_pipe:
+ case Builtin::BIsub_group_commit_write_pipe:
+ if (SemaBuiltinCommitRWPipe(*this, TheCall))
+ return ExprError();
+ break;
+ case Builtin::BIget_pipe_num_packets:
+ case Builtin::BIget_pipe_max_packets:
+ if (SemaBuiltinPipePackets(*this, TheCall))
+ return ExprError();
+ break;
+ case Builtin::BIto_global:
+ case Builtin::BIto_local:
+ case Builtin::BIto_private:
+ if (SemaOpenCLBuiltinToAddr(*this, BuiltinID, TheCall))
+ return ExprError();
+ break;
+ // OpenCL v2.0, s6.13.17 - Enqueue kernel functions.
+ case Builtin::BIenqueue_kernel:
+ if (SemaOpenCLBuiltinEnqueueKernel(*this, TheCall))
+ return ExprError();
+ break;
+ case Builtin::BIget_kernel_work_group_size:
+ case Builtin::BIget_kernel_preferred_work_group_size_multiple:
+ if (SemaOpenCLBuiltinKernelWorkGroupSize(*this, TheCall))
+ return ExprError();
}
// Since the target specific builtins for each arch overlap, only check those
@@ -843,7 +1343,6 @@ bool Sema::CheckARMBuiltinExclusiveCall(unsigned BuiltinID, CallExpr *TheCall,
return true;
}
-
if (IsLdrex) {
TheCall->setType(ValType);
return false;
@@ -931,7 +1430,7 @@ bool Sema::CheckAArch64BuiltinFunctionCall(unsigned BuiltinID,
if (BuiltinID == AArch64::BI__builtin_arm_rsr64 ||
BuiltinID == AArch64::BI__builtin_arm_wsr64)
- return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, false);
+ return SemaBuiltinARMSpecialReg(BuiltinID, TheCall, 0, 5, true);
if (BuiltinID == AArch64::BI__builtin_arm_rsr ||
BuiltinID == AArch64::BI__builtin_arm_rsrp ||
@@ -1091,19 +1590,58 @@ static bool SemaBuiltinCpuSupports(Sema &S, CallExpr *TheCall) {
}
bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
- unsigned i = 0, l = 0, u = 0;
+ int i = 0, l = 0, u = 0;
switch (BuiltinID) {
- default: return false;
+ default:
+ return false;
case X86::BI__builtin_cpu_supports:
return SemaBuiltinCpuSupports(*this, TheCall);
case X86::BI__builtin_ms_va_start:
return SemaBuiltinMSVAStart(TheCall);
- case X86::BI_mm_prefetch: i = 1; l = 0; u = 3; break;
- case X86::BI__builtin_ia32_sha1rnds4: i = 2, l = 0; u = 3; break;
+ case X86::BI__builtin_ia32_extractf64x4_mask:
+ case X86::BI__builtin_ia32_extracti64x4_mask:
+ case X86::BI__builtin_ia32_extractf32x8_mask:
+ case X86::BI__builtin_ia32_extracti32x8_mask:
+ case X86::BI__builtin_ia32_extractf64x2_256_mask:
+ case X86::BI__builtin_ia32_extracti64x2_256_mask:
+ case X86::BI__builtin_ia32_extractf32x4_256_mask:
+ case X86::BI__builtin_ia32_extracti32x4_256_mask:
+ i = 1; l = 0; u = 1;
+ break;
+ case X86::BI_mm_prefetch:
+ case X86::BI__builtin_ia32_extractf32x4_mask:
+ case X86::BI__builtin_ia32_extracti32x4_mask:
+ case X86::BI__builtin_ia32_extractf64x2_512_mask:
+ case X86::BI__builtin_ia32_extracti64x2_512_mask:
+ i = 1; l = 0; u = 3;
+ break;
+ case X86::BI__builtin_ia32_insertf32x8_mask:
+ case X86::BI__builtin_ia32_inserti32x8_mask:
+ case X86::BI__builtin_ia32_insertf64x4_mask:
+ case X86::BI__builtin_ia32_inserti64x4_mask:
+ case X86::BI__builtin_ia32_insertf64x2_256_mask:
+ case X86::BI__builtin_ia32_inserti64x2_256_mask:
+ case X86::BI__builtin_ia32_insertf32x4_256_mask:
+ case X86::BI__builtin_ia32_inserti32x4_256_mask:
+ i = 2; l = 0; u = 1;
+ break;
+ case X86::BI__builtin_ia32_sha1rnds4:
+ case X86::BI__builtin_ia32_shuf_f32x4_256_mask:
+ case X86::BI__builtin_ia32_shuf_f64x2_256_mask:
+ case X86::BI__builtin_ia32_shuf_i32x4_256_mask:
+ case X86::BI__builtin_ia32_shuf_i64x2_256_mask:
+ case X86::BI__builtin_ia32_insertf64x2_512_mask:
+ case X86::BI__builtin_ia32_inserti64x2_512_mask:
+ case X86::BI__builtin_ia32_insertf32x4_mask:
+ case X86::BI__builtin_ia32_inserti32x4_mask:
+ i = 2; l = 0; u = 3;
+ break;
case X86::BI__builtin_ia32_vpermil2pd:
case X86::BI__builtin_ia32_vpermil2pd256:
case X86::BI__builtin_ia32_vpermil2ps:
- case X86::BI__builtin_ia32_vpermil2ps256: i = 3, l = 0; u = 3; break;
+ case X86::BI__builtin_ia32_vpermil2ps256:
+ i = 3; l = 0; u = 3;
+ break;
case X86::BI__builtin_ia32_cmpb128_mask:
case X86::BI__builtin_ia32_cmpw128_mask:
case X86::BI__builtin_ia32_cmpd128_mask:
@@ -1127,29 +1665,205 @@ bool Sema::CheckX86BuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
case X86::BI__builtin_ia32_ucmpb512_mask:
case X86::BI__builtin_ia32_ucmpw512_mask:
case X86::BI__builtin_ia32_ucmpd512_mask:
- case X86::BI__builtin_ia32_ucmpq512_mask: i = 2; l = 0; u = 7; break;
+ case X86::BI__builtin_ia32_ucmpq512_mask:
+ case X86::BI__builtin_ia32_vpcomub:
+ case X86::BI__builtin_ia32_vpcomuw:
+ case X86::BI__builtin_ia32_vpcomud:
+ case X86::BI__builtin_ia32_vpcomuq:
+ case X86::BI__builtin_ia32_vpcomb:
+ case X86::BI__builtin_ia32_vpcomw:
+ case X86::BI__builtin_ia32_vpcomd:
+ case X86::BI__builtin_ia32_vpcomq:
+ i = 2; l = 0; u = 7;
+ break;
case X86::BI__builtin_ia32_roundps:
case X86::BI__builtin_ia32_roundpd:
case X86::BI__builtin_ia32_roundps256:
- case X86::BI__builtin_ia32_roundpd256: i = 1, l = 0; u = 15; break;
+ case X86::BI__builtin_ia32_roundpd256:
+ i = 1; l = 0; u = 15;
+ break;
case X86::BI__builtin_ia32_roundss:
- case X86::BI__builtin_ia32_roundsd: i = 2, l = 0; u = 15; break;
+ case X86::BI__builtin_ia32_roundsd:
+ case X86::BI__builtin_ia32_rangepd128_mask:
+ case X86::BI__builtin_ia32_rangepd256_mask:
+ case X86::BI__builtin_ia32_rangepd512_mask:
+ case X86::BI__builtin_ia32_rangeps128_mask:
+ case X86::BI__builtin_ia32_rangeps256_mask:
+ case X86::BI__builtin_ia32_rangeps512_mask:
+ case X86::BI__builtin_ia32_getmantsd_round_mask:
+ case X86::BI__builtin_ia32_getmantss_round_mask:
+ i = 2; l = 0; u = 15;
+ break;
case X86::BI__builtin_ia32_cmpps:
case X86::BI__builtin_ia32_cmpss:
case X86::BI__builtin_ia32_cmppd:
case X86::BI__builtin_ia32_cmpsd:
case X86::BI__builtin_ia32_cmpps256:
case X86::BI__builtin_ia32_cmppd256:
+ case X86::BI__builtin_ia32_cmpps128_mask:
+ case X86::BI__builtin_ia32_cmppd128_mask:
+ case X86::BI__builtin_ia32_cmpps256_mask:
+ case X86::BI__builtin_ia32_cmppd256_mask:
case X86::BI__builtin_ia32_cmpps512_mask:
- case X86::BI__builtin_ia32_cmppd512_mask: i = 2; l = 0; u = 31; break;
- case X86::BI__builtin_ia32_vpcomub:
- case X86::BI__builtin_ia32_vpcomuw:
- case X86::BI__builtin_ia32_vpcomud:
- case X86::BI__builtin_ia32_vpcomuq:
- case X86::BI__builtin_ia32_vpcomb:
- case X86::BI__builtin_ia32_vpcomw:
- case X86::BI__builtin_ia32_vpcomd:
- case X86::BI__builtin_ia32_vpcomq: i = 2; l = 0; u = 7; break;
+ case X86::BI__builtin_ia32_cmppd512_mask:
+ case X86::BI__builtin_ia32_cmpsd_mask:
+ case X86::BI__builtin_ia32_cmpss_mask:
+ i = 2; l = 0; u = 31;
+ break;
+ case X86::BI__builtin_ia32_xabort:
+ i = 0; l = -128; u = 255;
+ break;
+ case X86::BI__builtin_ia32_pshufw:
+ case X86::BI__builtin_ia32_aeskeygenassist128:
+ i = 1; l = -128; u = 255;
+ break;
+ case X86::BI__builtin_ia32_vcvtps2ph:
+ case X86::BI__builtin_ia32_vcvtps2ph256:
+ case X86::BI__builtin_ia32_rndscaleps_128_mask:
+ case X86::BI__builtin_ia32_rndscalepd_128_mask:
+ case X86::BI__builtin_ia32_rndscaleps_256_mask:
+ case X86::BI__builtin_ia32_rndscalepd_256_mask:
+ case X86::BI__builtin_ia32_rndscaleps_mask:
+ case X86::BI__builtin_ia32_rndscalepd_mask:
+ case X86::BI__builtin_ia32_reducepd128_mask:
+ case X86::BI__builtin_ia32_reducepd256_mask:
+ case X86::BI__builtin_ia32_reducepd512_mask:
+ case X86::BI__builtin_ia32_reduceps128_mask:
+ case X86::BI__builtin_ia32_reduceps256_mask:
+ case X86::BI__builtin_ia32_reduceps512_mask:
+ case X86::BI__builtin_ia32_prold512_mask:
+ case X86::BI__builtin_ia32_prolq512_mask:
+ case X86::BI__builtin_ia32_prold128_mask:
+ case X86::BI__builtin_ia32_prold256_mask:
+ case X86::BI__builtin_ia32_prolq128_mask:
+ case X86::BI__builtin_ia32_prolq256_mask:
+ case X86::BI__builtin_ia32_prord128_mask:
+ case X86::BI__builtin_ia32_prord256_mask:
+ case X86::BI__builtin_ia32_prorq128_mask:
+ case X86::BI__builtin_ia32_prorq256_mask:
+ case X86::BI__builtin_ia32_psllwi512_mask:
+ case X86::BI__builtin_ia32_psllwi128_mask:
+ case X86::BI__builtin_ia32_psllwi256_mask:
+ case X86::BI__builtin_ia32_psrldi128_mask:
+ case X86::BI__builtin_ia32_psrldi256_mask:
+ case X86::BI__builtin_ia32_psrldi512_mask:
+ case X86::BI__builtin_ia32_psrlqi128_mask:
+ case X86::BI__builtin_ia32_psrlqi256_mask:
+ case X86::BI__builtin_ia32_psrlqi512_mask:
+ case X86::BI__builtin_ia32_psrawi512_mask:
+ case X86::BI__builtin_ia32_psrawi128_mask:
+ case X86::BI__builtin_ia32_psrawi256_mask:
+ case X86::BI__builtin_ia32_psrlwi512_mask:
+ case X86::BI__builtin_ia32_psrlwi128_mask:
+ case X86::BI__builtin_ia32_psrlwi256_mask:
+ case X86::BI__builtin_ia32_psradi128_mask:
+ case X86::BI__builtin_ia32_psradi256_mask:
+ case X86::BI__builtin_ia32_psradi512_mask:
+ case X86::BI__builtin_ia32_psraqi128_mask:
+ case X86::BI__builtin_ia32_psraqi256_mask:
+ case X86::BI__builtin_ia32_psraqi512_mask:
+ case X86::BI__builtin_ia32_pslldi128_mask:
+ case X86::BI__builtin_ia32_pslldi256_mask:
+ case X86::BI__builtin_ia32_pslldi512_mask:
+ case X86::BI__builtin_ia32_psllqi128_mask:
+ case X86::BI__builtin_ia32_psllqi256_mask:
+ case X86::BI__builtin_ia32_psllqi512_mask:
+ case X86::BI__builtin_ia32_fpclasspd128_mask:
+ case X86::BI__builtin_ia32_fpclasspd256_mask:
+ case X86::BI__builtin_ia32_fpclassps128_mask:
+ case X86::BI__builtin_ia32_fpclassps256_mask:
+ case X86::BI__builtin_ia32_fpclassps512_mask:
+ case X86::BI__builtin_ia32_fpclasspd512_mask:
+ case X86::BI__builtin_ia32_fpclasssd_mask:
+ case X86::BI__builtin_ia32_fpclassss_mask:
+ i = 1; l = 0; u = 255;
+ break;
+ case X86::BI__builtin_ia32_palignr:
+ case X86::BI__builtin_ia32_insertps128:
+ case X86::BI__builtin_ia32_dpps:
+ case X86::BI__builtin_ia32_dppd:
+ case X86::BI__builtin_ia32_dpps256:
+ case X86::BI__builtin_ia32_mpsadbw128:
+ case X86::BI__builtin_ia32_mpsadbw256:
+ case X86::BI__builtin_ia32_pcmpistrm128:
+ case X86::BI__builtin_ia32_pcmpistri128:
+ case X86::BI__builtin_ia32_pcmpistria128:
+ case X86::BI__builtin_ia32_pcmpistric128:
+ case X86::BI__builtin_ia32_pcmpistrio128:
+ case X86::BI__builtin_ia32_pcmpistris128:
+ case X86::BI__builtin_ia32_pcmpistriz128:
+ case X86::BI__builtin_ia32_pclmulqdq128:
+ case X86::BI__builtin_ia32_vperm2f128_pd256:
+ case X86::BI__builtin_ia32_vperm2f128_ps256:
+ case X86::BI__builtin_ia32_vperm2f128_si256:
+ case X86::BI__builtin_ia32_permti256:
+ i = 2; l = -128; u = 255;
+ break;
+ case X86::BI__builtin_ia32_palignr128:
+ case X86::BI__builtin_ia32_palignr256:
+ case X86::BI__builtin_ia32_palignr128_mask:
+ case X86::BI__builtin_ia32_palignr256_mask:
+ case X86::BI__builtin_ia32_palignr512_mask:
+ case X86::BI__builtin_ia32_alignq512_mask:
+ case X86::BI__builtin_ia32_alignd512_mask:
+ case X86::BI__builtin_ia32_alignd128_mask:
+ case X86::BI__builtin_ia32_alignd256_mask:
+ case X86::BI__builtin_ia32_alignq128_mask:
+ case X86::BI__builtin_ia32_alignq256_mask:
+ case X86::BI__builtin_ia32_vcomisd:
+ case X86::BI__builtin_ia32_vcomiss:
+ case X86::BI__builtin_ia32_shuf_f32x4_mask:
+ case X86::BI__builtin_ia32_shuf_f64x2_mask:
+ case X86::BI__builtin_ia32_shuf_i32x4_mask:
+ case X86::BI__builtin_ia32_shuf_i64x2_mask:
+ case X86::BI__builtin_ia32_dbpsadbw128_mask:
+ case X86::BI__builtin_ia32_dbpsadbw256_mask:
+ case X86::BI__builtin_ia32_dbpsadbw512_mask:
+ i = 2; l = 0; u = 255;
+ break;
+ case X86::BI__builtin_ia32_fixupimmpd512_mask:
+ case X86::BI__builtin_ia32_fixupimmpd512_maskz:
+ case X86::BI__builtin_ia32_fixupimmps512_mask:
+ case X86::BI__builtin_ia32_fixupimmps512_maskz:
+ case X86::BI__builtin_ia32_fixupimmsd_mask:
+ case X86::BI__builtin_ia32_fixupimmsd_maskz:
+ case X86::BI__builtin_ia32_fixupimmss_mask:
+ case X86::BI__builtin_ia32_fixupimmss_maskz:
+ case X86::BI__builtin_ia32_fixupimmpd128_mask:
+ case X86::BI__builtin_ia32_fixupimmpd128_maskz:
+ case X86::BI__builtin_ia32_fixupimmpd256_mask:
+ case X86::BI__builtin_ia32_fixupimmpd256_maskz:
+ case X86::BI__builtin_ia32_fixupimmps128_mask:
+ case X86::BI__builtin_ia32_fixupimmps128_maskz:
+ case X86::BI__builtin_ia32_fixupimmps256_mask:
+ case X86::BI__builtin_ia32_fixupimmps256_maskz:
+ case X86::BI__builtin_ia32_pternlogd512_mask:
+ case X86::BI__builtin_ia32_pternlogd512_maskz:
+ case X86::BI__builtin_ia32_pternlogq512_mask:
+ case X86::BI__builtin_ia32_pternlogq512_maskz:
+ case X86::BI__builtin_ia32_pternlogd128_mask:
+ case X86::BI__builtin_ia32_pternlogd128_maskz:
+ case X86::BI__builtin_ia32_pternlogd256_mask:
+ case X86::BI__builtin_ia32_pternlogd256_maskz:
+ case X86::BI__builtin_ia32_pternlogq128_mask:
+ case X86::BI__builtin_ia32_pternlogq128_maskz:
+ case X86::BI__builtin_ia32_pternlogq256_mask:
+ case X86::BI__builtin_ia32_pternlogq256_maskz:
+ i = 3; l = 0; u = 255;
+ break;
+ case X86::BI__builtin_ia32_pcmpestrm128:
+ case X86::BI__builtin_ia32_pcmpestri128:
+ case X86::BI__builtin_ia32_pcmpestria128:
+ case X86::BI__builtin_ia32_pcmpestric128:
+ case X86::BI__builtin_ia32_pcmpestrio128:
+ case X86::BI__builtin_ia32_pcmpestris128:
+ case X86::BI__builtin_ia32_pcmpestriz128:
+ i = 4; l = -128; u = 255;
+ break;
+ case X86::BI__builtin_ia32_rndscalesd_round_mask:
+ case X86::BI__builtin_ia32_rndscaless_round_mask:
+ i = 4; l = 0; u = 255;
+ break;
}
return SemaBuiltinConstantArgRange(TheCall, i, l, u);
}
@@ -1534,10 +2248,10 @@ bool Sema::CheckOtherCall(CallExpr *TheCall, const FunctionProtoType *Proto) {
}
static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
- if (Ordering < AtomicExpr::AO_ABI_memory_order_relaxed ||
- Ordering > AtomicExpr::AO_ABI_memory_order_seq_cst)
+ if (!llvm::isValidAtomicOrderingCABI(Ordering))
return false;
+ auto OrderingCABI = (llvm::AtomicOrderingCABI)Ordering;
switch (Op) {
case AtomicExpr::AO__c11_atomic_init:
llvm_unreachable("There is no ordering argument for an init");
@@ -1545,15 +2259,15 @@ static bool isValidOrderingForOp(int64_t Ordering, AtomicExpr::AtomicOp Op) {
case AtomicExpr::AO__c11_atomic_load:
case AtomicExpr::AO__atomic_load_n:
case AtomicExpr::AO__atomic_load:
- return Ordering != AtomicExpr::AO_ABI_memory_order_release &&
- Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel;
+ return OrderingCABI != llvm::AtomicOrderingCABI::release &&
+ OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
- return Ordering != AtomicExpr::AO_ABI_memory_order_consume &&
- Ordering != AtomicExpr::AO_ABI_memory_order_acquire &&
- Ordering != AtomicExpr::AO_ABI_memory_order_acq_rel;
+ return OrderingCABI != llvm::AtomicOrderingCABI::consume &&
+ OrderingCABI != llvm::AtomicOrderingCABI::acquire &&
+ OrderingCABI != llvm::AtomicOrderingCABI::acq_rel;
default:
return true;
@@ -1572,6 +2286,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// C __c11_atomic_load(A *, int)
Load,
// void __atomic_load(A *, CP, int)
+ LoadCopy,
+ // void __atomic_store(A *, CP, int)
Copy,
// C __c11_atomic_add(A *, M, int)
Arithmetic,
@@ -1584,8 +2300,8 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// bool __atomic_compare_exchange(A *, C *, CP, bool, int, int)
GNUCmpXchg
} Form = Init;
- const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 4, 5, 6 };
- const unsigned NumVals[] = { 1, 0, 1, 1, 1, 2, 2, 3 };
+ const unsigned NumArgs[] = { 2, 2, 3, 3, 3, 3, 4, 5, 6 };
+ const unsigned NumVals[] = { 1, 0, 1, 1, 1, 1, 2, 2, 3 };
// where:
// C is an appropriate type,
// A is volatile _Atomic(C) for __c11 builtins and is C for GNU builtins,
@@ -1615,8 +2331,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
Form = Load;
break;
- case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__atomic_load:
+ Form = LoadCopy;
+ break;
+
+ case AtomicExpr::AO__c11_atomic_store:
case AtomicExpr::AO__atomic_store:
case AtomicExpr::AO__atomic_store_n:
Form = Copy;
@@ -1680,7 +2399,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// Inspect the first argument of the atomic operation.
Expr *Ptr = TheCall->getArg(0);
- Ptr = DefaultFunctionArrayLvalueConversion(Ptr).get();
+ ExprResult ConvertedPtr = DefaultFunctionArrayLvalueConversion(Ptr);
+ if (ConvertedPtr.isInvalid())
+ return ExprError();
+
+ Ptr = ConvertedPtr.get();
const PointerType *pointerType = Ptr->getType()->getAs<PointerType>();
if (!pointerType) {
Diag(DRE->getLocStart(), diag::err_atomic_builtin_must_be_pointer)
@@ -1703,7 +2426,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
return ExprError();
}
ValType = AtomTy->getAs<AtomicType>()->getValueType();
- } else if (Form != Load && Op != AtomicExpr::AO__atomic_load) {
+ } else if (Form != Load && Form != LoadCopy) {
if (ValType.isConstQualified()) {
Diag(DRE->getLocStart(), diag::err_atomic_op_needs_non_const_pointer)
<< Ptr->getType() << Ptr->getSourceRange();
@@ -1764,10 +2487,11 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
// atomic_fetch_or takes a pointer to a volatile 'A'. We shouldn't let the
// volatile-ness of the pointee-type inject itself into the result or the
- // other operands.
+ // other operands. Similarly atomic_load can take a pointer to a const 'A'.
ValType.removeLocalVolatile();
+ ValType.removeLocalConst();
QualType ResultType = ValType;
- if (Form == Copy || Form == GNUXchg || Form == Init)
+ if (Form == Copy || Form == LoadCopy || Form == GNUXchg || Form == Init)
ResultType = Context.VoidTy;
else if (Form == C11CmpXchg || Form == GNUCmpXchg)
ResultType = Context.BoolTy;
@@ -1778,10 +2502,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
if (!IsC11 && !IsN)
ByValType = Ptr->getType();
- // FIXME: __atomic_load allows the first argument to be a a pointer to const
- // but not the second argument. We need to manually remove possible const
- // qualifiers.
-
// The first argument --- the pointer --- has a fixed type; we
// deduce the types of the rest of the arguments accordingly. Walk
// the remaining arguments, converting them to the deduced value type.
@@ -1848,6 +2568,7 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
case Load:
SubExprs.push_back(TheCall->getArg(1)); // Order
break;
+ case LoadCopy:
case Copy:
case Arithmetic:
case Xchg:
@@ -1897,7 +2618,6 @@ ExprResult Sema::SemaAtomicOpsOverloaded(ExprResult TheCallResult,
return AE;
}
-
/// checkBuiltinArgument - Given a call to a builtin function, perform
/// normal type-checking on the given argument, updating the call in
/// place. This is useful when a builtin function requires custom
@@ -2443,6 +3163,7 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
// block.
QualType Type;
SourceLocation ParamLoc;
+ bool IsCRegister = false;
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(Arg)) {
if (const ParmVarDecl *PV = dyn_cast<ParmVarDecl>(DR->getDecl())) {
@@ -2450,24 +3171,30 @@ bool Sema::SemaBuiltinVAStartImpl(CallExpr *TheCall) {
// Get the last formal in the current function.
const ParmVarDecl *LastArg;
if (CurBlock)
- LastArg = *(CurBlock->TheDecl->param_end()-1);
+ LastArg = CurBlock->TheDecl->parameters().back();
else if (FunctionDecl *FD = getCurFunctionDecl())
- LastArg = *(FD->param_end()-1);
+ LastArg = FD->parameters().back();
else
- LastArg = *(getCurMethodDecl()->param_end()-1);
+ LastArg = getCurMethodDecl()->parameters().back();
SecondArgIsLastNamedArgument = PV == LastArg;
Type = PV->getType();
ParamLoc = PV->getLocation();
+ IsCRegister =
+ PV->getStorageClass() == SC_Register && !getLangOpts().CPlusPlus;
}
}
if (!SecondArgIsLastNamedArgument)
Diag(TheCall->getArg(1)->getLocStart(),
- diag::warn_second_parameter_of_va_start_not_last_named_argument);
- else if (Type->isReferenceType()) {
- Diag(Arg->getLocStart(),
- diag::warn_va_start_of_reference_type_is_undefined);
+ diag::warn_second_arg_of_va_start_not_last_named_param);
+ else if (IsCRegister || Type->isReferenceType() ||
+ Type->isPromotableIntegerType() ||
+ Type->isSpecificBuiltinType(BuiltinType::Float)) {
+ unsigned Reason = 0;
+ if (Type->isReferenceType()) Reason = 1;
+ else if (IsCRegister) Reason = 2;
+ Diag(Arg->getLocStart(), diag::warn_va_start_type_is_undefined) << Reason;
Diag(ParamLoc, diag::note_parameter_type) << Type;
}
@@ -2662,8 +3389,7 @@ ExprResult Sema::SemaBuiltinShuffleVector(CallExpr *TheCall) {
// Determine which of the following types of shufflevector we're checking:
// 1) unary, vector mask: (lhs, mask)
- // 2) binary, vector mask: (lhs, rhs, mask)
- // 3) binary, scalar mask: (lhs, rhs, index, ..., index)
+ // 2) binary, scalar mask: (lhs, rhs, index, ..., index)
QualType resType = TheCall->getArg(0)->getType();
unsigned numElements = 0;
@@ -3002,7 +3728,6 @@ bool Sema::SemaBuiltinLongjmp(CallExpr *TheCall) {
return false;
}
-
/// SemaBuiltinSetjmp - Handle __builtin_setjmp(void *env[5]).
/// This checks that the target supports __builtin_setjmp.
bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) {
@@ -3013,12 +3738,68 @@ bool Sema::SemaBuiltinSetjmp(CallExpr *TheCall) {
}
namespace {
+class UncoveredArgHandler {
+ enum { Unknown = -1, AllCovered = -2 };
+ signed FirstUncoveredArg;
+ SmallVector<const Expr *, 4> DiagnosticExprs;
+
+public:
+ UncoveredArgHandler() : FirstUncoveredArg(Unknown) { }
+
+ bool hasUncoveredArg() const {
+ return (FirstUncoveredArg >= 0);
+ }
+
+ unsigned getUncoveredArg() const {
+ assert(hasUncoveredArg() && "no uncovered argument");
+ return FirstUncoveredArg;
+ }
+
+ void setAllCovered() {
+ // A string has been found with all arguments covered, so clear out
+ // the diagnostics.
+ DiagnosticExprs.clear();
+ FirstUncoveredArg = AllCovered;
+ }
+
+ void Update(signed NewFirstUncoveredArg, const Expr *StrExpr) {
+ assert(NewFirstUncoveredArg >= 0 && "Outside range");
+
+ // Don't update if a previous string covers all arguments.
+ if (FirstUncoveredArg == AllCovered)
+ return;
+
+ // UncoveredArgHandler tracks the highest uncovered argument index
+ // and with it all the strings that match this index.
+ if (NewFirstUncoveredArg == FirstUncoveredArg)
+ DiagnosticExprs.push_back(StrExpr);
+ else if (NewFirstUncoveredArg > FirstUncoveredArg) {
+ DiagnosticExprs.clear();
+ DiagnosticExprs.push_back(StrExpr);
+ FirstUncoveredArg = NewFirstUncoveredArg;
+ }
+ }
+
+ void Diagnose(Sema &S, bool IsFunctionCall, const Expr *ArgExpr);
+};
+
enum StringLiteralCheckType {
SLCT_NotALiteral,
SLCT_UncheckedLiteral,
SLCT_CheckedLiteral
};
-}
+} // end anonymous namespace
+
+static void CheckFormatString(Sema &S, const StringLiteral *FExpr,
+ const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg,
+ Sema::FormatStringType Type,
+ bool inFunctionCall,
+ Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg);
// Determine if an expression is a string literal or constant string.
// If this function returns false on the arguments to a function expecting a
@@ -3029,7 +3810,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
bool HasVAListArg, unsigned format_idx,
unsigned firstDataArg, Sema::FormatStringType Type,
Sema::VariadicCallType CallType, bool InFunctionCall,
- llvm::SmallBitVector &CheckedVarArgs) {
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg) {
tryAgain:
if (E->isTypeDependent() || E->isValueDependent())
return SLCT_NotALiteral;
@@ -3050,17 +3832,39 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
// completely checked only if both sub-expressions were checked.
const AbstractConditionalOperator *C =
cast<AbstractConditionalOperator>(E);
- StringLiteralCheckType Left =
- checkFormatStringExpr(S, C->getTrueExpr(), Args,
- HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs);
- if (Left == SLCT_NotALiteral)
- return SLCT_NotALiteral;
+
+ // Determine whether it is necessary to check both sub-expressions, for
+ // example, because the condition expression is a constant that can be
+ // evaluated at compile time.
+ bool CheckLeft = true, CheckRight = true;
+
+ bool Cond;
+ if (C->getCond()->EvaluateAsBooleanCondition(Cond, S.getASTContext())) {
+ if (Cond)
+ CheckRight = false;
+ else
+ CheckLeft = false;
+ }
+
+ StringLiteralCheckType Left;
+ if (!CheckLeft)
+ Left = SLCT_UncheckedLiteral;
+ else {
+ Left = checkFormatStringExpr(S, C->getTrueExpr(), Args,
+ HasVAListArg, format_idx, firstDataArg,
+ Type, CallType, InFunctionCall,
+ CheckedVarArgs, UncoveredArg);
+ if (Left == SLCT_NotALiteral || !CheckRight)
+ return Left;
+ }
+
StringLiteralCheckType Right =
checkFormatStringExpr(S, C->getFalseExpr(), Args,
HasVAListArg, format_idx, firstDataArg,
- Type, CallType, InFunctionCall, CheckedVarArgs);
- return Left < Right ? Left : Right;
+ Type, CallType, InFunctionCall, CheckedVarArgs,
+ UncoveredArg);
+
+ return (CheckLeft && Left < Right) ? Left : Right;
}
case Stmt::ImplicitCastExprClass: {
@@ -3111,7 +3915,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return checkFormatStringExpr(S, Init, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
- /*InFunctionCall*/false, CheckedVarArgs);
+ /*InFunctionCall*/false, CheckedVarArgs,
+ UncoveredArg);
}
}
@@ -3166,7 +3971,7 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return checkFormatStringExpr(S, Arg, Args,
HasVAListArg, format_idx, firstDataArg,
Type, CallType, InFunctionCall,
- CheckedVarArgs);
+ CheckedVarArgs, UncoveredArg);
} else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND)) {
unsigned BuiltinID = FD->getBuiltinID();
if (BuiltinID == Builtin::BI__builtin___CFStringMakeConstantString ||
@@ -3175,7 +3980,8 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
return checkFormatStringExpr(S, Arg, Args,
HasVAListArg, format_idx,
firstDataArg, Type, CallType,
- InFunctionCall, CheckedVarArgs);
+ InFunctionCall, CheckedVarArgs,
+ UncoveredArg);
}
}
}
@@ -3192,8 +3998,9 @@ checkFormatStringExpr(Sema &S, const Expr *E, ArrayRef<const Expr *> Args,
StrE = cast<StringLiteral>(E);
if (StrE) {
- S.CheckFormatString(StrE, E, Args, HasVAListArg, format_idx, firstDataArg,
- Type, InFunctionCall, CallType, CheckedVarArgs);
+ CheckFormatString(S, StrE, E, Args, HasVAListArg, format_idx,
+ firstDataArg, Type, InFunctionCall, CallType,
+ CheckedVarArgs, UncoveredArg);
return SLCT_CheckedLiteral;
}
@@ -3261,10 +4068,20 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// C string (e.g. "%d")
// ObjC string uses the same format specifiers as C string, so we can use
// the same format string checking logic for both ObjC and C strings.
+ UncoveredArgHandler UncoveredArg;
StringLiteralCheckType CT =
checkFormatStringExpr(*this, OrigFormatExpr, Args, HasVAListArg,
format_idx, firstDataArg, Type, CallType,
- /*IsFunctionCall*/true, CheckedVarArgs);
+ /*IsFunctionCall*/true, CheckedVarArgs,
+ UncoveredArg);
+
+ // Generate a diagnostic where an uncovered argument is detected.
+ if (UncoveredArg.hasUncoveredArg()) {
+ unsigned ArgIdx = UncoveredArg.getUncoveredArg() + firstDataArg;
+ assert(ArgIdx < Args.size() && "ArgIdx outside bounds");
+ UncoveredArg.Diagnose(*this, /*IsFunctionCall*/true, Args[ArgIdx]);
+ }
+
if (CT != SLCT_NotALiteral)
// Literal format string found, check done!
return CT == SLCT_CheckedLiteral;
@@ -3278,20 +4095,33 @@ bool Sema::CheckFormatArguments(ArrayRef<const Expr *> Args,
// format is either NSString or CFString. This is a hack to prevent
// diag when using the NSLocalizedString and CFCopyLocalizedString macros
// which are usually used in place of NS and CF string literals.
- if (Type == FST_NSString &&
- SourceMgr.isInSystemMacro(Args[format_idx]->getLocStart()))
+ SourceLocation FormatLoc = Args[format_idx]->getLocStart();
+ if (Type == FST_NSString && SourceMgr.isInSystemMacro(FormatLoc))
return false;
// If there are no arguments specified, warn with -Wformat-security, otherwise
// warn only with -Wformat-nonliteral.
- if (Args.size() == firstDataArg)
- Diag(Args[format_idx]->getLocStart(),
- diag::warn_format_nonliteral_noargs)
+ if (Args.size() == firstDataArg) {
+ Diag(FormatLoc, diag::warn_format_nonliteral_noargs)
<< OrigFormatExpr->getSourceRange();
- else
- Diag(Args[format_idx]->getLocStart(),
- diag::warn_format_nonliteral)
- << OrigFormatExpr->getSourceRange();
+ switch (Type) {
+ default:
+ break;
+ case FST_Kprintf:
+ case FST_FreeBSDKPrintf:
+ case FST_Printf:
+ Diag(FormatLoc, diag::note_format_security_fixit)
+ << FixItHint::CreateInsertion(FormatLoc, "\"%s\", ");
+ break;
+ case FST_NSString:
+ Diag(FormatLoc, diag::note_format_security_fixit)
+ << FixItHint::CreateInsertion(FormatLoc, "@\"%@\", ");
+ break;
+ }
+ } else {
+ Diag(FormatLoc, diag::warn_format_nonliteral)
+ << OrigFormatExpr->getSourceRange();
+ }
return false;
}
@@ -3313,6 +4143,8 @@ protected:
bool inFunctionCall;
Sema::VariadicCallType CallType;
llvm::SmallBitVector &CheckedVarArgs;
+ UncoveredArgHandler &UncoveredArg;
+
public:
CheckFormatHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
@@ -3320,14 +4152,15 @@ public:
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType callType,
- llvm::SmallBitVector &CheckedVarArgs)
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg)
: S(s), FExpr(fexpr), OrigFormatExpr(origFormatExpr),
FirstDataArg(firstDataArg), NumDataArgs(numDataArgs),
Beg(beg), HasVAListArg(hasVAListArg),
Args(Args), FormatIdx(formatIdx),
usesPositionalArgs(false), atFirstArg(true),
inFunctionCall(inFunctionCall), CallType(callType),
- CheckedVarArgs(CheckedVarArgs) {
+ CheckedVarArgs(CheckedVarArgs), UncoveredArg(UncoveredArg) {
CoveredArgs.resize(numDataArgs);
CoveredArgs.reset();
}
@@ -3362,12 +4195,11 @@ public:
void HandleNullChar(const char *nullCharacter) override;
template <typename Range>
- static void EmitFormatDiagnostic(Sema &S, bool inFunctionCall,
- const Expr *ArgumentExpr,
- PartialDiagnostic PDiag,
- SourceLocation StringLoc,
- bool IsStringLocation, Range StringRange,
- ArrayRef<FixItHint> Fixit = None);
+ static void
+ EmitFormatDiagnostic(Sema &S, bool inFunctionCall, const Expr *ArgumentExpr,
+ const PartialDiagnostic &PDiag, SourceLocation StringLoc,
+ bool IsStringLocation, Range StringRange,
+ ArrayRef<FixItHint> Fixit = None);
protected:
bool HandleInvalidConversionSpecifier(unsigned argIndex, SourceLocation Loc,
@@ -3396,7 +4228,7 @@ protected:
bool IsStringLocation, Range StringRange,
ArrayRef<FixItHint> Fixit = None);
};
-}
+} // end anonymous namespace
SourceRange CheckFormatHandler::getFormatStringRange() {
return OrigFormatExpr->getSourceRange();
@@ -3558,26 +4390,44 @@ const Expr *CheckFormatHandler::getDataArg(unsigned i) const {
}
void CheckFormatHandler::DoneProcessing() {
- // Does the number of data arguments exceed the number of
- // format conversions in the format string?
+ // Does the number of data arguments exceed the number of
+ // format conversions in the format string?
if (!HasVAListArg) {
// Find any arguments that weren't covered.
CoveredArgs.flip();
signed notCoveredArg = CoveredArgs.find_first();
if (notCoveredArg >= 0) {
assert((unsigned)notCoveredArg < NumDataArgs);
- if (const Expr *E = getDataArg((unsigned) notCoveredArg)) {
- SourceLocation Loc = E->getLocStart();
- if (!S.getSourceManager().isInSystemMacro(Loc)) {
- EmitFormatDiagnostic(S.PDiag(diag::warn_printf_data_arg_not_used),
- Loc, /*IsStringLocation*/false,
- getFormatStringRange());
- }
- }
+ UncoveredArg.Update(notCoveredArg, OrigFormatExpr);
+ } else {
+ UncoveredArg.setAllCovered();
}
}
}
+void UncoveredArgHandler::Diagnose(Sema &S, bool IsFunctionCall,
+ const Expr *ArgExpr) {
+ assert(hasUncoveredArg() && DiagnosticExprs.size() > 0 &&
+ "Invalid state");
+
+ if (!ArgExpr)
+ return;
+
+ SourceLocation Loc = ArgExpr->getLocStart();
+
+ if (S.getSourceManager().isInSystemMacro(Loc))
+ return;
+
+ PartialDiagnostic PDiag = S.PDiag(diag::warn_printf_data_arg_not_used);
+ for (auto E : DiagnosticExprs)
+ PDiag << E->getSourceRange();
+
+ CheckFormatHandler::EmitFormatDiagnostic(
+ S, IsFunctionCall, DiagnosticExprs[0],
+ PDiag, Loc, /*IsStringLocation*/false,
+ DiagnosticExprs[0]->getSourceRange());
+}
+
bool
CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
SourceLocation Loc,
@@ -3585,7 +4435,6 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
unsigned specifierLen,
const char *csStart,
unsigned csLen) {
-
bool keepGoing = true;
if (argIndex < NumDataArgs) {
// Consider the argument coverered, even though the specifier doesn't
@@ -3600,12 +4449,41 @@ CheckFormatHandler::HandleInvalidConversionSpecifier(unsigned argIndex,
// gibberish when trying to match arguments.
keepGoing = false;
}
-
- EmitFormatDiagnostic(S.PDiag(diag::warn_format_invalid_conversion)
- << StringRef(csStart, csLen),
- Loc, /*IsStringLocation*/true,
- getSpecifierRange(startSpec, specifierLen));
-
+
+ StringRef Specifier(csStart, csLen);
+
+ // If the specifier in non-printable, it could be the first byte of a UTF-8
+ // sequence. In that case, print the UTF-8 code point. If not, print the byte
+ // hex value.
+ std::string CodePointStr;
+ if (!llvm::sys::locale::isPrint(*csStart)) {
+ UTF32 CodePoint;
+ const UTF8 **B = reinterpret_cast<const UTF8 **>(&csStart);
+ const UTF8 *E =
+ reinterpret_cast<const UTF8 *>(csStart + csLen);
+ ConversionResult Result =
+ llvm::convertUTF8Sequence(B, E, &CodePoint, strictConversion);
+
+ if (Result != conversionOK) {
+ unsigned char FirstChar = *csStart;
+ CodePoint = (UTF32)FirstChar;
+ }
+
+ llvm::raw_string_ostream OS(CodePointStr);
+ if (CodePoint < 256)
+ OS << "\\x" << llvm::format("%02x", CodePoint);
+ else if (CodePoint <= 0xFFFF)
+ OS << "\\u" << llvm::format("%04x", CodePoint);
+ else
+ OS << "\\U" << llvm::format("%08x", CodePoint);
+ OS.flush();
+ Specifier = CodePointStr;
+ }
+
+ EmitFormatDiagnostic(
+ S.PDiag(diag::warn_format_invalid_conversion) << Specifier, Loc,
+ /*IsStringLocation*/ true, getSpecifierRange(startSpec, specifierLen));
+
return keepGoing;
}
@@ -3632,6 +4510,10 @@ CheckFormatHandler::CheckNumArgs(
EmitFormatDiagnostic(
PDiag, getLocationOfByte(CS.getStart()), /*IsStringLocation*/true,
getSpecifierRange(startSpecifier, specifierLen));
+
+ // Since more arguments than conversion tokens are given, by extension
+ // all arguments are covered, so mark this as so.
+ UncoveredArg.setAllCovered();
return false;
}
return true;
@@ -3674,14 +4556,11 @@ void CheckFormatHandler::EmitFormatDiagnostic(PartialDiagnostic PDiag,
/// templated so it can accept either a CharSourceRange or a SourceRange.
///
/// \param FixIt optional fix it hint for the format string.
-template<typename Range>
-void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
- const Expr *ArgumentExpr,
- PartialDiagnostic PDiag,
- SourceLocation Loc,
- bool IsStringLocation,
- Range StringRange,
- ArrayRef<FixItHint> FixIt) {
+template <typename Range>
+void CheckFormatHandler::EmitFormatDiagnostic(
+ Sema &S, bool InFunctionCall, const Expr *ArgumentExpr,
+ const PartialDiagnostic &PDiag, SourceLocation Loc, bool IsStringLocation,
+ Range StringRange, ArrayRef<FixItHint> FixIt) {
if (InFunctionCall) {
const Sema::SemaDiagnosticBuilder &D = S.Diag(Loc, PDiag);
D << StringRange;
@@ -3704,6 +4583,7 @@ void CheckFormatHandler::EmitFormatDiagnostic(Sema &S, bool InFunctionCall,
namespace {
class CheckPrintfHandler : public CheckFormatHandler {
bool ObjCContext;
+
public:
CheckPrintfHandler(Sema &s, const StringLiteral *fexpr,
const Expr *origFormatExpr, unsigned firstDataArg,
@@ -3712,14 +4592,15 @@ public:
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs)
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg, Args,
- formatIdx, inFunctionCall, CallType, CheckedVarArgs),
+ formatIdx, inFunctionCall, CallType, CheckedVarArgs,
+ UncoveredArg),
ObjCContext(isObjC)
{}
-
bool HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
const char *startSpecifier,
@@ -3760,7 +4641,7 @@ public:
const char *conversionPosition)
override;
};
-}
+} // end anonymous namespace
bool CheckPrintfHandler::HandleInvalidPrintfConversionSpecifier(
const analyze_printf::PrintfSpecifier &FS,
@@ -3779,7 +4660,6 @@ bool CheckPrintfHandler::HandleAmount(
const analyze_format_string::OptionalAmount &Amt,
unsigned k, const char *startSpecifier,
unsigned specifierLen) {
-
if (Amt.hasDataArgument()) {
if (!HasVAListArg) {
unsigned argIndex = Amt.getArgIndex();
@@ -3991,7 +4871,6 @@ CheckPrintfHandler::HandlePrintfSpecifier(const analyze_printf::PrintfSpecifier
&FS,
const char *startSpecifier,
unsigned specifierLen) {
-
using namespace analyze_format_string;
using namespace analyze_printf;
const PrintfConversionSpecifier &CS = FS.getConversionSpecifier();
@@ -4361,7 +5240,6 @@ CheckPrintfHandler::checkFormatExpr(const analyze_printf::PrintfSpecifier &FS,
E->getLocStart(),
/*IsStringLocation*/ false, SpecRange,
FixItHint::CreateReplacement(SpecRange, os.str()));
-
} else {
// The canonical type for formatting this value is different from the
// actual type of the expression. (This occurs, for example, with Darwin's
@@ -4500,11 +5378,12 @@ public:
ArrayRef<const Expr *> Args,
unsigned formatIdx, bool inFunctionCall,
Sema::VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs)
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg)
: CheckFormatHandler(s, fexpr, origFormatExpr, firstDataArg,
numDataArgs, beg, hasVAListArg,
Args, formatIdx, inFunctionCall, CallType,
- CheckedVarArgs)
+ CheckedVarArgs, UncoveredArg)
{}
bool HandleScanfSpecifier(const analyze_scanf::ScanfSpecifier &FS,
@@ -4518,7 +5397,7 @@ public:
void HandleIncompleteScanList(const char *start, const char *end) override;
};
-}
+} // end anonymous namespace
void CheckScanfHandler::HandleIncompleteScanList(const char *start,
const char *end) {
@@ -4545,7 +5424,6 @@ bool CheckScanfHandler::HandleScanfSpecifier(
const analyze_scanf::ScanfSpecifier &FS,
const char *startSpecifier,
unsigned specifierLen) {
-
using namespace analyze_scanf;
using namespace analyze_format_string;
@@ -4665,28 +5543,31 @@ bool CheckScanfHandler::HandleScanfSpecifier(
return true;
}
-void Sema::CheckFormatString(const StringLiteral *FExpr,
- const Expr *OrigFormatExpr,
- ArrayRef<const Expr *> Args,
- bool HasVAListArg, unsigned format_idx,
- unsigned firstDataArg, FormatStringType Type,
- bool inFunctionCall, VariadicCallType CallType,
- llvm::SmallBitVector &CheckedVarArgs) {
-
+static void CheckFormatString(Sema &S, const StringLiteral *FExpr,
+ const Expr *OrigFormatExpr,
+ ArrayRef<const Expr *> Args,
+ bool HasVAListArg, unsigned format_idx,
+ unsigned firstDataArg,
+ Sema::FormatStringType Type,
+ bool inFunctionCall,
+ Sema::VariadicCallType CallType,
+ llvm::SmallBitVector &CheckedVarArgs,
+ UncoveredArgHandler &UncoveredArg) {
// CHECK: is the format string a wide literal?
if (!FExpr->isAscii() && !FExpr->isUTF8()) {
CheckFormatHandler::EmitFormatDiagnostic(
- *this, inFunctionCall, Args[format_idx],
- PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
+ S, inFunctionCall, Args[format_idx],
+ S.PDiag(diag::warn_format_string_is_wide_literal), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
-
+
// Str - The format string. NOTE: this is NOT null-terminated!
StringRef StrRef = FExpr->getString();
const char *Str = StrRef.data();
// Account for cases where the string literal is truncated in a declaration.
- const ConstantArrayType *T = Context.getAsConstantArrayType(FExpr->getType());
+ const ConstantArrayType *T =
+ S.Context.getAsConstantArrayType(FExpr->getType());
assert(T && "String literal not of constant array type!");
size_t TypeSize = T->getSize().getZExtValue();
size_t StrLen = std::min(std::max(TypeSize, size_t(1)) - 1, StrRef.size());
@@ -4697,8 +5578,8 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
if (TypeSize <= StrRef.size() &&
StrRef.substr(0, TypeSize).find('\0') == StringRef::npos) {
CheckFormatHandler::EmitFormatDiagnostic(
- *this, inFunctionCall, Args[format_idx],
- PDiag(diag::warn_printf_format_string_not_null_terminated),
+ S, inFunctionCall, Args[format_idx],
+ S.PDiag(diag::warn_printf_format_string_not_null_terminated),
FExpr->getLocStart(),
/*IsStringLocation=*/true, OrigFormatExpr->getSourceRange());
return;
@@ -4707,32 +5588,35 @@ void Sema::CheckFormatString(const StringLiteral *FExpr,
// CHECK: empty format string?
if (StrLen == 0 && numDataArgs > 0) {
CheckFormatHandler::EmitFormatDiagnostic(
- *this, inFunctionCall, Args[format_idx],
- PDiag(diag::warn_empty_format_string), FExpr->getLocStart(),
+ S, inFunctionCall, Args[format_idx],
+ S.PDiag(diag::warn_empty_format_string), FExpr->getLocStart(),
/*IsStringLocation*/true, OrigFormatExpr->getSourceRange());
return;
}
-
- if (Type == FST_Printf || Type == FST_NSString ||
- Type == FST_FreeBSDKPrintf || Type == FST_OSTrace) {
- CheckPrintfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg,
- numDataArgs, (Type == FST_NSString || Type == FST_OSTrace),
+
+ if (Type == Sema::FST_Printf || Type == Sema::FST_NSString ||
+ Type == Sema::FST_FreeBSDKPrintf || Type == Sema::FST_OSTrace) {
+ CheckPrintfHandler H(S, FExpr, OrigFormatExpr, firstDataArg,
+ numDataArgs, (Type == Sema::FST_NSString ||
+ Type == Sema::FST_OSTrace),
Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType, CheckedVarArgs);
-
+ inFunctionCall, CallType, CheckedVarArgs,
+ UncoveredArg);
+
if (!analyze_format_string::ParsePrintfString(H, Str, Str + StrLen,
- getLangOpts(),
- Context.getTargetInfo(),
- Type == FST_FreeBSDKPrintf))
+ S.getLangOpts(),
+ S.Context.getTargetInfo(),
+ Type == Sema::FST_FreeBSDKPrintf))
H.DoneProcessing();
- } else if (Type == FST_Scanf) {
- CheckScanfHandler H(*this, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
+ } else if (Type == Sema::FST_Scanf) {
+ CheckScanfHandler H(S, FExpr, OrigFormatExpr, firstDataArg, numDataArgs,
Str, HasVAListArg, Args, format_idx,
- inFunctionCall, CallType, CheckedVarArgs);
-
+ inFunctionCall, CallType, CheckedVarArgs,
+ UncoveredArg);
+
if (!analyze_format_string::ParseScanfString(H, Str, Str + StrLen,
- getLangOpts(),
- Context.getTargetInfo()))
+ S.getLangOpts(),
+ S.Context.getTargetInfo()))
H.DoneProcessing();
} // TODO: handle other formats
}
@@ -5145,7 +6029,6 @@ void Sema::CheckAbsoluteValueFunction(const CallExpr *Call,
emitReplacement(*this, Call->getExprLoc(),
Call->getCallee()->getSourceRange(), NewAbsKind, ArgType);
- return;
}
//===--- CHECK: Standard memory functions ---------------------------------===//
@@ -5191,7 +6074,7 @@ static const CXXRecordDecl *getContainedDynamicClass(QualType T,
const CXXRecordDecl *RD = Ty->getAsCXXRecordDecl();
RD = RD ? RD->getDefinition() : nullptr;
- if (!RD)
+ if (!RD || RD->isInvalidDecl())
return nullptr;
if (RD->isDynamicClass())
@@ -5398,7 +6281,6 @@ void Sema::CheckMemaccessArguments(const CallExpr *Call,
<< FixItHint::CreateInsertion(ArgRange.getBegin(), "(void*)"));
break;
}
-
}
// A little helper routine: ignore addition and subtraction of integer literals.
@@ -5613,10 +6495,12 @@ void Sema::CheckStrncatArguments(const CallExpr *CE,
//===--- CHECK: Return Address of Stack Variable --------------------------===//
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
- Decl *ParentDecl);
-static Expr *EvalAddr(Expr* E, SmallVectorImpl<DeclRefExpr *> &refVars,
- Decl *ParentDecl);
+static const Expr *EvalVal(const Expr *E,
+ SmallVectorImpl<const DeclRefExpr *> &refVars,
+ const Decl *ParentDecl);
+static const Expr *EvalAddr(const Expr *E,
+ SmallVectorImpl<const DeclRefExpr *> &refVars,
+ const Decl *ParentDecl);
/// CheckReturnStackAddr - Check if a return statement returns the address
/// of a stack variable.
@@ -5624,8 +6508,8 @@ static void
CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
SourceLocation ReturnLoc) {
- Expr *stackE = nullptr;
- SmallVector<DeclRefExpr *, 8> refVars;
+ const Expr *stackE = nullptr;
+ SmallVector<const DeclRefExpr *, 8> refVars;
// Perform checking for returned stack addresses, local blocks,
// label addresses or references to temporaries.
@@ -5653,7 +6537,8 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
diagRange = refVars[0]->getSourceRange();
}
- if (DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) { //address of local var.
+ if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(stackE)) {
+ // address of local var
S.Diag(diagLoc, diag::warn_ret_stack_addr_ref) << lhsType->isReferenceType()
<< DR->getDecl()->getDeclName() << diagRange;
} else if (isa<BlockExpr>(stackE)) { // local block.
@@ -5668,12 +6553,12 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
// Display the "trail" of reference variables that we followed until we
// found the problematic expression using notes.
for (unsigned i = 0, e = refVars.size(); i != e; ++i) {
- VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl());
+ const VarDecl *VD = cast<VarDecl>(refVars[i]->getDecl());
// If this var binds to another reference var, show the range of the next
// var, otherwise the var binds to the problematic expression, in which case
// show the range of the expression.
- SourceRange range = (i < e-1) ? refVars[i+1]->getSourceRange()
- : stackE->getSourceRange();
+ SourceRange range = (i < e - 1) ? refVars[i + 1]->getSourceRange()
+ : stackE->getSourceRange();
S.Diag(VD->getLocation(), diag::note_ref_var_local_bind)
<< VD->getDeclName() << range;
}
@@ -5705,8 +6590,9 @@ CheckReturnStackAddr(Sema &S, Expr *RetValExp, QualType lhsType,
/// * arbitrary interplay between "&" and "*" operators
/// * pointer arithmetic from an address of a stack variable
/// * taking the address of an array element where the array is on the stack
-static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
- Decl *ParentDecl) {
+static const Expr *EvalAddr(const Expr *E,
+ SmallVectorImpl<const DeclRefExpr *> &refVars,
+ const Decl *ParentDecl) {
if (E->isTypeDependent())
return nullptr;
@@ -5723,13 +6609,13 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
// EvalAddr and EvalVal appropriately.
switch (E->getStmtClass()) {
case Stmt::DeclRefExprClass: {
- DeclRefExpr *DR = cast<DeclRefExpr>(E);
+ const DeclRefExpr *DR = cast<DeclRefExpr>(E);
// If we leave the immediate function, the lifetime isn't about to end.
if (DR->refersToEnclosingVariableOrCapture())
return nullptr;
- if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
+ if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl()))
// If this is a reference variable, follow through to the expression that
// it points to.
if (V->hasLocalStorage() &&
@@ -5745,44 +6631,44 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
case Stmt::UnaryOperatorClass: {
// The only unary operator that make sense to handle here
// is AddrOf. All others don't make sense as pointers.
- UnaryOperator *U = cast<UnaryOperator>(E);
+ const UnaryOperator *U = cast<UnaryOperator>(E);
if (U->getOpcode() == UO_AddrOf)
return EvalVal(U->getSubExpr(), refVars, ParentDecl);
- else
- return nullptr;
+ return nullptr;
}
case Stmt::BinaryOperatorClass: {
// Handle pointer arithmetic. All other binary operators are not valid
// in this context.
- BinaryOperator *B = cast<BinaryOperator>(E);
+ const BinaryOperator *B = cast<BinaryOperator>(E);
BinaryOperatorKind op = B->getOpcode();
if (op != BO_Add && op != BO_Sub)
return nullptr;
- Expr *Base = B->getLHS();
+ const Expr *Base = B->getLHS();
// Determine which argument is the real pointer base. It could be
// the RHS argument instead of the LHS.
- if (!Base->getType()->isPointerType()) Base = B->getRHS();
+ if (!Base->getType()->isPointerType())
+ Base = B->getRHS();
- assert (Base->getType()->isPointerType());
+ assert(Base->getType()->isPointerType());
return EvalAddr(Base, refVars, ParentDecl);
}
// For conditional operators we need to see if either the LHS or RHS are
// valid DeclRefExpr*s. If one of them is valid, we return it.
case Stmt::ConditionalOperatorClass: {
- ConditionalOperator *C = cast<ConditionalOperator>(E);
+ const ConditionalOperator *C = cast<ConditionalOperator>(E);
// Handle the GNU extension for missing LHS.
// FIXME: That isn't a ConditionalOperator, so doesn't get here.
- if (Expr *LHSExpr = C->getLHS()) {
+ if (const Expr *LHSExpr = C->getLHS()) {
// In C++, we can have a throw-expression, which has 'void' type.
if (!LHSExpr->getType()->isVoidType())
- if (Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl))
+ if (const Expr *LHS = EvalAddr(LHSExpr, refVars, ParentDecl))
return LHS;
}
@@ -5815,7 +6701,7 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
case Stmt::CXXDynamicCastExprClass:
case Stmt::CXXConstCastExprClass:
case Stmt::CXXReinterpretCastExprClass: {
- Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
+ const Expr* SubExpr = cast<CastExpr>(E)->getSubExpr();
switch (cast<CastExpr>(E)->getCastKind()) {
case CK_LValueToRValue:
case CK_NoOp:
@@ -5845,157 +6731,161 @@ static Expr *EvalAddr(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
}
case Stmt::MaterializeTemporaryExprClass:
- if (Expr *Result = EvalAddr(
- cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars, ParentDecl))
+ if (const Expr *Result =
+ EvalAddr(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars, ParentDecl))
return Result;
-
return E;
-
+
// Everything else: we simply don't reason about them.
default:
return nullptr;
}
}
-
/// EvalVal - This function is complements EvalAddr in the mutual recursion.
/// See the comments for EvalAddr for more details.
-static Expr *EvalVal(Expr *E, SmallVectorImpl<DeclRefExpr *> &refVars,
- Decl *ParentDecl) {
-do {
- // We should only be called for evaluating non-pointer expressions, or
- // expressions with a pointer type that are not used as references but instead
- // are l-values (e.g., DeclRefExpr with a pointer type).
-
- // Our "symbolic interpreter" is just a dispatch off the currently
- // viewed AST node. We then recursively traverse the AST by calling
- // EvalAddr and EvalVal appropriately.
-
- E = E->IgnoreParens();
- switch (E->getStmtClass()) {
- case Stmt::ImplicitCastExprClass: {
- ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
- if (IE->getValueKind() == VK_LValue) {
- E = IE->getSubExpr();
- continue;
+static const Expr *EvalVal(const Expr *E,
+ SmallVectorImpl<const DeclRefExpr *> &refVars,
+ const Decl *ParentDecl) {
+ do {
+ // We should only be called for evaluating non-pointer expressions, or
+ // expressions with a pointer type that are not used as references but
+ // instead
+ // are l-values (e.g., DeclRefExpr with a pointer type).
+
+ // Our "symbolic interpreter" is just a dispatch off the currently
+ // viewed AST node. We then recursively traverse the AST by calling
+ // EvalAddr and EvalVal appropriately.
+
+ E = E->IgnoreParens();
+ switch (E->getStmtClass()) {
+ case Stmt::ImplicitCastExprClass: {
+ const ImplicitCastExpr *IE = cast<ImplicitCastExpr>(E);
+ if (IE->getValueKind() == VK_LValue) {
+ E = IE->getSubExpr();
+ continue;
+ }
+ return nullptr;
}
- return nullptr;
- }
-
- case Stmt::ExprWithCleanupsClass:
- return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,ParentDecl);
- case Stmt::DeclRefExprClass: {
- // When we hit a DeclRefExpr we are looking at code that refers to a
- // variable's name. If it's not a reference variable we check if it has
- // local storage within the function, and if so, return the expression.
- DeclRefExpr *DR = cast<DeclRefExpr>(E);
+ case Stmt::ExprWithCleanupsClass:
+ return EvalVal(cast<ExprWithCleanups>(E)->getSubExpr(), refVars,
+ ParentDecl);
- // If we leave the immediate function, the lifetime isn't about to end.
- if (DR->refersToEnclosingVariableOrCapture())
- return nullptr;
+ case Stmt::DeclRefExprClass: {
+ // When we hit a DeclRefExpr we are looking at code that refers to a
+ // variable's name. If it's not a reference variable we check if it has
+ // local storage within the function, and if so, return the expression.
+ const DeclRefExpr *DR = cast<DeclRefExpr>(E);
- if (VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
- // Check if it refers to itself, e.g. "int& i = i;".
- if (V == ParentDecl)
- return DR;
+ // If we leave the immediate function, the lifetime isn't about to end.
+ if (DR->refersToEnclosingVariableOrCapture())
+ return nullptr;
- if (V->hasLocalStorage()) {
- if (!V->getType()->isReferenceType())
+ if (const VarDecl *V = dyn_cast<VarDecl>(DR->getDecl())) {
+ // Check if it refers to itself, e.g. "int& i = i;".
+ if (V == ParentDecl)
return DR;
- // Reference variable, follow through to the expression that
- // it points to.
- if (V->hasInit()) {
- // Add the reference variable to the "trail".
- refVars.push_back(DR);
- return EvalVal(V->getInit(), refVars, V);
+ if (V->hasLocalStorage()) {
+ if (!V->getType()->isReferenceType())
+ return DR;
+
+ // Reference variable, follow through to the expression that
+ // it points to.
+ if (V->hasInit()) {
+ // Add the reference variable to the "trail".
+ refVars.push_back(DR);
+ return EvalVal(V->getInit(), refVars, V);
+ }
}
}
- }
-
- return nullptr;
- }
-
- case Stmt::UnaryOperatorClass: {
- // The only unary operator that make sense to handle here
- // is Deref. All others don't resolve to a "name." This includes
- // handling all sorts of rvalues passed to a unary operator.
- UnaryOperator *U = cast<UnaryOperator>(E);
- if (U->getOpcode() == UO_Deref)
- return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
+ return nullptr;
+ }
- return nullptr;
- }
+ case Stmt::UnaryOperatorClass: {
+ // The only unary operator that make sense to handle here
+ // is Deref. All others don't resolve to a "name." This includes
+ // handling all sorts of rvalues passed to a unary operator.
+ const UnaryOperator *U = cast<UnaryOperator>(E);
- case Stmt::ArraySubscriptExprClass: {
- // Array subscripts are potential references to data on the stack. We
- // retrieve the DeclRefExpr* for the array variable if it indeed
- // has local storage.
- return EvalAddr(cast<ArraySubscriptExpr>(E)->getBase(), refVars,ParentDecl);
- }
+ if (U->getOpcode() == UO_Deref)
+ return EvalAddr(U->getSubExpr(), refVars, ParentDecl);
- case Stmt::OMPArraySectionExprClass: {
- return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars,
- ParentDecl);
- }
+ return nullptr;
+ }
- case Stmt::ConditionalOperatorClass: {
- // For conditional operators we need to see if either the LHS or RHS are
- // non-NULL Expr's. If one is non-NULL, we return it.
- ConditionalOperator *C = cast<ConditionalOperator>(E);
+ case Stmt::ArraySubscriptExprClass: {
+ // Array subscripts are potential references to data on the stack. We
+ // retrieve the DeclRefExpr* for the array variable if it indeed
+ // has local storage.
+ const auto *ASE = cast<ArraySubscriptExpr>(E);
+ if (ASE->isTypeDependent())
+ return nullptr;
+ return EvalAddr(ASE->getBase(), refVars, ParentDecl);
+ }
- // Handle the GNU extension for missing LHS.
- if (Expr *LHSExpr = C->getLHS()) {
- // In C++, we can have a throw-expression, which has 'void' type.
- if (!LHSExpr->getType()->isVoidType())
- if (Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl))
- return LHS;
+ case Stmt::OMPArraySectionExprClass: {
+ return EvalAddr(cast<OMPArraySectionExpr>(E)->getBase(), refVars,
+ ParentDecl);
}
- // In C++, we can have a throw-expression, which has 'void' type.
- if (C->getRHS()->getType()->isVoidType())
- return nullptr;
+ case Stmt::ConditionalOperatorClass: {
+ // For conditional operators we need to see if either the LHS or RHS are
+ // non-NULL Expr's. If one is non-NULL, we return it.
+ const ConditionalOperator *C = cast<ConditionalOperator>(E);
+
+ // Handle the GNU extension for missing LHS.
+ if (const Expr *LHSExpr = C->getLHS()) {
+ // In C++, we can have a throw-expression, which has 'void' type.
+ if (!LHSExpr->getType()->isVoidType())
+ if (const Expr *LHS = EvalVal(LHSExpr, refVars, ParentDecl))
+ return LHS;
+ }
- return EvalVal(C->getRHS(), refVars, ParentDecl);
- }
+ // In C++, we can have a throw-expression, which has 'void' type.
+ if (C->getRHS()->getType()->isVoidType())
+ return nullptr;
- // Accesses to members are potential references to data on the stack.
- case Stmt::MemberExprClass: {
- MemberExpr *M = cast<MemberExpr>(E);
+ return EvalVal(C->getRHS(), refVars, ParentDecl);
+ }
- // Check for indirect access. We only want direct field accesses.
- if (M->isArrow())
- return nullptr;
+ // Accesses to members are potential references to data on the stack.
+ case Stmt::MemberExprClass: {
+ const MemberExpr *M = cast<MemberExpr>(E);
- // Check whether the member type is itself a reference, in which case
- // we're not going to refer to the member, but to what the member refers to.
- if (M->getMemberDecl()->getType()->isReferenceType())
- return nullptr;
+ // Check for indirect access. We only want direct field accesses.
+ if (M->isArrow())
+ return nullptr;
- return EvalVal(M->getBase(), refVars, ParentDecl);
- }
+ // Check whether the member type is itself a reference, in which case
+ // we're not going to refer to the member, but to what the member refers
+ // to.
+ if (M->getMemberDecl()->getType()->isReferenceType())
+ return nullptr;
- case Stmt::MaterializeTemporaryExprClass:
- if (Expr *Result = EvalVal(
- cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
- refVars, ParentDecl))
- return Result;
-
- return E;
+ return EvalVal(M->getBase(), refVars, ParentDecl);
+ }
- default:
- // Check that we don't return or take the address of a reference to a
- // temporary. This is only useful in C++.
- if (!E->isTypeDependent() && E->isRValue())
+ case Stmt::MaterializeTemporaryExprClass:
+ if (const Expr *Result =
+ EvalVal(cast<MaterializeTemporaryExpr>(E)->GetTemporaryExpr(),
+ refVars, ParentDecl))
+ return Result;
return E;
- // Everything else: we simply don't reason about them.
- return nullptr;
- }
-} while (true);
+ default:
+ // Check that we don't return or take the address of a reference to a
+ // temporary. This is only useful in C++.
+ if (!E->isTypeDependent() && E->isRValue())
+ return E;
+
+ // Everything else: we simply don't reason about them.
+ return nullptr;
+ }
+ } while (true);
}
void
@@ -6047,7 +6937,6 @@ void Sema::CheckFloatComparison(SourceLocation Loc, Expr* LHS, Expr *RHS) {
if (DRL->getDecl() == DRR->getDecl())
return;
-
// Special case: check for comparisons against literals that can be exactly
// represented by APFloat. In such cases, do not emit a warning. This
// is a heuristic: often comparison against such literals are used to
@@ -6173,8 +7062,7 @@ struct IntRange {
}
};
-static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value,
- unsigned MaxWidth) {
+IntRange GetValueRange(ASTContext &C, llvm::APSInt &value, unsigned MaxWidth) {
if (value.isSigned() && value.isNegative())
return IntRange(value.getMinSignedBits(), false);
@@ -6186,8 +7074,8 @@ static IntRange GetValueRange(ASTContext &C, llvm::APSInt &value,
return IntRange(value.getActiveBits(), true);
}
-static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
- unsigned MaxWidth) {
+IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
+ unsigned MaxWidth) {
if (result.isInt())
return GetValueRange(C, result.getInt(), MaxWidth);
@@ -6215,7 +7103,7 @@ static IntRange GetValueRange(ASTContext &C, APValue &result, QualType Ty,
return IntRange(MaxWidth, Ty->isUnsignedIntegerOrEnumerationType());
}
-static QualType GetExprType(Expr *E) {
+QualType GetExprType(const Expr *E) {
QualType Ty = E->getType();
if (const AtomicType *AtomicRHS = Ty->getAs<AtomicType>())
Ty = AtomicRHS->getValueType();
@@ -6226,7 +7114,7 @@ static QualType GetExprType(Expr *E) {
/// range of values it might take.
///
/// \param MaxWidth - the width to which the value will be truncated
-static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
+IntRange GetExprRange(ASTContext &C, const Expr *E, unsigned MaxWidth) {
E = E->IgnoreParens();
// Try a full evaluation first.
@@ -6237,7 +7125,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
// I think we only want to look through implicit casts here; if the
// user has an explicit widening cast, we should treat the value as
// being of the new, wider type.
- if (ImplicitCastExpr *CE = dyn_cast<ImplicitCastExpr>(E)) {
+ if (const auto *CE = dyn_cast<ImplicitCastExpr>(E)) {
if (CE->getCastKind() == CK_NoOp || CE->getCastKind() == CK_LValueToRValue)
return GetExprRange(C, CE->getSubExpr(), MaxWidth);
@@ -6264,7 +7152,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
SubRange.NonNegative || OutputTypeRange.NonNegative);
}
- if (ConditionalOperator *CO = dyn_cast<ConditionalOperator>(E)) {
+ if (const auto *CO = dyn_cast<ConditionalOperator>(E)) {
// If we can fold the condition, just take that operand.
bool CondResult;
if (CO->getCond()->EvaluateAsBooleanCondition(CondResult, C))
@@ -6278,7 +7166,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return IntRange::join(L, R);
}
- if (BinaryOperator *BO = dyn_cast<BinaryOperator>(E)) {
+ if (const auto *BO = dyn_cast<BinaryOperator>(E)) {
switch (BO->getOpcode()) {
// Boolean-valued operations are single-bit and positive.
@@ -6418,7 +7306,7 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
return IntRange::join(L, R);
}
- if (UnaryOperator *UO = dyn_cast<UnaryOperator>(E)) {
+ if (const auto *UO = dyn_cast<UnaryOperator>(E)) {
switch (UO->getOpcode()) {
// Boolean-valued operations are white-listed.
case UO_LNot:
@@ -6434,26 +7322,26 @@ static IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
}
}
- if (OpaqueValueExpr *OVE = dyn_cast<OpaqueValueExpr>(E))
+ if (const auto *OVE = dyn_cast<OpaqueValueExpr>(E))
return GetExprRange(C, OVE->getSourceExpr(), MaxWidth);
- if (FieldDecl *BitField = E->getSourceBitField())
+ if (const auto *BitField = E->getSourceBitField())
return IntRange(BitField->getBitWidthValue(C),
BitField->getType()->isUnsignedIntegerOrEnumerationType());
return IntRange::forValueOfType(C, GetExprType(E));
}
-static IntRange GetExprRange(ASTContext &C, Expr *E) {
+IntRange GetExprRange(ASTContext &C, const Expr *E) {
return GetExprRange(C, E, C.getIntWidth(GetExprType(E)));
}
/// Checks whether the given value, which currently has the given
/// source semantics, has the same value when coerced through the
/// target semantics.
-static bool IsSameFloatAfterCast(const llvm::APFloat &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+bool IsSameFloatAfterCast(const llvm::APFloat &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
llvm::APFloat truncated = value;
bool ignored;
@@ -6468,9 +7356,9 @@ static bool IsSameFloatAfterCast(const llvm::APFloat &value,
/// target semantics.
///
/// The value might be a vector of floats (or a complex number).
-static bool IsSameFloatAfterCast(const APValue &value,
- const llvm::fltSemantics &Src,
- const llvm::fltSemantics &Tgt) {
+bool IsSameFloatAfterCast(const APValue &value,
+ const llvm::fltSemantics &Src,
+ const llvm::fltSemantics &Tgt) {
if (value.isFloat())
return IsSameFloatAfterCast(value.getFloat(), Src, Tgt);
@@ -6486,9 +7374,9 @@ static bool IsSameFloatAfterCast(const APValue &value,
IsSameFloatAfterCast(value.getComplexFloatImag(), Src, Tgt));
}
-static void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
+void AnalyzeImplicitConversions(Sema &S, Expr *E, SourceLocation CC);
-static bool IsZero(Sema &S, Expr *E) {
+bool IsZero(Sema &S, Expr *E) {
// Suppress cases where we are comparing against an enum constant.
if (const DeclRefExpr *DR =
dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
@@ -6503,7 +7391,7 @@ static bool IsZero(Sema &S, Expr *E) {
return E->isIntegerConstantExpr(Value, S.Context) && Value == 0;
}
-static bool HasEnumType(Expr *E) {
+bool HasEnumType(Expr *E) {
// Strip off implicit integral promotions.
while (ImplicitCastExpr *ICE = dyn_cast<ImplicitCastExpr>(E)) {
if (ICE->getCastKind() != CK_IntegralCast &&
@@ -6515,7 +7403,7 @@ static bool HasEnumType(Expr *E) {
return E->getType()->isEnumeralType();
}
-static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
// Disable warning in template instantiations.
if (!S.ActiveTemplateInstantiations.empty())
return;
@@ -6543,10 +7431,9 @@ static void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
}
}
-static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
- Expr *Constant, Expr *Other,
- llvm::APSInt Value,
- bool RhsConstant) {
+void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
+ Expr *Other, const llvm::APSInt &Value,
+ bool RhsConstant) {
// Disable warning in template instantiations.
if (!S.ActiveTemplateInstantiations.empty())
return;
@@ -6754,7 +7641,7 @@ static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
-static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
+void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
AnalyzeImplicitConversions(S, E->getRHS(), E->getOperatorLoc());
}
@@ -6762,7 +7649,7 @@ static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
/// \brief Implements -Wsign-compare.
///
/// \param E the binary operator to check for warnings
-static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
+void AnalyzeComparison(Sema &S, BinaryOperator *E) {
// The type the comparison is being performed in.
QualType T = E->getLHS()->getType();
@@ -6863,8 +7750,8 @@ static void AnalyzeComparison(Sema &S, BinaryOperator *E) {
/// Analyzes an attempt to assign the given value to a bitfield.
///
/// Returns true if there was something fishy about the attempt.
-static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
- SourceLocation InitLoc) {
+bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
+ SourceLocation InitLoc) {
assert(Bitfield->isBitField());
if (Bitfield->isInvalidDecl())
return false;
@@ -6918,7 +7805,7 @@ static bool AnalyzeBitFieldAssignment(Sema &S, FieldDecl *Bitfield, Expr *Init,
/// Analyze the given simple or compound assignment for warning-worthy
/// operations.
-static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
+void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
// Just recurse on the LHS.
AnalyzeImplicitConversions(S, E->getLHS(), E->getOperatorLoc());
@@ -6937,9 +7824,9 @@ static void AnalyzeAssignment(Sema &S, BinaryOperator *E) {
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
- SourceLocation CContext, unsigned diag,
- bool pruneControlFlow = false) {
+void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
+ SourceLocation CContext, unsigned diag,
+ bool pruneControlFlow = false) {
if (pruneControlFlow) {
S.DiagRuntimeBehavior(E->getExprLoc(), E,
S.PDiag(diag)
@@ -6952,25 +7839,75 @@ static void DiagnoseImpCast(Sema &S, Expr *E, QualType SourceType, QualType T,
}
/// Diagnose an implicit cast; purely a helper for CheckImplicitConversion.
-static void DiagnoseImpCast(Sema &S, Expr *E, QualType T,
- SourceLocation CContext, unsigned diag,
- bool pruneControlFlow = false) {
+void DiagnoseImpCast(Sema &S, Expr *E, QualType T, SourceLocation CContext,
+ unsigned diag, bool pruneControlFlow = false) {
DiagnoseImpCast(S, E, E->getType(), T, CContext, diag, pruneControlFlow);
}
-/// Diagnose an implicit cast from a literal expression. Does not warn when the
-/// cast wouldn't lose information.
-void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
- SourceLocation CContext) {
- // Try to convert the literal exactly to an integer. If we can, don't warn.
+
+/// Diagnose an implicit cast from a floating point value to an integer value.
+void DiagnoseFloatingImpCast(Sema &S, Expr *E, QualType T,
+
+ SourceLocation CContext) {
+ const bool IsBool = T->isSpecificBuiltinType(BuiltinType::Bool);
+ const bool PruneWarnings = !S.ActiveTemplateInstantiations.empty();
+
+ Expr *InnerE = E->IgnoreParenImpCasts();
+ // We also want to warn on, e.g., "int i = -1.234"
+ if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE))
+ if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus)
+ InnerE = UOp->getSubExpr()->IgnoreParenImpCasts();
+
+ const bool IsLiteral =
+ isa<FloatingLiteral>(E) || isa<FloatingLiteral>(InnerE);
+
+ llvm::APFloat Value(0.0);
+ bool IsConstant =
+ E->EvaluateAsFloat(Value, S.Context, Expr::SE_AllowSideEffects);
+ if (!IsConstant) {
+ return DiagnoseImpCast(S, E, T, CContext,
+ diag::warn_impcast_float_integer, PruneWarnings);
+ }
+
bool isExact = false;
- const llvm::APFloat &Value = FL->getValue();
+
llvm::APSInt IntegerValue(S.Context.getIntWidth(T),
T->hasUnsignedIntegerRepresentation());
- if (Value.convertToInteger(IntegerValue,
- llvm::APFloat::rmTowardZero, &isExact)
- == llvm::APFloat::opOK && isExact)
- return;
+ if (Value.convertToInteger(IntegerValue, llvm::APFloat::rmTowardZero,
+ &isExact) == llvm::APFloat::opOK &&
+ isExact) {
+ if (IsLiteral) return;
+ return DiagnoseImpCast(S, E, T, CContext, diag::warn_impcast_float_integer,
+ PruneWarnings);
+ }
+
+ unsigned DiagID = 0;
+ if (IsLiteral) {
+ // Warn on floating point literal to integer.
+ DiagID = diag::warn_impcast_literal_float_to_integer;
+ } else if (IntegerValue == 0) {
+ if (Value.isZero()) { // Skip -0.0 to 0 conversion.
+ return DiagnoseImpCast(S, E, T, CContext,
+ diag::warn_impcast_float_integer, PruneWarnings);
+ }
+ // Warn on non-zero to zero conversion.
+ DiagID = diag::warn_impcast_float_to_integer_zero;
+ } else {
+ if (IntegerValue.isUnsigned()) {
+ if (!IntegerValue.isMaxValue()) {
+ return DiagnoseImpCast(S, E, T, CContext,
+ diag::warn_impcast_float_integer, PruneWarnings);
+ }
+ } else { // IntegerValue.isSigned()
+ if (!IntegerValue.isMaxSignedValue() &&
+ !IntegerValue.isMinSignedValue()) {
+ return DiagnoseImpCast(S, E, T, CContext,
+ diag::warn_impcast_float_integer, PruneWarnings);
+ }
+ }
+ // Warn on evaluatable floating point expression to integer conversion.
+ DiagID = diag::warn_impcast_float_to_integer;
+ }
// FIXME: Force the precision of the source value down so we don't print
// digits which are usually useless (we don't really care here if we
@@ -6983,14 +7920,22 @@ void DiagnoseFloatingLiteralImpCast(Sema &S, FloatingLiteral *FL, QualType T,
Value.toString(PrettySourceValue, precision);
SmallString<16> PrettyTargetValue;
- if (T->isSpecificBuiltinType(BuiltinType::Bool))
+ if (IsBool)
PrettyTargetValue = Value.isZero() ? "false" : "true";
else
IntegerValue.toString(PrettyTargetValue);
- S.Diag(FL->getExprLoc(), diag::warn_impcast_literal_float_to_integer)
- << FL->getType() << T.getUnqualifiedType() << PrettySourceValue
- << PrettyTargetValue << FL->getSourceRange() << SourceRange(CContext);
+ if (PruneWarnings) {
+ S.DiagRuntimeBehavior(E->getExprLoc(), E,
+ S.PDiag(DiagID)
+ << E->getType() << T.getUnqualifiedType()
+ << PrettySourceValue << PrettyTargetValue
+ << E->getSourceRange() << SourceRange(CContext));
+ } else {
+ S.Diag(E->getExprLoc(), DiagID)
+ << E->getType() << T.getUnqualifiedType() << PrettySourceValue
+ << PrettyTargetValue << E->getSourceRange() << SourceRange(CContext);
+ }
}
std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
@@ -7002,7 +7947,7 @@ std::string PrettyPrintInRange(const llvm::APSInt &Value, IntRange Range) {
return ValueInRange.toString(10);
}
-static bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
+bool IsImplicitBoolFloatConversion(Sema &S, Expr *Ex, bool ToBool) {
if (!isa<ImplicitCastExpr>(Ex))
return false;
@@ -7042,8 +7987,7 @@ void CheckImplicitArgumentConversions(Sema &S, CallExpr *TheCall,
}
}
-static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
- SourceLocation CC) {
+void DiagnoseNullConversion(Sema &S, Expr *E, QualType T, SourceLocation CC) {
if (S.Diags.isIgnored(diag::warn_impcast_null_pointer_to_integer,
E->getExprLoc()))
return;
@@ -7065,14 +8009,21 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
SourceLocation Loc = E->getSourceRange().getBegin();
+ // Venture through the macro stacks to get to the source of macro arguments.
+ // The new location is a better location than the complete location that was
+ // passed in.
+ while (S.SourceMgr.isMacroArgExpansion(Loc))
+ Loc = S.SourceMgr.getImmediateMacroCallerLoc(Loc);
+
+ while (S.SourceMgr.isMacroArgExpansion(CC))
+ CC = S.SourceMgr.getImmediateMacroCallerLoc(CC);
+
// __null is usually wrapped in a macro. Go up a macro if that is the case.
- if (NullKind == Expr::NPCK_GNUNull) {
- if (Loc.isMacroID()) {
- StringRef MacroName =
- Lexer::getImmediateMacroName(Loc, S.SourceMgr, S.getLangOpts());
- if (MacroName == "NULL")
- Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
- }
+ if (NullKind == Expr::NPCK_GNUNull && Loc.isMacroID()) {
+ StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics(
+ Loc, S.SourceMgr, S.getLangOpts());
+ if (MacroName == "NULL")
+ Loc = S.SourceMgr.getImmediateExpansionRange(Loc).first;
}
// Only warn if the null and context location are in the same macro expansion.
@@ -7085,17 +8036,15 @@ static void DiagnoseNullConversion(Sema &S, Expr *E, QualType T,
S.getFixItZeroLiteralForType(T, Loc));
}
-static void checkObjCArrayLiteral(Sema &S, QualType TargetType,
- ObjCArrayLiteral *ArrayLiteral);
-static void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
- ObjCDictionaryLiteral *DictionaryLiteral);
+void checkObjCArrayLiteral(Sema &S, QualType TargetType,
+ ObjCArrayLiteral *ArrayLiteral);
+void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
+ ObjCDictionaryLiteral *DictionaryLiteral);
/// Check a single element within a collection literal against the
/// target element type.
-static void checkObjCCollectionLiteralElement(Sema &S,
- QualType TargetElementType,
- Expr *Element,
- unsigned ElementKind) {
+void checkObjCCollectionLiteralElement(Sema &S, QualType TargetElementType,
+ Expr *Element, unsigned ElementKind) {
// Skip a bitcast to 'id' or qualified 'id'.
if (auto ICE = dyn_cast<ImplicitCastExpr>(Element)) {
if (ICE->getCastKind() == CK_BitCast &&
@@ -7124,8 +8073,8 @@ static void checkObjCCollectionLiteralElement(Sema &S,
/// Check an Objective-C array literal being converted to the given
/// target type.
-static void checkObjCArrayLiteral(Sema &S, QualType TargetType,
- ObjCArrayLiteral *ArrayLiteral) {
+void checkObjCArrayLiteral(Sema &S, QualType TargetType,
+ ObjCArrayLiteral *ArrayLiteral) {
if (!S.NSArrayDecl)
return;
@@ -7152,9 +8101,8 @@ static void checkObjCArrayLiteral(Sema &S, QualType TargetType,
/// Check an Objective-C dictionary literal being converted to the given
/// target type.
-static void checkObjCDictionaryLiteral(
- Sema &S, QualType TargetType,
- ObjCDictionaryLiteral *DictionaryLiteral) {
+void checkObjCDictionaryLiteral(Sema &S, QualType TargetType,
+ ObjCDictionaryLiteral *DictionaryLiteral) {
if (!S.NSDictionaryDecl)
return;
@@ -7180,6 +8128,32 @@ static void checkObjCDictionaryLiteral(
}
}
+// Helper function to filter out cases for constant width constant conversion.
+// Don't warn on char array initialization or for non-decimal values.
+bool isSameWidthConstantConversion(Sema &S, Expr *E, QualType T,
+ SourceLocation CC) {
+ // If initializing from a constant, and the constant starts with '0',
+ // then it is a binary, octal, or hexadecimal. Allow these constants
+ // to fill all the bits, even if there is a sign change.
+ if (auto *IntLit = dyn_cast<IntegerLiteral>(E->IgnoreParenImpCasts())) {
+ const char FirstLiteralCharacter =
+ S.getSourceManager().getCharacterData(IntLit->getLocStart())[0];
+ if (FirstLiteralCharacter == '0')
+ return false;
+ }
+
+ // If the CC location points to a '{', and the type is char, then assume
+ // assume it is an array initialization.
+ if (CC.isValid() && T->isCharType()) {
+ const char FirstContextCharacter =
+ S.getSourceManager().getCharacterData(CC)[0];
+ if (FirstContextCharacter == '{')
+ return false;
+ }
+
+ return true;
+}
+
void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
SourceLocation CC, bool *ICContext = nullptr) {
if (E->isTypeDependent() || E->isValueDependent()) return;
@@ -7284,7 +8258,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_precision);
-
}
// ... or possibly if we're increasing rank, too
else if (TargetBT->getKind() > SourceBT->getKind()) {
@@ -7296,22 +8269,12 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return;
}
- // If the target is integral, always warn.
+ // If the target is integral, always warn.
if (TargetBT && TargetBT->isInteger()) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
-
- Expr *InnerE = E->IgnoreParenImpCasts();
- // We also want to warn on, e.g., "int i = -1.234"
- if (UnaryOperator *UOp = dyn_cast<UnaryOperator>(InnerE))
- if (UOp->getOpcode() == UO_Minus || UOp->getOpcode() == UO_Plus)
- InnerE = UOp->getSubExpr()->IgnoreParenImpCasts();
-
- if (FloatingLiteral *FL = dyn_cast<FloatingLiteral>(InnerE)) {
- DiagnoseFloatingLiteralImpCast(S, FL, T, CC);
- } else {
- DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_float_integer);
- }
+
+ DiagnoseFloatingImpCast(S, E, T, CC);
}
// Detect the case where a call result is converted from floating-point to
@@ -7358,7 +8321,7 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
// If the source is a constant, use a default-on diagnostic.
// TODO: this should happen for bitfield stores, too.
llvm::APSInt Value(32);
- if (E->isIntegerConstantExpr(Value, S.Context)) {
+ if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects)) {
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -7383,10 +8346,34 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return DiagnoseImpCast(S, E, T, CC, diag::warn_impcast_integer_precision);
}
+ if (TargetRange.Width == SourceRange.Width && !TargetRange.NonNegative &&
+ SourceRange.NonNegative && Source->isSignedIntegerType()) {
+ // Warn when doing a signed to signed conversion, warn if the positive
+ // source value is exactly the width of the target type, which will
+ // cause a negative value to be stored.
+
+ llvm::APSInt Value;
+ if (E->EvaluateAsInt(Value, S.Context, Expr::SE_AllowSideEffects) &&
+ !S.SourceMgr.isInSystemMacro(CC)) {
+ if (isSameWidthConstantConversion(S, E, T, CC)) {
+ std::string PrettySourceValue = Value.toString(10);
+ std::string PrettyTargetValue = PrettyPrintInRange(Value, TargetRange);
+
+ S.DiagRuntimeBehavior(
+ E->getExprLoc(), E,
+ S.PDiag(diag::warn_impcast_integer_precision_constant)
+ << PrettySourceValue << PrettyTargetValue << E->getType() << T
+ << E->getSourceRange() << clang::SourceRange(CC));
+ return;
+ }
+ }
+
+ // Fall through for non-constants to give a sign conversion warning.
+ }
+
if ((TargetRange.NonNegative && !SourceRange.NonNegative) ||
(!TargetRange.NonNegative && SourceRange.NonNegative &&
SourceRange.Width == TargetRange.Width)) {
-
if (S.SourceMgr.isInSystemMacro(CC))
return;
@@ -7429,8 +8416,6 @@ void CheckImplicitConversion(Sema &S, Expr *E, QualType T,
return DiagnoseImpCast(S, E, SourceType, T, CC,
diag::warn_impcast_different_enum_types);
}
-
- return;
}
void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
@@ -7446,7 +8431,6 @@ void CheckConditionalOperand(Sema &S, Expr *E, QualType T,
AnalyzeImplicitConversions(S, E, CC);
if (E->getType() != T)
return CheckImplicitConversion(S, E, T, CC, &ICContext);
- return;
}
void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
@@ -7479,7 +8463,7 @@ void CheckConditionalOperator(Sema &S, ConditionalOperator *E,
/// CheckBoolLikeConversion - Check conversion of given expression to boolean.
/// Input argument E is a logical expression.
-static void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
+void CheckBoolLikeConversion(Sema &S, Expr *E, SourceLocation CC) {
if (S.getLangOpts().Bool)
return;
CheckImplicitConversion(S, E->IgnoreParenImpCasts(), S.Context.BoolTy, CC);
@@ -7583,10 +8567,31 @@ void AnalyzeImplicitConversions(Sema &S, Expr *OrigE, SourceLocation CC) {
} // end anonymous namespace
+static bool checkOpenCLEnqueueLocalSizeArgs(Sema &S, CallExpr *TheCall,
+ unsigned Start, unsigned End) {
+ bool IllegalParams = false;
+ for (unsigned I = Start; I <= End; ++I) {
+ QualType Ty = TheCall->getArg(I)->getType();
+ // Taking into account implicit conversions,
+ // allow any integer within 32 bits range
+ if (!Ty->isIntegerType() ||
+ S.Context.getTypeSizeInChars(Ty).getQuantity() > 4) {
+ S.Diag(TheCall->getArg(I)->getLocStart(),
+ diag::err_opencl_enqueue_kernel_invalid_local_size_type);
+ IllegalParams = true;
+ }
+ // Potentially emit standard warnings for implicit conversions if enabled
+ // using -Wconversion.
+ CheckImplicitConversion(S, TheCall->getArg(I), S.Context.UnsignedIntTy,
+ TheCall->getArg(I)->getLocStart());
+ }
+ return IllegalParams;
+}
+
// Helper function for Sema::DiagnoseAlwaysNonNullPointer.
// Returns true when emitting a warning about taking the address of a reference.
static bool CheckForReference(Sema &SemaRef, const Expr *E,
- PartialDiagnostic PD) {
+ const PartialDiagnostic &PD) {
E = E->IgnoreParenImpCasts();
const FunctionDecl *FD = nullptr;
@@ -7681,7 +8686,8 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
}
}
- auto ComplainAboutNonnullParamOrCall = [&](bool IsParam) {
+ auto ComplainAboutNonnullParamOrCall = [&](const Attr *NonnullAttr) {
+ bool IsParam = isa<NonNullAttr>(NonnullAttr);
std::string Str;
llvm::raw_string_ostream S(Str);
E->printPretty(S, nullptr, getPrintingPolicy());
@@ -7689,13 +8695,14 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
: diag::warn_cast_nonnull_to_bool;
Diag(E->getExprLoc(), DiagID) << IsParam << S.str()
<< E->getSourceRange() << Range << IsEqual;
+ Diag(NonnullAttr->getLocation(), diag::note_declared_nonnull) << IsParam;
};
// If we have a CallExpr that is tagged with returns_nonnull, we can complain.
if (auto *Call = dyn_cast<CallExpr>(E->IgnoreParenImpCasts())) {
if (auto *Callee = Call->getDirectCallee()) {
- if (Callee->hasAttr<ReturnsNonNullAttr>()) {
- ComplainAboutNonnullParamOrCall(false);
+ if (const Attr *A = Callee->getAttr<ReturnsNonNullAttr>()) {
+ ComplainAboutNonnullParamOrCall(A);
return;
}
}
@@ -7717,25 +8724,25 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
if (const auto* PV = dyn_cast<ParmVarDecl>(D)) {
if (getCurFunction() &&
!getCurFunction()->ModifiedNonNullParams.count(PV)) {
- if (PV->hasAttr<NonNullAttr>()) {
- ComplainAboutNonnullParamOrCall(true);
+ if (const Attr *A = PV->getAttr<NonNullAttr>()) {
+ ComplainAboutNonnullParamOrCall(A);
return;
}
if (const auto *FD = dyn_cast<FunctionDecl>(PV->getDeclContext())) {
- auto ParamIter = std::find(FD->param_begin(), FD->param_end(), PV);
+ auto ParamIter = llvm::find(FD->parameters(), PV);
assert(ParamIter != FD->param_end());
unsigned ParamNo = std::distance(FD->param_begin(), ParamIter);
for (const auto *NonNull : FD->specific_attrs<NonNullAttr>()) {
if (!NonNull->args_size()) {
- ComplainAboutNonnullParamOrCall(true);
+ ComplainAboutNonnullParamOrCall(NonNull);
return;
}
for (unsigned ArgNo : NonNull->args()) {
if (ArgNo == ParamNo) {
- ComplainAboutNonnullParamOrCall(true);
+ ComplainAboutNonnullParamOrCall(NonNull);
return;
}
}
@@ -7817,7 +8824,6 @@ void Sema::DiagnoseAlwaysNonNullPointer(Expr *E,
<< FixItHint::CreateInsertion(getLocForEndOfToken(E->getLocEnd()), "()");
}
-
/// Diagnoses "dangerous" implicit conversions within the given
/// expression (which is a full expression). Implements -Wconversion
/// and -Wsign-compare.
@@ -7852,12 +8858,20 @@ void Sema::CheckBoolLikeConversion(Expr *E, SourceLocation CC) {
/// Diagnose when expression is an integer constant expression and its evaluation
/// results in integer overflow
void Sema::CheckForIntOverflow (Expr *E) {
- if (isa<BinaryOperator>(E->IgnoreParenCasts()))
- E->IgnoreParenCasts()->EvaluateForOverflow(Context);
- else if (auto InitList = dyn_cast<InitListExpr>(E))
- for (Expr *E : InitList->inits())
- if (isa<BinaryOperator>(E->IgnoreParenCasts()))
- E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ // Use a work list to deal with nested struct initializers.
+ SmallVector<Expr *, 2> Exprs(1, E);
+
+ do {
+ Expr *E = Exprs.pop_back_val();
+
+ if (isa<BinaryOperator>(E->IgnoreParenCasts())) {
+ E->IgnoreParenCasts()->EvaluateForOverflow(Context);
+ continue;
+ }
+
+ if (auto InitList = dyn_cast<InitListExpr>(E))
+ Exprs.append(InitList->inits().begin(), InitList->inits().end());
+ } while (!Exprs.empty());
}
namespace {
@@ -7875,7 +8889,7 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
struct Value {
explicit Value(unsigned Parent) : Parent(Parent), Merged(false) {}
unsigned Parent : 31;
- bool Merged : 1;
+ unsigned Merged : 1;
};
SmallVector<Value, 8> Values;
@@ -7987,12 +9001,11 @@ class SequenceChecker : public EvaluatedExprVisitor<SequenceChecker> {
Self.ModAsSideEffect = &ModAsSideEffect;
}
~SequencedSubexpression() {
- for (auto MI = ModAsSideEffect.rbegin(), ME = ModAsSideEffect.rend();
- MI != ME; ++MI) {
- UsageInfo &U = Self.UsageMap[MI->first];
+ for (auto &M : llvm::reverse(ModAsSideEffect)) {
+ UsageInfo &U = Self.UsageMap[M.first];
auto &SideEffectUsage = U.Uses[UK_ModAsSideEffect];
- Self.addUsage(U, MI->first, SideEffectUsage.Use, UK_ModAsValue);
- SideEffectUsage = MI->second;
+ Self.addUsage(U, M.first, SideEffectUsage.Use, UK_ModAsValue);
+ SideEffectUsage = M.second;
}
Self.ModAsSideEffect = OldModAsSideEffect;
}
@@ -8195,6 +9208,7 @@ public:
notePostMod(O, BO, SemaRef.getLangOpts().CPlusPlus ? UK_ModAsValue
: UK_ModAsSideEffect);
}
+
void VisitCompoundAssignOperator(CompoundAssignOperator *CAO) {
VisitBinAssign(CAO);
}
@@ -8344,7 +9358,7 @@ public:
Tree.merge(Elts[I]);
}
};
-}
+} // end anonymous namespace
void Sema::CheckUnsequencedOperations(Expr *E) {
SmallVector<Expr *, 8> WorkList;
@@ -8403,13 +9417,10 @@ static void diagnoseArrayStarInParamType(Sema &S, QualType PType,
/// takes care of any checks that cannot be performed on the
/// declaration itself, e.g., that the types of each of the function
/// parameters are complete.
-bool Sema::CheckParmsForFunctionDef(ParmVarDecl *const *P,
- ParmVarDecl *const *PEnd,
+bool Sema::CheckParmsForFunctionDef(ArrayRef<ParmVarDecl *> Parameters,
bool CheckParameterNames) {
bool HasInvalidParm = false;
- for (; P != PEnd; ++P) {
- ParmVarDecl *Param = *P;
-
+ for (ParmVarDecl *Param : Parameters) {
// C99 6.7.5.3p4: the parameters in a parameter type list in a
// function declarator that is part of a function definition of
// that function shall not have incomplete type.
@@ -8517,21 +9528,12 @@ void Sema::CheckCastAlign(Expr *Op, QualType T, SourceRange TRange) {
<< TRange << Op->getSourceRange();
}
-static const Type* getElementType(const Expr *BaseExpr) {
- const Type* EltType = BaseExpr->getType().getTypePtr();
- if (EltType->isAnyPointerType())
- return EltType->getPointeeType().getTypePtr();
- else if (EltType->isArrayType())
- return EltType->getBaseElementTypeUnsafe();
- return EltType;
-}
-
/// \brief Check whether this array fits the idiom of a size-one tail padded
/// array member of a struct.
///
/// We avoid emitting out-of-bounds access warnings for such arrays as they are
/// commonly used to emulate flexible arrays in C89 code.
-static bool IsTailPaddedMemberArray(Sema &S, llvm::APInt Size,
+static bool IsTailPaddedMemberArray(Sema &S, const llvm::APInt &Size,
const NamedDecl *ND) {
if (Size != 1 || !ND) return false;
@@ -8580,7 +9582,8 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (IndexExpr->isValueDependent())
return;
- const Type *EffectiveType = getElementType(BaseExpr);
+ const Type *EffectiveType =
+ BaseExpr->getType()->getPointeeOrArrayElementType();
BaseExpr = BaseExpr->IgnoreParenCasts();
const ConstantArrayType *ArrayTy =
Context.getAsConstantArrayType(BaseExpr->getType());
@@ -8604,7 +9607,7 @@ void Sema::CheckArrayAccess(const Expr *BaseExpr, const Expr *IndexExpr,
if (!size.isStrictlyPositive())
return;
- const Type* BaseType = getElementType(BaseExpr);
+ const Type *BaseType = BaseExpr->getType()->getPointeeOrArrayElementType();
if (BaseType != EffectiveType) {
// Make sure we're comparing apples to apples when comparing index to size
uint64_t ptrarith_typesize = Context.getTypeSize(EffectiveType);
@@ -8754,7 +9757,7 @@ namespace {
Range = e->getSourceRange();
}
};
-}
+} // end anonymous namespace
/// Consider whether capturing the given variable can possibly lead to
/// a retain cycle.
@@ -8900,7 +9903,7 @@ namespace {
}
}
};
-}
+} // end anonymous namespace
/// Check whether the given argument is a block which captures a
/// variable.
@@ -9136,7 +10139,6 @@ void Sema::CheckObjCCircularContainer(ObjCMessageExpr *Message) {
}
}
}
-
}
/// Check a message send to see if it's likely to cause a retain cycle.
@@ -9340,7 +10342,7 @@ bool ShouldDiagnoseEmptyStmtBody(const SourceManager &SourceMgr,
return true;
}
-} // Unnamed namespace
+} // end anonymous namespace
void Sema::DiagnoseEmptyStmtBody(SourceLocation StmtLoc,
const Stmt *Body,
@@ -9436,7 +10438,6 @@ void Sema::DiagnoseEmptyLoopBody(const Stmt *S,
/// DiagnoseSelfMove - Emits a warning if a value is moved to itself.
void Sema::DiagnoseSelfMove(const Expr *LHSExpr, const Expr *RHSExpr,
SourceLocation OpLoc) {
-
if (Diags.isIgnored(diag::warn_sizeof_pointer_expr_memaccess, OpLoc))
return;
@@ -9675,7 +10676,7 @@ bool isLayoutCompatible(ASTContext &C, QualType T1, QualType T2) {
return false;
}
-}
+} // end anonymous namespace
//===--- CHECK: pointer_with_type_tag attribute: datatypes should match ----//
@@ -9806,7 +10807,7 @@ bool GetMatchingCType(
TypeInfo = I->second;
return true;
}
-} // unnamed namespace
+} // end anonymous namespace
void Sema::RegisterTypeTagForDatatype(const IdentifierInfo *ArgumentKind,
uint64_t MagicValue, QualType Type,
@@ -9839,7 +10840,7 @@ bool IsSameCharType(QualType T1, QualType T2) {
(T1Kind == BuiltinType::Char_U && T2Kind == BuiltinType::UChar) ||
(T1Kind == BuiltinType::Char_S && T2Kind == BuiltinType::SChar);
}
-} // unnamed namespace
+} // end anonymous namespace
void Sema::CheckArgumentWithTypeTag(const ArgumentWithTypeTagAttr *Attr,
const Expr * const *ExprArgs) {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
index 21cf62585142..36babc4bc0cd 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCodeComplete.cpp
@@ -19,7 +19,6 @@
#include "clang/Lex/MacroInfo.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/CodeCompleteConsumer.h"
-#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
@@ -482,12 +481,37 @@ getRequiredQualification(ASTContext &Context,
/// Determine whether \p Id is a name reserved for the implementation (C99
/// 7.1.3, C++ [lib.global.names]).
-static bool isReservedName(const IdentifierInfo *Id) {
+static bool isReservedName(const IdentifierInfo *Id,
+ bool doubleUnderscoreOnly = false) {
if (Id->getLength() < 2)
return false;
const char *Name = Id->getNameStart();
return Name[0] == '_' &&
- (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z'));
+ (Name[1] == '_' || (Name[1] >= 'A' && Name[1] <= 'Z' &&
+ !doubleUnderscoreOnly));
+}
+
+// Some declarations have reserved names that we don't want to ever show.
+// Filter out names reserved for the implementation if they come from a
+// system header.
+static bool shouldIgnoreDueToReservedName(const NamedDecl *ND, Sema &SemaRef) {
+ const IdentifierInfo *Id = ND->getIdentifier();
+ if (!Id)
+ return false;
+
+ // Ignore reserved names for compiler provided decls.
+ if (isReservedName(Id) && ND->getLocation().isInvalid())
+ return true;
+
+ // For system headers ignore only double-underscore names.
+ // This allows for system headers providing private symbols with a single
+ // underscore.
+ if (isReservedName(Id, /*doubleUnderscoreOnly=*/true) &&
+ SemaRef.SourceMgr.isInSystemHeader(
+ SemaRef.SourceMgr.getSpellingLoc(ND->getLocation())))
+ return true;
+
+ return false;
}
bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
@@ -514,17 +538,9 @@ bool ResultBuilder::isInterestingDecl(const NamedDecl *ND,
// Using declarations themselves are never added as results.
if (isa<UsingDecl>(ND))
return false;
-
- // Some declarations have reserved names that we don't want to ever show.
- // Filter out names reserved for the implementation if they come from a
- // system header.
- // TODO: Add a predicate for this.
- if (const IdentifierInfo *Id = ND->getIdentifier())
- if (isReservedName(Id) &&
- (ND->getLocation().isInvalid() ||
- SemaRef.SourceMgr.isInSystemHeader(
- SemaRef.SourceMgr.getSpellingLoc(ND->getLocation()))))
- return false;
+
+ if (shouldIgnoreDueToReservedName(ND, SemaRef))
+ return false;
if (Filter == &ResultBuilder::IsNestedNameSpecifier ||
(isa<NamespaceDecl>(ND) &&
@@ -1518,7 +1534,6 @@ static void AddOrdinaryNameResults(Sema::ParserCompletionContext CCC,
ResultBuilder &Results) {
CodeCompletionAllocator &Allocator = Results.getAllocator();
CodeCompletionBuilder Builder(Allocator, Results.getCodeCompletionTUInfo());
- PrintingPolicy Policy = getCompletionPrintingPolicy(SemaRef);
typedef CodeCompletionResult Result;
switch (CCC) {
@@ -3046,6 +3061,7 @@ CXCursorKind clang::getCursorKindForDecl(const Decl *D) {
case Decl::ClassTemplatePartialSpecialization:
return CXCursor_ClassTemplatePartialSpecialization;
case Decl::UsingDirective: return CXCursor_UsingDirective;
+ case Decl::StaticAssert: return CXCursor_StaticAssert;
case Decl::TranslationUnit: return CXCursor_TranslationUnit;
case Decl::Using:
@@ -3209,7 +3225,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
// We need to have names for all of the parameters, if we're going to
// generate a forwarding call.
- for (auto P : Method->params())
+ for (auto P : Method->parameters())
if (!P->getDeclName())
return;
@@ -3241,7 +3257,7 @@ static void MaybeAddOverrideCalls(Sema &S, DeclContext *InContext,
Overridden->getNameAsString()));
Builder.AddChunk(CodeCompletionString::CK_LeftParen);
bool FirstParam = true;
- for (auto P : Method->params()) {
+ for (auto P : Method->parameters()) {
if (FirstParam)
FirstParam = false;
else
@@ -3570,7 +3586,7 @@ static void AddObjCProperties(const CodeCompletionContext &CCContext,
Container = getContainerDef(Container);
// Add properties in this container.
- for (const auto *P : Container->properties())
+ for (const auto *P : Container->instance_properties())
if (AddedProperties.insert(P->getIdentifier()).second)
Results.MaybeAddResult(Result(P, Results.getBasePriority(P), nullptr),
CurContext);
@@ -3812,12 +3828,19 @@ void Sema::CodeCompleteTypeQualifiers(DeclSpec &DS) {
if (getLangOpts().C11 &&
!(DS.getTypeQualifiers() & DeclSpec::TQ_atomic))
Results.AddResult("_Atomic");
+ if (getLangOpts().MSVCCompat &&
+ !(DS.getTypeQualifiers() & DeclSpec::TQ_unaligned))
+ Results.AddResult("__unaligned");
Results.ExitScope();
HandleCodeCompleteResults(this, CodeCompleter,
Results.getCompletionContext(),
Results.data(), Results.size());
}
+void Sema::CodeCompleteBracketDeclarator(Scope *S) {
+ CodeCompleteExpression(S, QualType(getASTContext().getSizeType()));
+}
+
void Sema::CodeCompleteCase(Scope *S) {
if (getCurFunction()->SwitchStack.empty() || !CodeCompleter)
return;
@@ -6189,7 +6212,7 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
// Figure out which interface we're looking into.
ObjCInterfaceDecl *Class = nullptr;
if (ObjCImplementationDecl *ClassImpl
- = dyn_cast<ObjCImplementationDecl>(Container))
+ = dyn_cast<ObjCImplementationDecl>(Container))
Class = ClassImpl->getClassInterface();
else
Class = cast<ObjCCategoryImplDecl>(Container)->getCategoryDecl()
@@ -6198,8 +6221,8 @@ void Sema::CodeCompleteObjCPropertySynthesizeIvar(Scope *S,
// Determine the type of the property we're synthesizing.
QualType PropertyType = Context.getObjCIdType();
if (Class) {
- if (ObjCPropertyDecl *Property
- = Class->FindPropertyDeclaration(PropertyName)) {
+ if (ObjCPropertyDecl *Property = Class->FindPropertyDeclaration(
+ PropertyName, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
PropertyType
= Property->getType().getNonReferenceType().getUnqualifiedType();
@@ -7178,7 +7201,7 @@ void Sema::CodeCompleteObjCMethodDecl(Scope *S,
Containers.push_back(Cat);
for (unsigned I = 0, N = Containers.size(); I != N; ++I)
- for (auto *P : Containers[I]->properties())
+ for (auto *P : Containers[I]->instance_properties())
AddObjCKeyValueCompletions(P, IsInstanceMethod, ReturnType, Context,
KnownSelectors, Results);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
index 4b4fd6b16a06..c8715fff4159 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaCoroutine.cpp
@@ -244,7 +244,7 @@ ExprResult Sema::BuildCoawaitExpr(SourceLocation Loc, Expr *E) {
// If the expression is a temporary, materialize it as an lvalue so that we
// can use it multiple times.
if (E->getValueKind() == VK_RValue)
- E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
+ E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
// Build the await_ready, await_suspend, await_resume calls.
ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
@@ -311,7 +311,7 @@ ExprResult Sema::BuildCoyieldExpr(SourceLocation Loc, Expr *E) {
// If the expression is a temporary, materialize it as an lvalue so that we
// can use it multiple times.
if (E->getValueKind() == VK_RValue)
- E = new (Context) MaterializeTemporaryExpr(E->getType(), E, true);
+ E = CreateMaterializeTemporaryExpr(E->getType(), E, true);
// Build the await_ready, await_suspend, await_resume calls.
ReadySuspendResumeResult RSS = buildCoawaitCalls(*this, Loc, E);
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
index f95d1068cc59..ea276a995d81 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDecl.cpp
@@ -47,6 +47,7 @@
#include <algorithm>
#include <cstring>
#include <functional>
+
using namespace clang;
using namespace sema;
@@ -88,7 +89,7 @@ class TypeNameValidatorCCC : public CorrectionCandidateCallback {
bool AllowClassTemplates;
};
-}
+} // end anonymous namespace
/// \brief Determine whether the token kind starts a simple-type-specifier.
bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
@@ -107,6 +108,7 @@ bool Sema::isSimpleTypeSpecifier(tok::TokenKind Kind) const {
case tok::kw_half:
case tok::kw_float:
case tok::kw_double:
+ case tok::kw___float128:
case tok::kw_wchar_t:
case tok::kw_bool:
case tok::kw___underlying_type:
@@ -134,7 +136,7 @@ enum class UnqualifiedTypeNameLookupResult {
FoundNonType,
FoundType
};
-} // namespace
+} // end anonymous namespace
/// \brief Tries to perform unqualified lookup of the type decls in bases for
/// dependent class.
@@ -161,11 +163,17 @@ lookupUnqualifiedTypeNameInBase(Sema &S, const IdentifierInfo &II,
auto *TD = TST->getTemplateName().getAsTemplateDecl();
if (!TD)
continue;
- auto *BasePrimaryTemplate =
- dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl());
- if (!BasePrimaryTemplate)
- continue;
- BaseRD = BasePrimaryTemplate;
+ if (auto *BasePrimaryTemplate =
+ dyn_cast_or_null<CXXRecordDecl>(TD->getTemplatedDecl())) {
+ if (BasePrimaryTemplate->getCanonicalDecl() != RD->getCanonicalDecl())
+ BaseRD = BasePrimaryTemplate;
+ else if (auto *CTD = dyn_cast<ClassTemplateDecl>(TD)) {
+ if (const ClassTemplatePartialSpecializationDecl *PS =
+ CTD->findPartialSpecialization(Base.getType()))
+ if (PS->getCanonicalDecl() != RD->getCanonicalDecl())
+ BaseRD = PS;
+ }
+ }
}
if (BaseRD) {
for (NamedDecl *ND : BaseRD->lookup(&II)) {
@@ -207,7 +215,7 @@ static ParsedType recoverFromTypeInKnownDependentBase(Sema &S,
FoundTypeDecl = lookupUnqualifiedTypeNameInBase(S, II, NameLoc, RD);
}
if (FoundTypeDecl != UnqualifiedTypeNameLookupResult::FoundType)
- return ParsedType();
+ return nullptr;
// We found some types in dependent base classes. Recover as if the user
// wrote 'typename MyClass::II' instead of 'II'. We'll fully resolve the
@@ -266,25 +274,25 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// We therefore do not perform any name lookup if the result would
// refer to a member of an unknown specialization.
if (!isClassName && !IsCtorOrDtorName)
- return ParsedType();
-
+ return nullptr;
+
// We know from the grammar that this name refers to a type,
// so build a dependent node to describe the type.
if (WantNontrivialTypeSourceInfo)
return ActOnTypenameType(S, SourceLocation(), *SS, II, NameLoc).get();
-
+
NestedNameSpecifierLoc QualifierLoc = SS->getWithLocInContext(Context);
QualType T = CheckTypenameType(ETK_None, SourceLocation(), QualifierLoc,
II, NameLoc);
return ParsedType::make(T);
}
-
- return ParsedType();
+
+ return nullptr;
}
-
+
if (!LookupCtx->isDependentContext() &&
RequireCompleteDeclContext(*SS, LookupCtx))
- return ParsedType();
+ return nullptr;
}
// FIXME: LookupNestedNameSpecifierName isn't the right kind of
@@ -302,7 +310,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (ObjectTypePtr && Result.empty()) {
// C++ [basic.lookup.classref]p3:
// If the unqualified-id is ~type-name, the type-name is looked up
- // in the context of the entire postfix-expression. If the type T of
+ // in the context of the entire postfix-expression. If the type T of
// the object expression is of a class type C, the type-name is also
// looked up in the scope of class C. At least one of the lookups shall
// find a name that refers to (possibly cv-qualified) T.
@@ -346,8 +354,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// identifier is not a template (typo correction for template names
// is handled elsewhere).
!(getLangOpts().CPlusPlus && NewSSPtr &&
- isTemplateName(S, *NewSSPtr, false, TemplateName, ParsedType(),
- false, Template, MemberOfUnknownSpecialization))) {
+ isTemplateName(S, *NewSSPtr, false, TemplateName, nullptr, false,
+ Template, MemberOfUnknownSpecialization))) {
ParsedType Ty = getTypeName(*NewII, NameLoc, S, NewSSPtr,
isClassName, HasTrailingDot, ObjectTypePtr,
IsCtorOrDtorName,
@@ -367,7 +375,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
case LookupResult::Ambiguous:
// Recover from type-hiding ambiguities by hiding the type. We'll
@@ -377,7 +385,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// that only makes sense if the identifier was treated like a type.
if (Result.getAmbiguityKind() == LookupResult::AmbiguousTagHiding) {
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
// Look to see if we have a type anywhere in the list of results.
@@ -399,7 +407,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// will produce the ambiguity, or will complain that it expected
// a type name.
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
// We found a type within the ambiguous lookup; diagnose the
@@ -430,7 +438,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
// Construct a type with type-source information.
TypeLocBuilder Builder;
Builder.pushTypeSpec(T).setNameLoc(NameLoc);
-
+
T = getElaboratedType(ETK_None, *SS, T);
ElaboratedTypeLoc ElabTL = Builder.push<ElaboratedTypeLoc>(T);
ElabTL.setElaboratedKeywordLoc(SourceLocation());
@@ -449,7 +457,7 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (T.isNull()) {
// If it's not plausibly a type, suppress diagnostics.
Result.suppressDiagnostics();
- return ParsedType();
+ return nullptr;
}
return ParsedType::make(T);
}
@@ -471,17 +479,53 @@ synthesizeCurrentNestedNameSpecifier(ASTContext &Context, DeclContext *DC) {
llvm_unreachable("something isn't in TU scope?");
}
-ParsedType Sema::ActOnDelayedDefaultTemplateArg(const IdentifierInfo &II,
- SourceLocation NameLoc) {
- // Accepting an undeclared identifier as a default argument for a template
- // type parameter is a Microsoft extension.
- Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
+/// Find the parent class with dependent bases of the innermost enclosing method
+/// context. Do not look for enclosing CXXRecordDecls directly, or we will end
+/// up allowing unqualified dependent type names at class-level, which MSVC
+/// correctly rejects.
+static const CXXRecordDecl *
+findRecordWithDependentBasesOfEnclosingMethod(const DeclContext *DC) {
+ for (; DC && DC->isDependentContext(); DC = DC->getLookupParent()) {
+ DC = DC->getPrimaryContext();
+ if (const auto *MD = dyn_cast<CXXMethodDecl>(DC))
+ if (MD->getParent()->hasAnyDependentBases())
+ return MD->getParent();
+ }
+ return nullptr;
+}
+
+ParsedType Sema::ActOnMSVCUnknownTypeName(const IdentifierInfo &II,
+ SourceLocation NameLoc,
+ bool IsTemplateTypeArg) {
+ assert(getLangOpts().MSVCCompat && "shouldn't be called in non-MSVC mode");
+
+ NestedNameSpecifier *NNS = nullptr;
+ if (IsTemplateTypeArg && getCurScope()->isTemplateParamScope()) {
+ // If we weren't able to parse a default template argument, delay lookup
+ // until instantiation time by making a non-dependent DependentTypeName. We
+ // pretend we saw a NestedNameSpecifier referring to the current scope, and
+ // lookup is retried.
+ // FIXME: This hurts our diagnostic quality, since we get errors like "no
+ // type named 'Foo' in 'current_namespace'" when the user didn't write any
+ // name specifiers.
+ NNS = synthesizeCurrentNestedNameSpecifier(Context, CurContext);
+ Diag(NameLoc, diag::ext_ms_delayed_template_argument) << &II;
+ } else if (const CXXRecordDecl *RD =
+ findRecordWithDependentBasesOfEnclosingMethod(CurContext)) {
+ // Build a DependentNameType that will perform lookup into RD at
+ // instantiation time.
+ NNS = NestedNameSpecifier::Create(Context, nullptr, RD->isTemplateDecl(),
+ RD->getTypeForDecl());
+
+ // Diagnose that this identifier was undeclared, and retry the lookup during
+ // template instantiation.
+ Diag(NameLoc, diag::ext_undeclared_unqual_id_with_dependent_base) << &II
+ << RD;
+ } else {
+ // This is not a situation that we should recover from.
+ return ParsedType();
+ }
- // Build a fake DependentNameType that will perform lookup into CurContext at
- // instantiation time. The name specifier isn't dependent, so template
- // instantiation won't transform it. It will retry the lookup, however.
- NestedNameSpecifier *NNS =
- synthesizeCurrentNestedNameSpecifier(Context, CurContext);
QualType T = Context.getDependentNameType(ETK_None, NNS, &II);
// Build type location information. We synthesized the qualifier, so we have
@@ -548,7 +592,7 @@ bool Sema::isMicrosoftMissingTypename(const CXXScopeSpec *SS, Scope *S) {
if (Context.hasSameUnqualifiedType(QualType(Ty, 1), Base.getType()))
return true;
return S->isFunctionPrototypeScope();
- }
+ }
return CurContext->isFunctionOrMethod() || S->isFunctionPrototypeScope();
}
@@ -559,8 +603,8 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
ParsedType &SuggestedType,
bool AllowClassTemplates) {
// We don't have anything to suggest (yet).
- SuggestedType = ParsedType();
-
+ SuggestedType = nullptr;
+
// There may have been a typo in the name of the type. Look up typo
// results, in case we have something that we can suggest.
if (TypoCorrection Corrected =
@@ -592,11 +636,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
if (Corrected.getCorrectionSpecifier())
tmpSS.MakeTrivial(Context, Corrected.getCorrectionSpecifier(),
SourceRange(IILoc));
- SuggestedType = getTypeName(*Corrected.getCorrectionAsIdentifierInfo(),
- IILoc, S, tmpSS.isSet() ? &tmpSS : SS, false,
- false, ParsedType(),
- /*IsCtorOrDtorName=*/false,
- /*NonTrivialTypeSourceInfo=*/true);
+ SuggestedType =
+ getTypeName(*Corrected.getCorrectionAsIdentifierInfo(), IILoc, S,
+ tmpSS.isSet() ? &tmpSS : SS, false, false, nullptr,
+ /*IsCtorOrDtorName=*/false,
+ /*NonTrivialTypeSourceInfo=*/true);
}
return;
}
@@ -609,7 +653,7 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
TemplateTy TemplateResult;
bool MemberOfUnknownSpecialization;
if (isTemplateName(S, SS ? *SS : EmptySS, /*hasTemplateKeyword=*/false,
- Name, ParsedType(), true, TemplateResult,
+ Name, nullptr, true, TemplateResult,
MemberOfUnknownSpecialization) == TNK_Type_template) {
TemplateName TplName = TemplateResult.get();
Diag(IILoc, diag::err_template_missing_args) << TplName;
@@ -623,11 +667,11 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
// FIXME: Should we move the logic that tries to recover from a missing tag
// (struct, union, enum) from Parser::ParseImplicitInt here, instead?
-
+
if (!SS || (!SS->isSet() && !SS->isInvalid()))
Diag(IILoc, diag::err_unknown_typename) << II;
else if (DeclContext *DC = computeDeclContext(*SS, false))
- Diag(IILoc, diag::err_typename_nested_not_found)
+ Diag(IILoc, diag::err_typename_nested_not_found)
<< II << DC << SS->getRange();
else if (isDependentScopeSpecifier(*SS)) {
unsigned DiagID = diag::err_typename_missing;
@@ -641,25 +685,25 @@ void Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
SuggestedType = ActOnTypenameType(S, SourceLocation(),
*SS, *II, IILoc).get();
} else {
- assert(SS && SS->isInvalid() &&
+ assert(SS && SS->isInvalid() &&
"Invalid scope specifier has already been diagnosed");
}
}
/// \brief Determine whether the given result set contains either a type name
-/// or
+/// or
static bool isResultTypeOrTemplate(LookupResult &R, const Token &NextToken) {
bool CheckTemplate = R.getSema().getLangOpts().CPlusPlus &&
NextToken.is(tok::less);
-
+
for (LookupResult::iterator I = R.begin(), IEnd = R.end(); I != IEnd; ++I) {
if (isa<TypeDecl>(*I) || isa<ObjCInterfaceDecl>(*I))
return true;
-
+
if (CheckTemplate && isa<TemplateDecl>(*I))
return true;
}
-
+
return false;
}
@@ -751,7 +795,7 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
return TypeInBase;
}
- // Perform lookup for Objective-C instance variables (including automatically
+ // Perform lookup for Objective-C instance variables (including automatically
// synthesized instance variables), if we're in an Objective-C method.
// FIXME: This lookup really, really needs to be folded in to the normal
// unqualified lookup mechanism.
@@ -760,10 +804,10 @@ Sema::ClassifyName(Scope *S, CXXScopeSpec &SS, IdentifierInfo *&Name,
if (E.get() || E.isInvalid())
return E;
}
-
+
bool SecondTry = false;
bool IsFilteredTemplateName = false;
-
+
Corrected:
switch (Result.getResultKind()) {
case LookupResult::NotFound:
@@ -774,18 +818,18 @@ Corrected:
// FIXME: Reference?
if (getLangOpts().CPlusPlus)
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/true);
-
+
// C90 6.3.2.2:
- // If the expression that precedes the parenthesized argument list in a
- // function call consists solely of an identifier, and if no
- // declaration is visible for this identifier, the identifier is
+ // If the expression that precedes the parenthesized argument list in a
+ // function call consists solely of an identifier, and if no
+ // declaration is visible for this identifier, the identifier is
// implicitly declared exactly as if, in the innermost block containing
// the function call, the declaration
//
- // extern int identifier ();
+ // extern int identifier ();
+ //
+ // appeared.
//
- // appeared.
- //
// We also allow this in C99 as an extension.
if (NamedDecl *D = ImplicitlyDefineFunction(NameLoc, *Name, S)) {
Result.addDecl(D);
@@ -793,9 +837,9 @@ Corrected:
return BuildDeclarationNameExpr(SS, Result, /*ADL=*/false);
}
}
-
- // In C, we first see whether there is a tag type by the same name, in
- // which case it's likely that the user just forgot to write "enum",
+
+ // In C, we first see whether there is a tag type by the same name, in
+ // which case it's likely that the user just forgot to write "enum",
// "struct", or "union".
if (!getLangOpts().CPlusPlus && !SecondTry &&
isTagTypeWithMissingTag(*this, Result, S, SS, Name, NameLoc)) {
@@ -807,7 +851,7 @@ Corrected:
if (!SecondTry && CCC) {
SecondTry = true;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
- Result.getLookupKind(), S,
+ Result.getLookupKind(), S,
&SS, std::move(CCC),
CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
@@ -819,8 +863,8 @@ Corrected:
UnderlyingFirstDecl && isa<TemplateDecl>(UnderlyingFirstDecl)) {
UnqualifiedDiag = diag::err_no_template_suggest;
QualifiedDiag = diag::err_no_member_template_suggest;
- } else if (UnderlyingFirstDecl &&
- (isa<TypeDecl>(UnderlyingFirstDecl) ||
+ } else if (UnderlyingFirstDecl &&
+ (isa<TypeDecl>(UnderlyingFirstDecl) ||
isa<ObjCInterfaceDecl>(UnderlyingFirstDecl) ||
isa<ObjCCompatibleAliasDecl>(UnderlyingFirstDecl))) {
UnqualifiedDiag = diag::err_unknown_typename_suggest;
@@ -861,28 +905,28 @@ Corrected:
ExprResult E(LookupInObjCMethod(Result, S, Ivar->getIdentifier()));
return E;
}
-
+
goto Corrected;
}
}
-
+
// We failed to correct; just fall through and let the parser deal with it.
Result.suppressDiagnostics();
return NameClassification::Unknown();
-
+
case LookupResult::NotFoundInCurrentInstantiation: {
- // We performed name lookup into the current instantiation, and there were
+ // We performed name lookup into the current instantiation, and there were
// dependent bases, so we treat this result the same way as any other
// dependent nested-name-specifier.
-
+
// C++ [temp.res]p2:
- // A name used in a template declaration or definition and that is
- // dependent on a template-parameter is assumed not to name a type
- // unless the applicable name lookup finds a type name or the name is
+ // A name used in a template declaration or definition and that is
+ // dependent on a template-parameter is assumed not to name a type
+ // unless the applicable name lookup finds a type name or the name is
// qualified by the keyword typename.
//
// FIXME: If the next token is '<', we might want to ask the parser to
- // perform some heroics to see if we actually have a
+ // perform some heroics to see if we actually have a
// template-argument-list, which would indicate a missing 'template'
// keyword here.
return ActOnDependentIdExpression(SS, /*TemplateKWLoc=*/SourceLocation(),
@@ -894,7 +938,7 @@ Corrected:
case LookupResult::FoundOverloaded:
case LookupResult::FoundUnresolvedValue:
break;
-
+
case LookupResult::Ambiguous:
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
hasAnyAcceptableTemplateNames(Result)) {
@@ -915,29 +959,29 @@ Corrected:
break;
}
}
-
+
// Diagnose the ambiguity and return an error.
return NameClassification::Error();
}
-
+
if (getLangOpts().CPlusPlus && NextToken.is(tok::less) &&
(IsFilteredTemplateName || hasAnyAcceptableTemplateNames(Result))) {
// C++ [temp.names]p3:
// After name lookup (3.4) finds that a name is a template-name or that
// an operator-function-id or a literal- operator-id refers to a set of
- // overloaded functions any member of which is a function template if
+ // overloaded functions any member of which is a function template if
// this is followed by a <, the < is always taken as the delimiter of a
// template-argument-list and never as the less-than operator.
if (!IsFilteredTemplateName)
FilterAcceptableTemplateNames(Result);
-
+
if (!Result.empty()) {
bool IsFunctionTemplate;
bool IsVarTemplate;
TemplateName Template;
if (Result.end() - Result.begin() > 1) {
IsFunctionTemplate = true;
- Template = Context.getOverloadedTemplateName(Result.begin(),
+ Template = Context.getOverloadedTemplateName(Result.begin(),
Result.end());
} else {
TemplateDecl *TD
@@ -946,19 +990,19 @@ Corrected:
IsVarTemplate = isa<VarTemplateDecl>(TD);
if (SS.isSet() && !SS.isInvalid())
- Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
+ Template = Context.getQualifiedTemplateName(SS.getScopeRep(),
/*TemplateKeyword=*/false,
TD);
else
Template = TemplateName(TD);
}
-
+
if (IsFunctionTemplate) {
// Function templates always go through overload resolution, at which
// point we'll perform the various checks (e.g., accessibility) we need
// to based on which function we selected.
Result.suppressDiagnostics();
-
+
return NameClassification::FunctionTemplate(Template);
}
@@ -984,17 +1028,17 @@ Corrected:
dyn_cast<ObjCCompatibleAliasDecl>(FirstDecl))
Class = Alias->getClassInterface();
}
-
+
if (Class) {
DiagnoseUseOfDecl(Class, NameLoc);
-
+
if (NextToken.is(tok::period)) {
// Interface. <something> is parsed as a property reference expression.
// Just return "unknown" as a fall-through for now.
Result.suppressDiagnostics();
return NameClassification::Unknown();
}
-
+
QualType T = Context.getObjCInterfaceType(Class);
return ParsedType::make(T);
}
@@ -1018,7 +1062,7 @@ Corrected:
return buildNestedType(*this, SS, T, NameLoc);
return ParsedType::make(T);
}
-
+
if (FirstDecl->isCXXClassMember())
return BuildPossibleImplicitMemberExpr(SS, SourceLocation(), Result,
nullptr, S);
@@ -1035,15 +1079,15 @@ DeclContext *Sema::getContainingDC(DeclContext *DC) {
// Functions defined inline within classes aren't parsed until we've
// finished parsing the top-level class, so the top-level class is
// the context we'll need to return to.
- // A Lambda call operator whose parent is a class must not be treated
+ // A Lambda call operator whose parent is a class must not be treated
// as an inline member function. A Lambda can be used legally
// either as an in-class member initializer or a default argument. These
// are parsed once the class has been marked complete and so the containing
// context would be the nested class (when the lambda is defined in one);
- // If the class is not complete, then the lambda is being used in an
+ // If the class is not complete, then the lambda is being used in an
// ill-formed fashion (such as to specify the width of a bit-field, or
- // in an array-bound) - in which case we still want to return the
- // lexically containing DC (which could be a nested class).
+ // in an array-bound) - in which case we still want to return the
+ // lexically containing DC (which could be a nested class).
if (isa<FunctionDecl>(DC) && !isLambdaCallOperator(DC)) {
DC = DC->getLexicalParent();
@@ -1143,7 +1187,6 @@ void Sema::ExitDeclaratorContext(Scope *S) {
// disappear.
}
-
void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
// We assume that the caller has already called
// ActOnReenterTemplateScope so getTemplatedDecl() works.
@@ -1168,7 +1211,6 @@ void Sema::ActOnReenterFunctionContext(Scope* S, Decl *D) {
}
}
-
void Sema::ActOnExitFunctionContext() {
// Same implementation as PopDeclContext, but returns to the lexical parent,
// rather than the top-level class.
@@ -1177,7 +1219,6 @@ void Sema::ActOnExitFunctionContext() {
assert(CurContext && "Popped translation unit!");
}
-
/// \brief Determine whether we allow overloading of the function
/// PrevDecl with another declaration.
///
@@ -1226,7 +1267,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
cast<FunctionDecl>(D)->isFunctionTemplateSpecialization())
return;
- // If this replaces anything in the current scope,
+ // If this replaces anything in the current scope,
IdentifierResolver::iterator I = IdResolver.begin(D->getDeclName()),
IEnd = IdResolver.end();
for (; I != IEnd; ++I) {
@@ -1240,7 +1281,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
}
S->AddDecl(D);
-
+
if (isa<LabelDecl>(D) && !cast<LabelDecl>(D)->isGnuLocal()) {
// Implicitly-generated labels may end up getting generated in an order that
// isn't strictly lexical, which breaks name lookup. Be careful to insert
@@ -1253,7 +1294,7 @@ void Sema::PushOnScopeChains(NamedDecl *D, Scope *S, bool AddToContext) {
} else if (IDC->Encloses(CurContext))
break;
}
-
+
IdResolver.InsertDeclAfter(I, D);
} else {
IdResolver.AddDecl(D);
@@ -1416,6 +1457,9 @@ bool Sema::ShouldWarnIfUnusedFileScopedDecl(const DeclaratorDecl *D) const {
if (VD->isStaticDataMember() &&
VD->getTemplateSpecializationKind() == TSK_ImplicitInstantiation)
return false;
+
+ if (VD->isInline() && !isMainFileLoc(*this, VD->getLocation()))
+ return false;
} else {
return false;
}
@@ -1469,7 +1513,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
if (isa<TypedefNameDecl>(D))
return true;
-
+
// White-list anything that isn't a local variable.
if (!isa<VarDecl>(D) || isa<ParmVarDecl>(D) || isa<ImplicitParamDecl>(D))
return false;
@@ -1487,7 +1531,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
}
// If we failed to complete the type for some reason, or if the type is
- // dependent, don't diagnose the variable.
+ // dependent, don't diagnose the variable.
if (Ty->isIncompleteType() || Ty->isDependentType())
return false;
@@ -1517,7 +1561,7 @@ static bool ShouldDiagnoseUnusedDecl(const NamedDecl *D) {
// TODO: __attribute__((unused)) templates?
}
-
+
return true;
}
@@ -1531,7 +1575,6 @@ static void GenerateFixForUnusedDecl(const NamedDecl *D, ASTContext &Ctx,
Hint = FixItHint::CreateRemoval(CharSourceRange::
getCharRange(D->getLocStart(), AfterColon));
}
- return;
}
void Sema::DiagnoseUnusedNestedTypedefs(const RecordDecl *D) {
@@ -1558,7 +1601,7 @@ void Sema::DiagnoseUnusedDecl(const NamedDecl *D) {
UnusedLocalTypedefNameCandidates.insert(TD);
return;
}
-
+
FixItHint Hint;
GenerateFixForUnusedDecl(D, Context, Hint);
@@ -1608,13 +1651,23 @@ void Sema::ActOnPopScope(SourceLocation Loc, Scope *S) {
if (const auto *RD = dyn_cast<RecordDecl>(D))
DiagnoseUnusedNestedTypedefs(RD);
}
-
+
// If this was a forward reference to a label, verify it was defined.
if (LabelDecl *LD = dyn_cast<LabelDecl>(D))
CheckPoppedLabel(LD, *this);
-
- // Remove this name from our lexical scope.
+
+ // Remove this name from our lexical scope, and warn on it if we haven't
+ // already.
IdResolver.RemoveDecl(D);
+ auto ShadowI = ShadowingDecls.find(D);
+ if (ShadowI != ShadowingDecls.end()) {
+ if (const auto *FD = dyn_cast<FieldDecl>(ShadowI->second)) {
+ Diag(D->getLocation(), diag::warn_ctor_parm_shadows_field)
+ << D << FD << FD->getParent();
+ Diag(FD->getLocation(), diag::note_previous_declaration);
+ }
+ ShadowingDecls.erase(ShadowI);
+ }
}
}
@@ -1697,7 +1750,7 @@ static void LookupPredefedObjCSuperType(Sema &ThisSema, Scope *S,
if (!II->isStr("objc_msgSendSuper"))
return;
ASTContext &Context = ThisSema.Context;
-
+
LookupResult Result(ThisSema, &Context.Idents.get("objc_super"),
SourceLocation(), Sema::LookupTagName);
ThisSema.LookupName(Result, S);
@@ -1748,6 +1801,9 @@ NamedDecl *Sema::LazilyCreateBuiltin(IdentifierInfo *II, unsigned ID,
<< Context.BuiltinInfo.getName(ID);
}
+ if (R.isNull())
+ return nullptr;
+
DeclContext *Parent = Context.getTranslationUnitDecl();
if (getLangOpts().CPlusPlus) {
LinkageSpecDecl *CLinkageDecl =
@@ -1855,13 +1911,13 @@ bool Sema::isIncompatibleTypedef(TypeDecl *Old, TypedefNameDecl *New) {
if (Old->getLocation().isValid())
Diag(Old->getLocation(), diag::note_previous_definition);
New->setInvalidDecl();
- return true;
+ return true;
}
-
+
if (OldType != NewType &&
!OldType->isDependentType() &&
!NewType->isDependentType() &&
- !Context.hasSameType(OldType, NewType)) {
+ !Context.hasSameType(OldType, NewType)) {
int Kind = isa<TypeAliasDecl>(Old) ? 1 : 0;
Diag(New->getLocation(), diag::err_redefinition_different_typedef)
<< Kind << NewType << OldType;
@@ -2000,7 +2056,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
return;
// C++0x [dcl.typedef]p4:
- // In a given class scope, a typedef specifier can be used to redefine
+ // In a given class scope, a typedef specifier can be used to redefine
// any class-name declared in that scope that is not also a typedef-name
// to refer to the type to which it already refers.
//
@@ -2032,7 +2088,7 @@ void Sema::MergeTypedefNameDecl(Scope *S, TypedefNameDecl *New,
// Modules always permit redefinition of typedefs, as does C11.
if (getLangOpts().Modules || getLangOpts().C11)
return;
-
+
// If we have a redefinition of a typedef in C, emit a warning. This warning
// is normally mapped to an error, but can be controlled with
// -Wtypedef-redefinition. If either the original or the redefinition is
@@ -2194,9 +2250,11 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
unsigned AttrSpellingListIndex = Attr->getSpellingListIndex();
if (const auto *AA = dyn_cast<AvailabilityAttr>(Attr))
NewAttr = S.mergeAvailabilityAttr(D, AA->getRange(), AA->getPlatform(),
- AA->getIntroduced(), AA->getDeprecated(),
+ AA->isImplicit(), AA->getIntroduced(),
+ AA->getDeprecated(),
AA->getObsoleted(), AA->getUnavailable(),
- AA->getMessage(), AMK,
+ AA->getMessage(), AA->getStrict(),
+ AA->getReplacement(), AMK,
AttrSpellingListIndex);
else if (const auto *VA = dyn_cast<VisibilityAttr>(Attr))
NewAttr = S.mergeVisibilityAttr(D, VA->getRange(), VA->getVisibility(),
@@ -2252,6 +2310,8 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
if (NewAttr) {
NewAttr->setInherited(true);
D->addAttr(NewAttr);
+ if (isa<MSInheritanceAttr>(NewAttr))
+ S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
return true;
}
@@ -2267,11 +2327,8 @@ static const Decl *getDefinition(const Decl *D) {
return Def;
return VD->getActingDefinition();
}
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
- const FunctionDecl* Def;
- if (FD->isDefined(Def))
- return Def;
- }
+ if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getDefinition();
return nullptr;
}
@@ -2296,7 +2353,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
for (unsigned I = 0, E = NewAttributes.size(); I != E;) {
const Attr *NewAttribute = NewAttributes[I];
- if (isa<AliasAttr>(NewAttribute)) {
+ if (isa<AliasAttr>(NewAttribute) || isa<IFuncAttr>(NewAttribute)) {
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(New)) {
Sema::SkipBodyInfo SkipBody;
S.CheckForFunctionRedefinition(FD, cast<FunctionDecl>(Def), &SkipBody);
@@ -2339,7 +2396,7 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) {
++I;
continue;
} else if (const AlignedAttr *AA = dyn_cast<AlignedAttr>(NewAttribute)) {
- if (AA->isAlignas()) {
+ if (AA->isAlignas()) {
// C++11 [dcl.align]p6:
// if any declaration of an entity has an alignment-specifier,
// every defining declaration of that entity shall specify an
@@ -2396,6 +2453,24 @@ void Sema::mergeDeclAttributes(NamedDecl *New, Decl *Old,
}
}
+ // Re-declaration cannot add abi_tag's.
+ if (const auto *NewAbiTagAttr = New->getAttr<AbiTagAttr>()) {
+ if (const auto *OldAbiTagAttr = Old->getAttr<AbiTagAttr>()) {
+ for (const auto &NewTag : NewAbiTagAttr->tags()) {
+ if (std::find(OldAbiTagAttr->tags_begin(), OldAbiTagAttr->tags_end(),
+ NewTag) == OldAbiTagAttr->tags_end()) {
+ Diag(NewAbiTagAttr->getLocation(),
+ diag::err_new_abi_tag_on_redeclaration)
+ << NewTag;
+ Diag(OldAbiTagAttr->getLocation(), diag::note_previous_declaration);
+ }
+ }
+ } else {
+ Diag(NewAbiTagAttr->getLocation(), diag::err_abi_tag_on_redeclaration);
+ Diag(Old->getLocation(), diag::note_previous_declaration);
+ }
+ }
+
if (!Old->hasAttrs())
return;
@@ -2519,7 +2594,7 @@ struct GNUCompatibleParamWarning {
QualType PromotedType;
};
-}
+} // end anonymous namespace
/// getSpecialMember - get the special member enum for a method.
Sema::CXXSpecialMember Sema::getSpecialMember(const CXXMethodDecl *MD) {
@@ -2799,11 +2874,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
Diag(OldLocation, diag::note_previous_declaration);
return true;
}
-
+
NewTypeInfo = NewTypeInfo.withProducesResult(true);
RequiresAdjustment = true;
}
-
+
if (RequiresAdjustment) {
const FunctionType *AdjustedType = New->getType()->getAs<FunctionType>();
AdjustedType = Context.adjustFunctionType(AdjustedType, NewTypeInfo);
@@ -2956,11 +3031,11 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, NamedDecl *&OldD,
NewMethod->setImplicit();
} else {
Diag(NewMethod->getLocation(),
- diag::err_definition_of_implicitly_declared_member)
+ diag::err_definition_of_implicitly_declared_member)
<< New << getSpecialMember(OldMethod);
return true;
}
- } else if (OldMethod->isExplicitlyDefaulted() && !isFriend) {
+ } else if (OldMethod->getFirstDecl()->isExplicitlyDefaulted() && !isFriend) {
Diag(NewMethod->getLocation(),
diag::err_definition_of_explicitly_defaulted_member)
<< getSpecialMember(OldMethod);
@@ -3221,10 +3296,8 @@ bool Sema::MergeCompatibleFunctionDecls(FunctionDecl *New, FunctionDecl *Old,
return false;
}
-
void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
ObjCMethodDecl *oldMethod) {
-
// Merge the attributes, including deprecated/unavailable
AvailabilityMergeKind MergeKind =
isa<ObjCProtocolDecl>(oldMethod->getDeclContext())
@@ -3245,6 +3318,22 @@ void Sema::mergeObjCMethodDecls(ObjCMethodDecl *newMethod,
CheckObjCMethodOverride(newMethod, oldMethod);
}
+static void diagnoseVarDeclTypeMismatch(Sema &S, VarDecl *New, VarDecl* Old) {
+ assert(!S.Context.hasSameType(New->getType(), Old->getType()));
+
+ S.Diag(New->getLocation(), New->isThisDeclarationADefinition()
+ ? diag::err_redefinition_different_type
+ : diag::err_redeclaration_different_type)
+ << New->getDeclName() << New->getType() << Old->getType();
+
+ diag::kind PrevDiag;
+ SourceLocation OldLocation;
+ std::tie(PrevDiag, OldLocation)
+ = getNoteDiagForInvalidRedeclaration(Old, New);
+ S.Diag(OldLocation, PrevDiag);
+ New->setInvalidDecl();
+}
+
/// MergeVarDeclTypes - We parsed a variable 'New' which has the same name and
/// scope as a previous declaration 'Old'. Figure out how to merge their types,
/// emitting diagnostics as appropriate.
@@ -3271,21 +3360,40 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
// object or function shall be identical, except that declarations for an
// array object can specify array types that differ by the presence or
// absence of a major array bound (8.3.4).
- else if (Old->getType()->isIncompleteArrayType() &&
- New->getType()->isArrayType()) {
- const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
- const ArrayType *NewArray = Context.getAsArrayType(New->getType());
- if (Context.hasSameType(OldArray->getElementType(),
- NewArray->getElementType()))
- MergedT = New->getType();
- } else if (Old->getType()->isArrayType() &&
- New->getType()->isIncompleteArrayType()) {
+ else if (Old->getType()->isArrayType() && New->getType()->isArrayType()) {
const ArrayType *OldArray = Context.getAsArrayType(Old->getType());
const ArrayType *NewArray = Context.getAsArrayType(New->getType());
- if (Context.hasSameType(OldArray->getElementType(),
- NewArray->getElementType()))
- MergedT = Old->getType();
- } else if (New->getType()->isObjCObjectPointerType() &&
+
+ // We are merging a variable declaration New into Old. If it has an array
+ // bound, and that bound differs from Old's bound, we should diagnose the
+ // mismatch.
+ if (!NewArray->isIncompleteArrayType()) {
+ for (VarDecl *PrevVD = Old->getMostRecentDecl(); PrevVD;
+ PrevVD = PrevVD->getPreviousDecl()) {
+ const ArrayType *PrevVDTy = Context.getAsArrayType(PrevVD->getType());
+ if (PrevVDTy->isIncompleteArrayType())
+ continue;
+
+ if (!Context.hasSameType(NewArray, PrevVDTy))
+ return diagnoseVarDeclTypeMismatch(*this, New, PrevVD);
+ }
+ }
+
+ if (OldArray->isIncompleteArrayType() && NewArray->isArrayType()) {
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
+ MergedT = New->getType();
+ }
+ // FIXME: Check visibility. New is hidden but has a complete type. If New
+ // has no array bound, it should not inherit one from Old, if Old is not
+ // visible.
+ else if (OldArray->isArrayType() && NewArray->isIncompleteArrayType()) {
+ if (Context.hasSameType(OldArray->getElementType(),
+ NewArray->getElementType()))
+ MergedT = Old->getType();
+ }
+ }
+ else if (New->getType()->isObjCObjectPointerType() &&
Old->getType()->isObjCObjectPointerType()) {
MergedT = Context.mergeObjCGCQualifiers(New->getType(),
Old->getType());
@@ -3311,27 +3419,7 @@ void Sema::MergeVarDeclTypes(VarDecl *New, VarDecl *Old,
New->setType(Context.DependentTy);
return;
}
-
- // FIXME: Even if this merging succeeds, some other non-visible declaration
- // of this variable might have an incompatible type. For instance:
- //
- // extern int arr[];
- // void f() { extern int arr[2]; }
- // void g() { extern int arr[3]; }
- //
- // Neither C nor C++ requires a diagnostic for this, but we should still try
- // to diagnose it.
- Diag(New->getLocation(), New->isThisDeclarationADefinition()
- ? diag::err_redefinition_different_type
- : diag::err_redeclaration_different_type)
- << New->getDeclName() << New->getType() << Old->getType();
-
- diag::kind PrevDiag;
- SourceLocation OldLocation;
- std::tie(PrevDiag, OldLocation) =
- getNoteDiagForInvalidRedeclaration(Old, New);
- Diag(OldLocation, PrevDiag);
- return New->setInvalidDecl();
+ return diagnoseVarDeclTypeMismatch(*this, New, Old);
}
// Don't actually update the type on the new declaration if the old
@@ -3425,17 +3513,17 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
// C++ [class.mem]p1:
// A member shall not be declared twice in the member-specification [...]
- //
+ //
// Here, we need only consider static data members.
if (Old->isStaticDataMember() && !New->isOutOfLine()) {
- Diag(New->getLocation(), diag::err_duplicate_member)
+ Diag(New->getLocation(), diag::err_duplicate_member)
<< New->getIdentifier();
Diag(Old->getLocation(), diag::note_previous_declaration);
New->setInvalidDecl();
}
-
+
mergeDeclAttributes(New, Old);
- // Warn if an already-declared variable is made a weak_import in a subsequent
+ // Warn if an already-declared variable is made a weak_import in a subsequent
// declaration
if (New->hasAttr<WeakImportAttr>() &&
Old->getStorageClass() == SC_None &&
@@ -3533,6 +3621,23 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
return New->setInvalidDecl();
}
+ if (New->isInline() && !Old->getMostRecentDecl()->isInline()) {
+ if (VarDecl *Def = Old->getDefinition()) {
+ // C++1z [dcl.fcn.spec]p4:
+ // If the definition of a variable appears in a translation unit before
+ // its first declaration as inline, the program is ill-formed.
+ Diag(New->getLocation(), diag::err_inline_decl_follows_def) << New;
+ Diag(Def->getLocation(), diag::note_previous_definition);
+ }
+ }
+
+ // If this redeclaration makes the function inline, we may need to add it to
+ // UndefinedButUsed.
+ if (!Old->isInline() && New->isInline() && Old->isUsed(false) &&
+ !Old->getDefinition() && !New->isThisDeclarationADefinition())
+ UndefinedButUsed.insert(std::make_pair(Old->getCanonicalDecl(),
+ SourceLocation()));
+
if (New->getTLSKind() != Old->getTLSKind()) {
if (!Old->getTLSKind()) {
Diag(New->getLocation(), diag::err_thread_non_thread) << New->getDeclName();
@@ -3564,6 +3669,12 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->getDeclContext()->isDependentContext())) {
// The previous definition is hidden, and multiple definitions are
// permitted (in separate TUs). Form another definition of it.
+ } else if (Old->isStaticDataMember() &&
+ Old->getCanonicalDecl()->isInline() &&
+ Old->getCanonicalDecl()->isConstexpr()) {
+ // This definition won't be a definition any more once it's been merged.
+ Diag(New->getLocation(),
+ diag::warn_deprecated_redundant_constexpr_static_def);
} else {
Diag(New->getLocation(), diag::err_redefinition) << New;
Diag(Def->getLocation(), diag::note_previous_definition);
@@ -3592,13 +3703,18 @@ void Sema::MergeVarDecl(VarDecl *New, LookupResult &Previous) {
New->setAccess(Old->getAccess());
if (NewTemplate)
NewTemplate->setAccess(New->getAccess());
+
+ if (Old->isInline())
+ New->setImplicitlyInline();
}
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed.
-Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS) {
- return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg());
+Decl *
+Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
+ RecordDecl *&AnonRecord) {
+ return ParsedFreeStandingDeclSpec(S, AS, DS, MultiTemplateParamsArg(), false,
+ AnonRecord);
}
// The MS ABI changed between VS2013 and VS2015 with regard to numbers used to
@@ -3704,10 +3820,11 @@ static unsigned GetDiagnosticTypeSpecifierID(DeclSpec::TST T) {
/// ParsedFreeStandingDeclSpec - This method is invoked when a declspec with
/// no declarator (e.g. "struct foo;") is parsed. It also accepts template
/// parameters to cope with template friend declarations.
-Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
- DeclSpec &DS,
- MultiTemplateParamsArg TemplateParams,
- bool IsExplicitInstantiation) {
+Decl *
+Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, DeclSpec &DS,
+ MultiTemplateParamsArg TemplateParams,
+ bool IsExplicitInstantiation,
+ RecordDecl *&AnonRecord) {
Decl *TagD = nullptr;
TagDecl *Tag = nullptr;
if (DS.getTypeSpecType() == DeclSpec::TST_class ||
@@ -3745,6 +3862,10 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
<< DS.getSourceRange();
}
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
+
if (DS.isConstexprSpecified()) {
// C++0x [dcl.constexpr]p1: constexpr can only be applied to declarations
// and definitions of functions and variables.
@@ -3802,9 +3923,19 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
if (!Record->getDeclName() && Record->isCompleteDefinition() &&
DS.getStorageClassSpec() != DeclSpec::SCS_typedef) {
if (getLangOpts().CPlusPlus ||
- Record->getDeclContext()->isRecord())
+ Record->getDeclContext()->isRecord()) {
+ // If CurContext is a DeclContext that can contain statements,
+ // RecursiveASTVisitor won't visit the decls that
+ // BuildAnonymousStructOrUnion() will put into CurContext.
+ // Also store them here so that they can be part of the
+ // DeclStmt that gets created in this case.
+ // FIXME: Also return the IndirectFieldDecls created by
+ // BuildAnonymousStructOr union, for the same reason?
+ if (CurContext->isFunctionOrMethod())
+ AnonRecord = Record;
return BuildAnonymousStructOrUnion(S, DS, AS, Record,
Context.getPrintingPolicy());
+ }
DeclaresAnything = false;
}
@@ -3926,6 +4057,8 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
// Restrict is covered above.
if (DS.getTypeQualifiers() & DeclSpec::TQ_atomic)
Diag(DS.getAtomicSpecLoc(), DiagID) << "_Atomic";
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned)
+ Diag(DS.getUnalignedSpecLoc(), DiagID) << "__unaligned";
}
// Warn about ignored type attributes, for example:
@@ -3992,12 +4125,10 @@ static bool CheckAnonMemberRedeclaration(Sema &SemaRef,
///
/// This routine is recursive, injecting the names of nested anonymous
/// structs/unions into the owning context and scope as well.
-static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
- DeclContext *Owner,
- RecordDecl *AnonRecord,
- AccessSpecifier AS,
- SmallVectorImpl<NamedDecl *> &Chaining,
- bool MSAnonStruct) {
+static bool
+InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S, DeclContext *Owner,
+ RecordDecl *AnonRecord, AccessSpecifier AS,
+ SmallVectorImpl<NamedDecl *> &Chaining) {
bool Invalid = false;
// Look every FieldDecl and IndirectFieldDecl with a name.
@@ -4033,7 +4164,7 @@ static bool InjectAnonymousStructOrUnionMembers(Sema &SemaRef, Scope *S,
IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
SemaRef.Context, Owner, VD->getLocation(), VD->getIdentifier(),
- VD->getType(), NamedChain, Chaining.size());
+ VD->getType(), {NamedChain, Chaining.size()});
for (const auto *Attr : VD->attrs())
IndirectField->addAttr(Attr->clone(SemaRef.Context));
@@ -4143,7 +4274,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
cast<NamespaceDecl>(Owner)->getDeclName()))) {
Diag(Record->getLocation(), diag::err_anonymous_union_not_static)
<< FixItHint::CreateInsertion(Record->getLocation(), "static ");
-
+
// Recover by adding 'static'.
DS.SetStorageClassSpec(*this, DeclSpec::SCS_static, SourceLocation(),
PrevSpec, DiagID, Policy);
@@ -4156,9 +4287,9 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
Diag(DS.getStorageClassSpecLoc(),
diag::err_anonymous_union_with_storage_spec)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
-
+
// Recover by removing the storage specifier.
- DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified,
+ DS.SetStorageClassSpec(*this, DeclSpec::SCS_unspecified,
SourceLocation(),
PrevSpec, DiagID, Context.getPrintingPolicy());
}
@@ -4185,6 +4316,11 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
diag::ext_anonymous_struct_union_qualified)
<< Record->isUnion() << "_Atomic"
<< FixItHint::CreateRemoval(DS.getAtomicSpecLoc());
+ if (DS.getTypeQualifiers() & DeclSpec::TQ_unaligned)
+ Diag(DS.getUnalignedSpecLoc(),
+ diag::ext_anonymous_struct_union_qualified)
+ << Record->isUnion() << "__unaligned"
+ << FixItHint::CreateRemoval(DS.getUnalignedSpecLoc());
DS.ClearTypeQualifiers();
}
@@ -4254,7 +4390,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
DK = diag::err_anonymous_record_with_function;
else if (isa<VarDecl>(Mem))
DK = diag::err_anonymous_record_with_static;
-
+
// Visual C++ allows type definition in anonymous struct or union.
if (getLangOpts().MicrosoftExt &&
DK == diag::err_anonymous_record_with_type)
@@ -4340,8 +4476,7 @@ Decl *Sema::BuildAnonymousStructOrUnion(Scope *S, DeclSpec &DS,
SmallVector<NamedDecl*, 2> Chain;
Chain.push_back(Anon);
- if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS,
- Chain, false))
+ if (InjectAnonymousStructOrUnionMembers(*this, S, Owner, Record, AS, Chain))
Invalid = true;
if (VarDecl *NewVD = dyn_cast<VarDecl>(Anon)) {
@@ -4413,7 +4548,7 @@ Decl *Sema::BuildMicrosoftCAnonymousStruct(Scope *S, DeclSpec &DS,
if (RequireCompleteType(Anon->getLocation(), RecTy,
diag::err_field_incomplete) ||
InjectAnonymousStructOrUnionMembers(*this, S, CurContext, RecordDef,
- AS_none, Chain, true)) {
+ AS_none, Chain)) {
Anon->setInvalidDecl();
ParentDecl->setInvalidDecl();
}
@@ -4662,7 +4797,7 @@ Decl *Sema::ActOnDeclarator(Scope *S, Declarator &D) {
}
/// DiagnoseClassNameShadow - Implement C++ [class.mem]p13:
-/// If T is the name of a class, then each of the following shall have a
+/// If T is the name of a class, then each of the following shall have a
/// name different from T:
/// - every static data member of class T;
/// - every member function of class T
@@ -4683,12 +4818,12 @@ bool Sema::DiagnoseClassNameShadow(DeclContext *DC,
return false;
}
-/// \brief Diagnose a declaration whose declarator-id has the given
+/// \brief Diagnose a declaration whose declarator-id has the given
/// nested-name-specifier.
///
/// \param SS The nested-name-specifier of the declarator-id.
///
-/// \param DC The declaration context to which the nested-name-specifier
+/// \param DC The declaration context to which the nested-name-specifier
/// resolves.
///
/// \param Name The name of the entity being declared.
@@ -4734,15 +4869,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
Diag(Loc, diag::err_invalid_declarator_global_scope)
<< Name << SS.getRange();
else if (isa<FunctionDecl>(Cur))
- Diag(Loc, diag::err_invalid_declarator_in_function)
+ Diag(Loc, diag::err_invalid_declarator_in_function)
<< Name << SS.getRange();
else if (isa<BlockDecl>(Cur))
- Diag(Loc, diag::err_invalid_declarator_in_block)
+ Diag(Loc, diag::err_invalid_declarator_in_block)
<< Name << SS.getRange();
else
Diag(Loc, diag::err_invalid_declarator_scope)
<< Name << cast<NamedDecl>(Cur) << cast<NamedDecl>(DC) << SS.getRange();
-
+
return true;
}
@@ -4751,7 +4886,7 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
Diag(Loc, diag::err_member_qualification)
<< Name << SS.getRange();
SS.clear();
-
+
// C++ constructors and destructors with incorrect scopes can break
// our AST invariants by having the wrong underlying types. If
// that's the case, then drop this declaration entirely.
@@ -4760,10 +4895,10 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
!Context.hasSameType(Name.getCXXNameType(),
Context.getTypeDeclType(cast<CXXRecordDecl>(Cur))))
return true;
-
+
return false;
}
-
+
// C++11 [dcl.meaning]p1:
// [...] "The nested-name-specifier of the qualified declarator-id shall
// not begin with a decltype-specifer"
@@ -4805,7 +4940,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (D.getCXXScopeSpec().isInvalid())
D.setInvalidType();
else if (D.getCXXScopeSpec().isSet()) {
- if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(),
+ if (DiagnoseUnexpandedParameterPack(D.getCXXScopeSpec(),
UPPC_DeclarationQualifier))
return nullptr;
@@ -4824,7 +4959,7 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
}
bool IsDependentContext = DC->isDependentContext();
- if (!IsDependentContext &&
+ if (!IsDependentContext &&
RequireCompleteDeclContext(D.getCXXScopeSpec(), DC))
return nullptr;
@@ -4904,11 +5039,11 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
LookupQualifiedName(Previous, DC);
// C++ [dcl.meaning]p1:
- // When the declarator-id is qualified, the declaration shall refer to a
- // previously declared member of the class or namespace to which the
+ // When the declarator-id is qualified, the declaration shall refer to a
+ // previously declared member of the class or namespace to which the
// qualifier refers (or, in the case of a namespace, of an element of the
// inline namespace set of that namespace (7.3.1)) or to a specialization
- // thereof; [...]
+ // thereof; [...]
//
// Note that we already checked the context above, and that we do not have
// enough information to make sure that Previous contains the declaration
@@ -4924,10 +5059,10 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
// In this case, Previous will point to the overload set
// containing the two f's declared in X, but neither of them
// matches.
-
+
// C++ [dcl.meaning]p1:
- // [...] the member shall not merely have been introduced by a
- // using-declaration in the scope of the class or namespace nominated by
+ // [...] the member shall not merely have been introduced by a
+ // using-declaration in the scope of the class or namespace nominated by
// the nested-name-specifier of the declarator-id.
RemoveUsingDecls(Previous);
}
@@ -4995,10 +5130,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
if (!New)
return nullptr;
- // If this has an identifier and is not an invalid redeclaration or
- // function template specialization, add it to the scope stack.
- if (New->getDeclName() && AddToScope &&
- !(D.isRedeclaration() && New->isInvalidDecl())) {
+ // If this has an identifier and is not a function template specialization,
+ // add it to the scope stack.
+ if (New->getDeclName() && AddToScope) {
// Only make a locally-scoped extern declaration visible if it is the first
// declaration of this entity. Qualified lookup for such an entity should
// only find this declaration if there is no visible declaration of it.
@@ -5008,6 +5142,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
CurContext->addHiddenDecl(New);
}
+ if (isInOpenMPDeclareTargetContext())
+ checkDeclIsAllowedInOpenMPTarget(nullptr, New);
+
return New;
}
@@ -5024,10 +5161,10 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
// constant expression folding, like struct {char x[(int)(char*)2];}
SizeIsNegative = false;
Oversized = 0;
-
+
if (T->isDependentType())
return QualType();
-
+
QualifierCollector Qs;
const Type *Ty = Qs.strip(T);
@@ -5076,7 +5213,7 @@ static QualType TryToFixInvalidVariablyModifiedType(QualType T,
Oversized = Res;
return QualType();
}
-
+
return Context.getConstantArrayType(VLATy->getElementType(),
Res, ArrayType::Normal, 0);
}
@@ -5154,11 +5291,7 @@ NamedDecl *Sema::findLocallyScopedExternCDecl(DeclarationName Name) {
/// does not identify a function.
void Sema::DiagnoseFunctionSpecifiers(const DeclSpec &DS) {
// FIXME: We should probably indicate the identifier in question to avoid
- // confusion for constructs like "inline int a(), b;"
- if (DS.isInlineSpecified())
- Diag(DS.getInlineSpecLoc(),
- diag::err_inline_non_function);
-
+ // confusion for constructs like "virtual int a(), b;"
if (DS.isVirtualSpecified())
Diag(DS.getVirtualSpecLoc(),
diag::err_virtual_non_function);
@@ -5187,6 +5320,9 @@ Sema::ActOnTypedefDeclarator(Scope* S, Declarator& D, DeclContext* DC,
DiagnoseFunctionSpecifiers(D.getDeclSpec());
+ if (D.getDeclSpec().isInlineSpecified())
+ Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (D.getDeclSpec().isConstexprSpecified())
Diag(D.getDeclSpec().getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 1;
@@ -5241,7 +5377,7 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
else if (T->isVariableArrayType())
Diag(NewTD->getLocation(), diag::err_vla_decl_in_file_scope);
else if (Oversized.getBoolValue())
- Diag(NewTD->getLocation(), diag::err_array_too_large)
+ Diag(NewTD->getLocation(), diag::err_array_too_large)
<< Oversized.toString(10);
else
Diag(NewTD->getLocation(), diag::err_vm_decl_in_file_scope);
@@ -5251,7 +5387,6 @@ Sema::CheckTypedefForVariablyModifiedType(Scope *S, TypedefNameDecl *NewTD) {
}
}
-
/// ActOnTypedefNameDecl - Perform semantic checking for a declaration which
/// declares a typedef-name, either using the 'typedef' type specifier or via
/// a C++0x [dcl.typedef]p2 alias-declaration: 'using T = A;'.
@@ -5323,12 +5458,12 @@ isOutOfScopePreviousDeclaration(NamedDecl *PrevDecl, DeclContext *DC,
if (!OuterContext->isFunctionOrMethod())
// This rule only applies to block-scope declarations.
return false;
-
+
DeclContext *PrevOuterContext = PrevDecl->getDeclContext();
if (PrevOuterContext->isRecord())
// We found a member function: ignore it.
return false;
-
+
// Find the innermost enclosing namespace for the new and
// previous declarations.
OuterContext = OuterContext->getEnclosingNamespaceContext();
@@ -5379,7 +5514,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
type = Context.getLifetimeQualifiedType(type, lifetime);
decl->setType(type);
}
-
+
if (VarDecl *var = dyn_cast<VarDecl>(decl)) {
// Thread-local variables cannot have lifetime.
if (lifetime && lifetime != Qualifiers::OCL_ExplicitNone &&
@@ -5389,7 +5524,7 @@ bool Sema::inferObjCARCLifetime(ValueDecl *decl) {
return true;
}
}
-
+
return false;
}
@@ -5418,7 +5553,7 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
if (const auto *Attr = VD->getAttr<AliasAttr>()) {
assert(VD->isThisDeclarationADefinition() &&
!VD->isExternallyVisible() && "Broken AliasAttr handled late!");
- S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD;
+ S.Diag(Attr->getLocation(), diag::err_alias_is_definition) << VD << 0;
VD->dropAttr<AliasAttr>();
}
}
@@ -5458,9 +5593,13 @@ static void checkAttributesAfterMerging(Sema &S, NamedDecl &ND) {
static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
NamedDecl *NewDecl,
- bool IsSpecialization) {
- if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl))
+ bool IsSpecialization,
+ bool IsDefinition) {
+ if (TemplateDecl *OldTD = dyn_cast<TemplateDecl>(OldDecl)) {
OldDecl = OldTD->getTemplatedDecl();
+ if (!IsSpecialization)
+ IsDefinition = false;
+ }
if (TemplateDecl *NewTD = dyn_cast<TemplateDecl>(NewDecl))
NewDecl = NewTD->getTemplatedDecl();
@@ -5516,14 +5655,17 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
// A redeclaration is not allowed to drop a dllimport attribute, the only
// exceptions being inline function definitions, local extern declarations,
- // and qualified friend declarations.
- // NB: MSVC converts such a declaration to dllexport.
+ // qualified friend declarations or special MSVC extension: in the last case,
+ // the declaration is treated as if it were marked dllexport.
bool IsInline = false, IsStaticDataMember = false, IsQualifiedFriend = false;
- if (const auto *VD = dyn_cast<VarDecl>(NewDecl))
+ bool IsMicrosoft = S.Context.getTargetInfo().getCXXABI().isMicrosoft();
+ if (const auto *VD = dyn_cast<VarDecl>(NewDecl)) {
// Ignore static data because out-of-line definitions are diagnosed
// separately.
IsStaticDataMember = VD->isStaticDataMember();
- else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) {
+ IsDefinition = VD->isThisDeclarationADefinition(S.Context) !=
+ VarDecl::DeclarationOnly;
+ } else if (const auto *FD = dyn_cast<FunctionDecl>(NewDecl)) {
IsInline = FD->isInlined();
IsQualifiedFriend = FD->getQualifier() &&
FD->getFriendObjectKind() == Decl::FOK_Declared;
@@ -5531,15 +5673,25 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
if (OldImportAttr && !HasNewAttr && !IsInline && !IsStaticDataMember &&
!NewDecl->isLocalExternDecl() && !IsQualifiedFriend) {
- S.Diag(NewDecl->getLocation(),
- diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
- << NewDecl << OldImportAttr;
- S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
- S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
- OldDecl->dropAttr<DLLImportAttr>();
- NewDecl->dropAttr<DLLImportAttr>();
- } else if (IsInline && OldImportAttr &&
- !S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ if (IsMicrosoft && IsDefinition) {
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_redeclaration_without_import_attribute)
+ << NewDecl;
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ NewDecl->dropAttr<DLLImportAttr>();
+ NewDecl->addAttr(::new (S.Context) DLLExportAttr(
+ NewImportAttr->getRange(), S.Context,
+ NewImportAttr->getSpellingListIndex()));
+ } else {
+ S.Diag(NewDecl->getLocation(),
+ diag::warn_redeclaration_without_attribute_prev_attribute_ignored)
+ << NewDecl << OldImportAttr;
+ S.Diag(OldDecl->getLocation(), diag::note_previous_declaration);
+ S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
+ OldDecl->dropAttr<DLLImportAttr>();
+ NewDecl->dropAttr<DLLImportAttr>();
+ }
+ } else if (IsInline && OldImportAttr && !IsMicrosoft) {
// In MinGW, seeing a function declared inline drops the dllimport attribute.
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
@@ -5605,10 +5757,9 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) {
if (!D->isInExternCContext() || D->template hasAttr<OverloadableAttr>())
return false;
- // So do CUDA's host/device attributes if overloading is enabled.
- if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads &&
- (D->template hasAttr<CUDADeviceAttr>() ||
- D->template hasAttr<CUDAHostAttr>()))
+ // So do CUDA's host/device attributes.
+ if (S.getLangOpts().CUDA && (D->template hasAttr<CUDADeviceAttr>() ||
+ D->template hasAttr<CUDAHostAttr>()))
return false;
}
return D->isExternC();
@@ -5616,7 +5767,7 @@ static bool isIncompleteDeclExternC(Sema &S, const T *D) {
static bool shouldConsiderLinkage(const VarDecl *VD) {
const DeclContext *DC = VD->getDeclContext()->getRedeclContext();
- if (DC->isFunctionOrMethod())
+ if (DC->isFunctionOrMethod() || isa<OMPDeclareReductionDecl>(DC))
return VD->hasExternalStorage();
if (DC->isFileContext())
return true;
@@ -5627,7 +5778,8 @@ static bool shouldConsiderLinkage(const VarDecl *VD) {
static bool shouldConsiderLinkage(const FunctionDecl *FD) {
const DeclContext *DC = FD->getDeclContext()->getRedeclContext();
- if (DC->isFileContext() || DC->isFunctionOrMethod())
+ if (DC->isFileContext() || DC->isFunctionOrMethod() ||
+ isa<OMPDeclareReductionDecl>(DC))
return true;
if (DC->isRecord())
return false;
@@ -5701,6 +5853,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
QualType R = TInfo->getType();
DeclarationName Name = GetNameForDeclarator(D).getName();
+ // OpenCL v2.0 s6.9.b - Image type can only be used as a function argument.
+ // OpenCL v2.0 s6.13.16.1 - Pipe type can only be used as a function
+ // argument.
+ if (getLangOpts().OpenCL && (R->isImageType() || R->isPipeType())) {
+ Diag(D.getIdentifierLoc(),
+ diag::err_opencl_type_can_only_be_used_as_function_parameter)
+ << R;
+ D.setInvalidType();
+ return nullptr;
+ }
+
DeclSpec::SCS SCSpec = D.getDeclSpec().getStorageClassSpec();
StorageClass SC = StorageClassSpecToVarDeclStorageClass(D.getDeclSpec());
@@ -5847,7 +6010,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
case SC_PrivateExtern:
llvm_unreachable("C storage class in c++!");
}
- }
+ }
if (SC == SC_Static && CurContext->isRecord()) {
if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(DC)) {
@@ -5964,11 +6127,18 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewVD->setTemplateParameterListsInfo(
Context, TemplateParamLists.drop_back(VDTemplateParamLists));
- if (D.getDeclSpec().isConstexprSpecified())
+ if (D.getDeclSpec().isConstexprSpecified()) {
NewVD->setConstexpr(true);
+ // C++1z [dcl.spec.constexpr]p1:
+ // A static data member declared with the constexpr specifier is
+ // implicitly an inline variable.
+ if (NewVD->isStaticDataMember() && getLangOpts().CPlusPlus1z)
+ NewVD->setImplicitlyInline();
+ }
if (D.getDeclSpec().isConceptSpecified()) {
- NewVD->setConcept(true);
+ if (VarTemplateDecl *VTD = NewVD->getDescribedVarTemplate())
+ VTD->setConcept();
// C++ Concepts TS [dcl.spec.concept]p2: A concept definition shall not
// be declared with the thread_local, inline, friend, or constexpr
@@ -5986,6 +6156,41 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< 0 << 3;
NewVD->setInvalidDecl(true);
}
+
+ // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
+ // applied only to the definition of a function template or variable
+ // template, declared in namespace scope.
+ if (IsVariableTemplateSpecialization) {
+ Diag(D.getDeclSpec().getConceptSpecLoc(),
+ diag::err_concept_specified_specialization)
+ << (IsPartialSpecialization ? 2 : 1);
+ }
+
+ // C++ Concepts TS [dcl.spec.concept]p6: A variable concept has the
+ // following restrictions:
+ // - The declared type shall have the type bool.
+ if (!Context.hasSameType(NewVD->getType(), Context.BoolTy) &&
+ !NewVD->isInvalidDecl()) {
+ Diag(D.getIdentifierLoc(), diag::err_variable_concept_bool_decl);
+ NewVD->setInvalidDecl(true);
+ }
+ }
+ }
+
+ if (D.getDeclSpec().isInlineSpecified()) {
+ if (!getLangOpts().CPlusPlus) {
+ Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
+ << 0;
+ } else if (CurContext->isFunctionOrMethod()) {
+ // 'inline' is not allowed on block scope variable declaration.
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
+ diag::err_inline_declaration_block_scope) << Name
+ << FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
+ } else {
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
+ getLangOpts().CPlusPlus1z ? diag::warn_cxx14_compat_inline_variable
+ : diag::ext_inline_variable);
+ NewVD->setInlineSpecified();
}
}
@@ -6209,6 +6414,25 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (!IsVariableTemplateSpecialization)
D.setRedeclaration(CheckVariableDeclaration(NewVD, Previous));
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...]
+ // an explicit specialization (14.8.3) or a partial specialization of a
+ // concept definition.
+ if (IsVariableTemplateSpecialization &&
+ !D.getDeclSpec().isConceptSpecified() && !Previous.empty() &&
+ Previous.isSingleResult()) {
+ NamedDecl *PreviousDecl = Previous.getFoundDecl();
+ if (VarTemplateDecl *VarTmpl = dyn_cast<VarTemplateDecl>(PreviousDecl)) {
+ if (VarTmpl->isConcept()) {
+ Diag(NewVD->getLocation(), diag::err_concept_specialized)
+ << 1 /*variable*/
+ << (IsPartialSpecialization ? 2 /*partially specialized*/
+ : 1 /*explicitly specialized*/);
+ Diag(VarTmpl->getLocation(), diag::note_previous_declaration);
+ NewVD->setInvalidDecl();
+ }
+ }
+ }
+
if (NewTemplate) {
VarTemplateDecl *PrevVarTemplate =
NewVD->getPreviousDecl()
@@ -6274,7 +6498,7 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.isRedeclaration() && !Previous.empty()) {
checkDLLAttributeRedeclaration(
*this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewVD,
- IsExplicitSpecialization);
+ IsExplicitSpecialization, D.isFunctionDefinition());
}
if (NewTemplate) {
@@ -6287,6 +6511,17 @@ Sema::ActOnVariableDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return NewVD;
}
+/// Enum describing the %select options in diag::warn_decl_shadow.
+enum ShadowedDeclKind { SDK_Local, SDK_Global, SDK_StaticMember, SDK_Field };
+
+/// Determine what kind of declaration we're shadowing.
+static ShadowedDeclKind computeShadowedDeclKind(const NamedDecl *ShadowedDecl,
+ const DeclContext *OldDC) {
+ if (isa<RecordDecl>(OldDC))
+ return isa<FieldDecl>(ShadowedDecl) ? SDK_Field : SDK_StaticMember;
+ return OldDC->isFileContext() ? SDK_Global : SDK_Local;
+}
+
/// \brief Diagnose variable or built-in function shadowing. Implements
/// -Wshadow.
///
@@ -6315,12 +6550,23 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
if (!isa<VarDecl>(ShadowedDecl) && !isa<FieldDecl>(ShadowedDecl))
return;
- // Fields are not shadowed by variables in C++ static methods.
- if (isa<FieldDecl>(ShadowedDecl))
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(ShadowedDecl)) {
+ // Fields are not shadowed by variables in C++ static methods.
if (CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(NewDC))
if (MD->isStatic())
return;
+ // Fields shadowed by constructor parameters are a special case. Usually
+ // the constructor initializes the field with the parameter.
+ if (isa<CXXConstructorDecl>(NewDC) && isa<ParmVarDecl>(D)) {
+ // Remember that this was shadowed so we can either warn about its
+ // modification or its existence depending on warning settings.
+ D = D->getCanonicalDecl();
+ ShadowingDecls.insert({D, FD});
+ return;
+ }
+ }
+
if (VarDecl *shadowedVar = dyn_cast<VarDecl>(ShadowedDecl))
if (shadowedVar->isExternC()) {
// For shadowing external vars, make sure that we point to the global
@@ -6342,29 +6588,19 @@ void Sema::CheckShadow(Scope *S, VarDecl *D, const LookupResult& R) {
// TODO: should we warn about static data members shadowing
// static data members from base classes?
-
+
// TODO: don't diagnose for inaccessible shadowed members.
// This is hard to do perfectly because we might friend the
// shadowing context, but that's just a false negative.
}
- // Determine what kind of declaration we're shadowing.
- unsigned Kind;
- if (isa<RecordDecl>(OldDC)) {
- if (isa<FieldDecl>(ShadowedDecl))
- Kind = 3; // field
- else
- Kind = 2; // static data member
- } else if (OldDC->isFileContext())
- Kind = 1; // global
- else
- Kind = 0; // local
DeclarationName Name = R.getLookupName();
// Emit warning and note.
if (getSourceManager().isInSystemMacro(R.getNameLoc()))
return;
+ ShadowedDeclKind Kind = computeShadowedDeclKind(ShadowedDecl, OldDC);
Diag(R.getNameLoc(), diag::warn_decl_shadow) << Name << Kind << OldDC;
Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
}
@@ -6380,6 +6616,30 @@ void Sema::CheckShadow(Scope *S, VarDecl *D) {
CheckShadow(S, D, R);
}
+/// Check if 'E', which is an expression that is about to be modified, refers
+/// to a constructor parameter that shadows a field.
+void Sema::CheckShadowingDeclModification(Expr *E, SourceLocation Loc) {
+ // Quickly ignore expressions that can't be shadowing ctor parameters.
+ if (!getLangOpts().CPlusPlus || ShadowingDecls.empty())
+ return;
+ E = E->IgnoreParenImpCasts();
+ auto *DRE = dyn_cast<DeclRefExpr>(E);
+ if (!DRE)
+ return;
+ const NamedDecl *D = cast<NamedDecl>(DRE->getDecl()->getCanonicalDecl());
+ auto I = ShadowingDecls.find(D);
+ if (I == ShadowingDecls.end())
+ return;
+ const NamedDecl *ShadowedDecl = I->second;
+ const DeclContext *OldDC = ShadowedDecl->getDeclContext();
+ Diag(Loc, diag::warn_modifying_shadowing_decl) << D << OldDC;
+ Diag(D->getLocation(), diag::note_var_declared_here) << D;
+ Diag(ShadowedDecl->getLocation(), diag::note_previous_declaration);
+
+ // Avoid issuing multiple warnings about the same decl.
+ ShadowingDecls.erase(I);
+}
+
/// Check for conflict between this global or extern "C" declaration and
/// previous global or extern "C" declarations. This is only used in C++.
template<typename T>
@@ -6530,7 +6790,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
- // OpenCL v1.2 s6.8 -- The static qualifier is valid only in program
+ // OpenCL v1.2 s6.8 - The static qualifier is valid only in program
// scope.
if (getLangOpts().OpenCLVersion == 120 &&
!getOpenCLOptions().cl_clang_storage_class_specifiers &&
@@ -6540,40 +6800,64 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
return;
}
- // OpenCL v1.2 s6.5 - All program scope variables must be declared in the
- // __constant address space.
- // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
- // variables inside a function can also be declared in the global
- // address space.
if (getLangOpts().OpenCL) {
- if (NewVD->isFileVarDecl()) {
+ // OpenCL v2.0 s6.12.5 - The __block storage type is not supported.
+ if (NewVD->hasAttr<BlocksAttr>()) {
+ Diag(NewVD->getLocation(), diag::err_opencl_block_storage_type);
+ return;
+ }
+
+ if (T->isBlockPointerType()) {
+ // OpenCL v2.0 s6.12.5 - Any block declaration must be const qualified and
+ // can't use 'extern' storage class.
+ if (!T.isConstQualified()) {
+ Diag(NewVD->getLocation(), diag::err_opencl_invalid_block_declaration)
+ << 0 /*const*/;
+ NewVD->setInvalidDecl();
+ return;
+ }
+ if (NewVD->hasExternalStorage()) {
+ Diag(NewVD->getLocation(), diag::err_opencl_extern_block_declaration);
+ NewVD->setInvalidDecl();
+ return;
+ }
+ // OpenCL v2.0 s6.12.5 - Blocks with variadic arguments are not supported.
+ // TODO: this check is not enough as it doesn't diagnose the typedef
+ const BlockPointerType *BlkTy = T->getAs<BlockPointerType>();
+ const FunctionProtoType *FTy =
+ BlkTy->getPointeeType()->getAs<FunctionProtoType>();
+ if (FTy && FTy->isVariadic()) {
+ Diag(NewVD->getLocation(), diag::err_opencl_block_proto_variadic)
+ << T << NewVD->getSourceRange();
+ NewVD->setInvalidDecl();
+ return;
+ }
+ }
+ // OpenCL v1.2 s6.5 - All program scope variables must be declared in the
+ // __constant address space.
+ // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
+ // variables inside a function can also be declared in the global
+ // address space.
+ if (NewVD->isFileVarDecl() || NewVD->isStaticLocal() ||
+ NewVD->hasExternalStorage()) {
if (!T->isSamplerT() &&
!(T.getAddressSpace() == LangAS::opencl_constant ||
(T.getAddressSpace() == LangAS::opencl_global &&
getLangOpts().OpenCLVersion == 200))) {
+ int Scope = NewVD->isStaticLocal() | NewVD->hasExternalStorage() << 1;
if (getLangOpts().OpenCLVersion == 200)
Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space)
- << "global or constant";
+ << Scope << "global or constant";
else
Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space)
- << "constant";
+ << Scope << "constant";
NewVD->setInvalidDecl();
return;
}
} else {
- // OpenCL v2.0 s6.5.1 - Variables defined at program scope and static
- // variables inside a function can also be declared in the global
- // address space.
- if (NewVD->isStaticLocal() &&
- !(T.getAddressSpace() == LangAS::opencl_constant ||
- (T.getAddressSpace() == LangAS::opencl_global &&
- getLangOpts().OpenCLVersion == 200))) {
- if (getLangOpts().OpenCLVersion == 200)
- Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space)
- << "global or constant";
- else
- Diag(NewVD->getLocation(), diag::err_opencl_global_invalid_addr_space)
- << "constant";
+ if (T.getAddressSpace() == LangAS::opencl_global) {
+ Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
+ << 1 /*is any function*/ << "global";
NewVD->setInvalidDecl();
return;
}
@@ -6584,11 +6868,11 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
FunctionDecl *FD = getCurFunctionDecl();
if (FD && !FD->hasAttr<OpenCLKernelAttr>()) {
if (T.getAddressSpace() == LangAS::opencl_constant)
- Diag(NewVD->getLocation(), diag::err_opencl_non_kernel_variable)
- << "constant";
+ Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
+ << 0 /*non-kernel only*/ << "constant";
else
- Diag(NewVD->getLocation(), diag::err_opencl_non_kernel_variable)
- << "local";
+ Diag(NewVD->getLocation(), diag::err_opencl_function_variable)
+ << 0 /*non-kernel only*/ << "local";
NewVD->setInvalidDecl();
return;
}
@@ -6605,7 +6889,7 @@ void Sema::CheckVariableDeclarationType(VarDecl *NewVD) {
Diag(NewVD->getLocation(), diag::warn_attribute_weak_on_local);
}
}
-
+
bool isVM = T->isVariablyModifiedType();
if (isVM || NewVD->hasAttr<CleanupAttr>() ||
NewVD->hasAttr<BlocksAttr>())
@@ -6821,7 +7105,7 @@ namespace {
MultiTemplateParamsArg TemplateParamLists;
bool AddToScope;
};
-}
+} // end anonymous namespace
namespace {
@@ -6865,7 +7149,7 @@ class DifferentNameValidatorCCC : public CorrectionCandidateCallback {
CXXRecordDecl *ExpectedParent;
};
-}
+} // end anonymous namespace
/// \brief Generate diagnostics for an invalid function redeclaration.
///
@@ -7072,9 +7356,9 @@ static FunctionDecl* CreateNewFunctionDecl(Sema &SemaRef, Declarator &D,
(D.isFunctionDeclarator() && D.getFunctionTypeInfo().hasPrototype) ||
(!isa<FunctionType>(R.getTypePtr()) && R->isFunctionProtoType());
- NewFD = FunctionDecl::Create(SemaRef.Context, DC,
- D.getLocStart(), NameInfo, R,
- TInfo, SC, isInline,
+ NewFD = FunctionDecl::Create(SemaRef.Context, DC,
+ D.getLocStart(), NameInfo, R,
+ TInfo, SC, isInline,
HasPrototype, false);
if (D.isInvalidType())
NewFD->setInvalidDecl();
@@ -7483,8 +7767,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(NewFD->getLocation(), diag::err_destructor_template);
NewFD->setInvalidDecl();
}
-
- // If we're adding a template to a dependent context, we may need to
+
+ // If we're adding a template to a dependent context, we may need to
// rebuilding some of the types used within the template parameter list,
// now that we know what the current instantiation is.
if (DC->isDependentContext()) {
@@ -7492,7 +7776,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (RebuildTemplateParamsInCurrentInstantiation(TemplateParams))
Invalid = true;
}
-
FunctionTemplate = FunctionTemplateDecl::Create(Context, DC,
NewFD->getLocation(),
@@ -7561,7 +7844,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::err_virtual_non_function);
} else if (!CurContext->isRecord()) {
// 'virtual' was specified outside of the class.
- Diag(D.getDeclSpec().getVirtualSpecLoc(),
+ Diag(D.getDeclSpec().getVirtualSpecLoc(),
diag::err_virtual_out_of_class)
<< FixItHint::CreateRemoval(D.getDeclSpec().getVirtualSpecLoc());
} else if (NewFD->getDescribedFunctionTemplate()) {
@@ -7599,12 +7882,12 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
// C++ [dcl.fct.spec]p3:
- // The inline specifier shall not appear on a block scope function
+ // The inline specifier shall not appear on a block scope function
// declaration.
if (isInline && !NewFD->isInvalidDecl()) {
if (CurContext->isFunctionOrMethod()) {
// 'inline' is not allowed on block scope function declaration.
- Diag(D.getDeclSpec().getInlineSpecLoc(),
+ Diag(D.getDeclSpec().getInlineSpecLoc(),
diag::err_inline_declaration_block_scope) << Name
<< FixItHint::CreateRemoval(D.getDeclSpec().getInlineSpecLoc());
}
@@ -7612,22 +7895,22 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++ [dcl.fct.spec]p6:
// The explicit specifier shall be used only in the declaration of a
- // constructor or conversion function within its class definition;
+ // constructor or conversion function within its class definition;
// see 12.3.1 and 12.3.2.
if (isExplicit && !NewFD->isInvalidDecl()) {
if (!CurContext->isRecord()) {
// 'explicit' was specified outside of the class.
- Diag(D.getDeclSpec().getExplicitSpecLoc(),
+ Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_out_of_class)
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
- } else if (!isa<CXXConstructorDecl>(NewFD) &&
+ } else if (!isa<CXXConstructorDecl>(NewFD) &&
!isa<CXXConversionDecl>(NewFD)) {
// 'explicit' was specified on a function that wasn't a constructor
// or conversion function.
Diag(D.getDeclSpec().getExplicitSpecLoc(),
diag::err_explicit_non_ctor_or_conv_function)
<< FixItHint::CreateRemoval(D.getDeclSpec().getExplicitSpecLoc());
- }
+ }
}
if (isConstexpr) {
@@ -7643,6 +7926,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
if (isConcept) {
+ // This is a function concept.
+ if (FunctionTemplateDecl *FTD = NewFD->getDescribedFunctionTemplate())
+ FTD->setConcept();
+
// C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
// applied only to the definition of a function template [...]
if (!D.isFunctionDefinition()) {
@@ -7668,6 +7955,14 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// C++ Concepts TS [dcl.spec.concept]p5: A function concept has the
// following restrictions:
+ // - The declared return type shall have the type bool.
+ if (!Context.hasSameType(FPT->getReturnType(), Context.BoolTy)) {
+ Diag(D.getIdentifierLoc(), diag::err_function_concept_bool_ret);
+ NewFD->setInvalidDecl();
+ }
+
+ // C++ Concepts TS [dcl.spec.concept]p5: A function concept has the
+ // following restrictions:
// - The declaration's parameter list shall be equivalent to an empty
// parameter list.
if (FPT->getNumParams() > 0 || FPT->isVariadic())
@@ -7701,6 +7996,16 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< 1 << 3;
NewFD->setInvalidDecl(true);
}
+
+ // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
+ // applied only to the definition of a function template or variable
+ // template, declared in namespace scope.
+ if (isFunctionTemplateSpecialization) {
+ Diag(D.getDeclSpec().getConceptSpecLoc(),
+ diag::err_concept_specified_specialization) << 1;
+ NewFD->setInvalidDecl(true);
+ return NewFD;
+ }
}
// If __module_private__ was specified, mark the function accordingly.
@@ -7734,11 +8039,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
case FDK_Declaration:
case FDK_Definition:
break;
-
+
case FDK_Defaulted:
NewFD->setDefaulted();
break;
-
+
case FDK_Deleted:
NewFD->setDeletedAsWritten();
break;
@@ -7747,7 +8052,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isa<CXXMethodDecl>(NewFD) && DC == CurContext &&
D.isFunctionDefinition()) {
// C++ [class.mfct]p2:
- // A member function may be defined (8.4) in its class definition, in
+ // A member function may be defined (8.4) in its class definition, in
// which case it is an inline member function (7.1.2)
NewFD->setImplicitlyInline();
}
@@ -7825,7 +8130,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
NewFD->setInvalidDecl();
}
}
-
} else if (const FunctionProtoType *FT = R->getAs<FunctionProtoType>()) {
// When we're declaring a function with a typedef, typeof, etc as in the
// following example, we'll need to synthesize (unnamed)
@@ -7890,6 +8194,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// Handle attributes.
ProcessDeclAttributes(S, NewFD, D);
+ if (getLangOpts().CUDA)
+ maybeAddCUDAHostDeviceAttrs(S, NewFD, Previous);
+
if (getLangOpts().OpenCL) {
// OpenCL v1.1 s6.5: Using an address space qualifier in a function return
// type declaration will generate a compilation error.
@@ -7952,7 +8259,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
diag::ext_operator_new_delete_declared_inline)
<< NewFD->getDeclName();
- // If the declarator is a template-id, translate the parser's template
+ // If the declarator is a template-id, translate the parser's template
// argument list into our AST format.
if (D.getName().getKind() == UnqualifiedId::IK_TemplateId) {
TemplateIdAnnotation *TemplateId = D.getName().TemplateId;
@@ -7962,9 +8269,9 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
TemplateId->NumArgs);
translateTemplateArguments(TemplateArgsPtr,
TemplateArgs);
-
+
HasExplicitTemplateArgs = true;
-
+
if (NewFD->isInvalidDecl()) {
HasExplicitTemplateArgs = false;
} else if (FunctionTemplate) {
@@ -8000,7 +8307,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (isFunctionTemplateSpecialization && isFriend &&
(NewFD->getType()->isDependentType() || DC->isDependentContext() ||
TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ TemplateArgs,
InstantiationDependent))) {
assert(HasExplicitTemplateArgs &&
"friend function specialization without template args");
@@ -8008,10 +8315,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Previous))
NewFD->setInvalidDecl();
} else if (isFunctionTemplateSpecialization) {
- if (CurContext->isDependentContext() && CurContext->isRecord()
+ if (CurContext->isDependentContext() && CurContext->isRecord()
&& !isFriend) {
isDependentClassScopeExplicitSpecialization = true;
- Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ?
+ Diag(NewFD->getLocation(), getLangOpts().MicrosoftExt ?
diag::ext_function_specialization_in_class :
diag::err_function_specialization_in_class)
<< NewFD->getDeclName();
@@ -8020,7 +8327,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
: nullptr),
Previous))
NewFD->setInvalidDecl();
-
+
// C++ [dcl.stc]p1:
// A storage-class-specifier shall not be specified in an explicit
// specialization (14.7.3)
@@ -8033,14 +8340,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
<< SC
<< FixItHint::CreateRemoval(
D.getDeclSpec().getStorageClassSpecLoc());
-
+
else
- Diag(NewFD->getLocation(),
+ Diag(NewFD->getLocation(),
diag::ext_explicit_specialization_storage_class)
<< FixItHint::CreateRemoval(
D.getDeclSpec().getStorageClassSpecLoc());
}
-
} else if (isExplicitSpecialization && isa<CXXMethodDecl>(NewFD)) {
if (CheckMemberSpecialization(NewFD, Previous))
NewFD->setInvalidDecl();
@@ -8086,7 +8392,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// If we have a function template, check the template parameter
// list. This will check and merge default template arguments.
if (FunctionTemplate) {
- FunctionTemplateDecl *PrevTemplate =
+ FunctionTemplateDecl *PrevTemplate =
FunctionTemplate->getPreviousDecl();
CheckTemplateParameterList(FunctionTemplate->getTemplateParameters(),
PrevTemplate ? PrevTemplate->getTemplateParameters()
@@ -8095,8 +8401,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
? (D.isFunctionDefinition()
? TPC_FriendFunctionTemplateDefinition
: TPC_FriendFunctionTemplate)
- : (D.getCXXScopeSpec().isSet() &&
- DC && DC->isRecord() &&
+ : (D.getCXXScopeSpec().isSet() &&
+ DC && DC->isRecord() &&
DC->isDependentContext())
? TPC_ClassTemplateMember
: TPC_FunctionTemplate);
@@ -8159,7 +8465,6 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
return Result;
}
}
-
} else if (!D.isFunctionDefinition() &&
isa<CXXMethodDecl>(NewFD) && NewFD->isOutOfLine() &&
!isFriend && !isFunctionTemplateSpecialization &&
@@ -8168,8 +8473,8 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
// definition (C++ [class.mfct]p2).
// Note that this is not the case for explicit specializations of
// function templates or member functions of class templates, per
- // C++ [temp.expl.spec]p2. We also allow these declarations as an
- // extension for compatibility with old SWIG code which likes to
+ // C++ [temp.expl.spec]p2. We also allow these declarations as an
+ // extension for compatibility with old SWIG code which likes to
// generate them.
Diag(NewFD->getLocation(), diag::ext_out_of_line_declaration)
<< D.getCXXScopeSpec().getRange();
@@ -8181,7 +8486,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
AddKnownFunctionAttributes(NewFD);
- if (NewFD->hasAttr<OverloadableAttr>() &&
+ if (NewFD->hasAttr<OverloadableAttr>() &&
!NewFD->getType()->getAs<FunctionProtoType>()) {
Diag(NewFD->getLocation(),
diag::err_attribute_overloadable_no_prototype)
@@ -8224,7 +8529,30 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
if (D.isRedeclaration() && !Previous.empty()) {
checkDLLAttributeRedeclaration(
*this, dyn_cast<NamedDecl>(Previous.getRepresentativeDecl()), NewFD,
- isExplicitSpecialization || isFunctionTemplateSpecialization);
+ isExplicitSpecialization || isFunctionTemplateSpecialization,
+ D.isFunctionDefinition());
+ }
+
+ if (getLangOpts().CUDA) {
+ IdentifierInfo *II = NewFD->getIdentifier();
+ if (II && II->isStr("cudaConfigureCall") && !NewFD->isInvalidDecl() &&
+ NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
+ if (!R->getAs<FunctionType>()->getReturnType()->isScalarType())
+ Diag(NewFD->getLocation(), diag::err_config_scalar_return);
+
+ Context.setcudaConfigureCallDecl(NewFD);
+ }
+
+ // Variadic functions, other than a *declaration* of printf, are not allowed
+ // in device-side CUDA code, unless someone passed
+ // -fcuda-allow-variadic-functions.
+ if (!getLangOpts().CUDAAllowVariadicFunctions && NewFD->isVariadic() &&
+ (NewFD->hasAttr<CUDADeviceAttr>() ||
+ NewFD->hasAttr<CUDAGlobalAttr>()) &&
+ !(II && II->isStr("printf") && NewFD->isExternC() &&
+ !D.isFunctionDefinition())) {
+ Diag(NewFD->getLocation(), diag::err_variadic_device_fn);
+ }
}
if (getLangOpts().CPlusPlus) {
@@ -8242,7 +8570,7 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
Diag(D.getIdentifierLoc(), diag::err_static_kernel);
D.setInvalidType();
}
-
+
// OpenCL v1.2, s6.9 -- Kernels can only have return type void.
if (!NewFD->getReturnType()->isVoidType()) {
SourceRange RTRange = NewFD->getReturnTypeSourceRange();
@@ -8253,12 +8581,10 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
}
llvm::SmallPtrSet<const Type *, 16> ValidTypes;
- for (auto Param : NewFD->params())
+ for (auto Param : NewFD->parameters())
checkIsValidOpenCLKernelParameter(*this, D, Param, ValidTypes);
}
- for (FunctionDecl::param_iterator PI = NewFD->param_begin(),
- PE = NewFD->param_end(); PI != PE; ++PI) {
- ParmVarDecl *Param = *PI;
+ for (const ParmVarDecl *Param : NewFD->parameters()) {
QualType PT = Param->getType();
// OpenCL 2.0 pipe restrictions forbids pipe packet types to be non-value
@@ -8276,25 +8602,13 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC,
MarkUnusedFileScopedDecl(NewFD);
- if (getLangOpts().CUDA)
- if (IdentifierInfo *II = NewFD->getIdentifier())
- if (!NewFD->isInvalidDecl() &&
- NewFD->getDeclContext()->getRedeclContext()->isTranslationUnit()) {
- if (II->isStr("cudaConfigureCall")) {
- if (!R->getAs<FunctionType>()->getReturnType()->isScalarType())
- Diag(NewFD->getLocation(), diag::err_config_scalar_return);
-
- Context.setcudaConfigureCallDecl(NewFD);
- }
- }
-
// Here we have an function template explicit specialization at class scope.
// The actually specialization will be postponed to template instatiation
// time via the ClassScopeFunctionSpecializationDecl node.
if (isDependentClassScopeExplicitSpecialization) {
ClassScopeFunctionSpecializationDecl *NewSpec =
ClassScopeFunctionSpecializationDecl::Create(
- Context, CurContext, SourceLocation(),
+ Context, CurContext, SourceLocation(),
cast<CXXMethodDecl>(NewFD),
HasExplicitTemplateArgs, TemplateArgs);
CurContext->addDecl(NewSpec);
@@ -8464,20 +8778,28 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
FunctionTemplateDecl *NewTemplateDecl
= NewFD->getDescribedFunctionTemplate();
assert(NewTemplateDecl && "Template/non-template mismatch");
- if (CXXMethodDecl *Method
+ if (CXXMethodDecl *Method
= dyn_cast<CXXMethodDecl>(NewTemplateDecl->getTemplatedDecl())) {
Method->setAccess(OldTemplateDecl->getAccess());
NewTemplateDecl->setAccess(OldTemplateDecl->getAccess());
}
-
+
// If this is an explicit specialization of a member that is a function
// template, mark it as a member specialization.
- if (IsExplicitSpecialization &&
+ if (IsExplicitSpecialization &&
NewTemplateDecl->getInstantiatedFromMemberTemplate()) {
NewTemplateDecl->setMemberSpecialization();
assert(OldTemplateDecl->isMemberSpecialization());
+ // Explicit specializations of a member template do not inherit deleted
+ // status from the parent member template that they are specializing.
+ if (OldTemplateDecl->getTemplatedDecl()->isDeleted()) {
+ FunctionDecl *const OldTemplatedDecl =
+ OldTemplateDecl->getTemplatedDecl();
+ assert(OldTemplatedDecl->getCanonicalDecl() == OldTemplatedDecl);
+ OldTemplatedDecl->setDeletedAsWritten(false);
+ }
}
-
+
} else {
// This needs to happen first so that 'inline' propagates.
NewFD->setPreviousDeclaration(cast<FunctionDecl>(OldDecl));
@@ -8493,11 +8815,11 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// C++-specific checks.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(NewFD)) {
CheckConstructor(Constructor);
- } else if (CXXDestructorDecl *Destructor =
+ } else if (CXXDestructorDecl *Destructor =
dyn_cast<CXXDestructorDecl>(NewFD)) {
CXXRecordDecl *Record = Destructor->getParent();
QualType ClassType = Context.getTypeDeclType(Record);
-
+
// FIXME: Shouldn't we be able to perform this check even when the class
// type is dependent? Both gcc and edg can handle that.
if (!ClassType->isDependentType()) {
@@ -8517,7 +8839,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
// Find any virtual functions that this function overrides.
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(NewFD)) {
- if (!Method->isFunctionTemplateSpecialization() &&
+ if (!Method->isFunctionTemplateSpecialization() &&
!Method->getDescribedFunctionTemplate() &&
Method->isCanonicalDecl()) {
if (AddOverriddenMethods(Method->getParent(), Method)) {
@@ -8527,7 +8849,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
}
-
+
if (Method->isStatic())
checkThisInStaticMemberFunctionType(Method);
}
@@ -8553,7 +8875,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
CheckCXXDefaultArguments(NewFD);
// If this function declares a builtin function, check the type of this
- // declaration against the expected type for the builtin.
+ // declaration against the expected type for the builtin.
if (unsigned BuiltinID = NewFD->getBuiltinID()) {
ASTContext::GetBuiltinTypeError Error;
LookupPredefedObjCSuperType(*this, S, NewFD->getIdentifier());
@@ -8565,7 +8887,7 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
- // If this function is declared as being extern "C", then check to see if
+ // If this function is declared as being extern "C", then check to see if
// the function returns a UDT (class, struct, or union type) that is not C
// compatible, and if it does, warn the user.
// But, issue any diagnostic on the first declaration only.
@@ -8591,11 +8913,11 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
// static main is not an error under C99, but we should warn about it.
// We accept _Noreturn main as an extension.
if (FD->getStorageClass() == SC_Static)
- Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus
- ? diag::err_static_main : diag::warn_static_main)
+ Diag(DS.getStorageClassSpecLoc(), getLangOpts().CPlusPlus
+ ? diag::err_static_main : diag::warn_static_main)
<< FixItHint::CreateRemoval(DS.getStorageClassSpecLoc());
if (FD->isInlineSpecified())
- Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
+ Diag(DS.getInlineSpecLoc(), diag::err_inline_main)
<< FixItHint::CreateRemoval(DS.getInlineSpecLoc());
if (DS.isNoreturnSpecified()) {
SourceLocation NoreturnLoc = DS.getNoreturnSpecLoc();
@@ -8722,7 +9044,7 @@ void Sema::CheckMain(FunctionDecl* FD, const DeclSpec& DS) {
if (nparams == 1 && !FD->isInvalidDecl()) {
Diag(FD->getLocation(), diag::warn_main_one_arg);
}
-
+
if (!FD->isInvalidDecl() && FD->getDescribedFunctionTemplate()) {
Diag(FD->getLocation(), diag::err_mainlike_template_decl) << FD;
FD->setInvalidDecl();
@@ -8779,6 +9101,7 @@ namespace {
bool isInitList;
llvm::SmallVector<unsigned, 4> InitFieldIndex;
+
public:
typedef EvaluatedExprVisitor<SelfReferenceChecker> Inherited;
@@ -9000,7 +9323,7 @@ namespace {
Inherited::VisitUnaryOperator(E);
}
- void VisitObjCMessageExpr(ObjCMessageExpr *E) { return; }
+ void VisitObjCMessageExpr(ObjCMessageExpr *E) {}
void VisitCXXConstructExpr(CXXConstructExpr *E) {
if (E->getConstructor()->isCopyConstructor()) {
@@ -9096,7 +9419,7 @@ namespace {
SelfReferenceChecker(S, OrigDecl).CheckExpr(E);
}
-}
+} // end anonymous namespace
QualType Sema::deduceVarTypeFromInitializer(VarDecl *VDecl,
DeclarationName Name, QualType Type,
@@ -9294,7 +9617,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
VarDecl *Def;
if ((Def = VDecl->getDefinition()) && Def != VDecl) {
NamedDecl *Hidden = nullptr;
- if (!hasVisibleDefinition(Def, &Hidden) &&
+ if (!hasVisibleDefinition(Def, &Hidden) &&
(VDecl->getFormalLinkage() == InternalLinkage ||
VDecl->getDescribedVarTemplate() ||
VDecl->getNumTemplateParameterLists() ||
@@ -9330,7 +9653,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
diag::note_previous_initializer)
<< 0;
return;
- }
+ }
if (VDecl->hasLocalStorage())
getCurFunction()->setHasBranchProtectedScope();
@@ -9352,7 +9675,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// Get the decls type and save a reference for later, since
// CheckInitializerTypes may change it.
QualType DclT = VDecl->getType(), SavT = DclT;
-
+
// Expressions default to 'id' when we're in a debugger
// and we are assigning it to a variable of Objective-C pointer type.
if (getLangOpts().DebuggerCastResultToId && DclT->isObjCObjectPointerType() &&
@@ -9400,7 +9723,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
if (VDecl->isInvalidDecl())
return;
- InitializationSequence InitSeq(*this, Entity, Kind, Args);
+ InitializationSequence InitSeq(*this, Entity, Kind, Args,
+ /*TopLevelOfInitList=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
ExprResult Result = InitSeq.Perform(*this, Entity, Kind, Args, &DclT);
if (Result.isInvalid()) {
VDecl->setInvalidDecl();
@@ -9486,7 +9811,7 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
diag::ext_aggregate_init_not_constant)
<< Culprit->getSourceRange();
}
- } else if (VDecl->isStaticDataMember() &&
+ } else if (VDecl->isStaticDataMember() && !VDecl->isInline() &&
VDecl->getLexicalDeclContext()->isRecord()) {
// This is an in-class initialization for a static data member, e.g.,
//
@@ -9500,8 +9825,8 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init,
// const enumeration type, see 9.4.2.
//
// C++11 [class.static.data]p3:
- // If a non-volatile const static data member is of integral or
- // enumeration type, its declaration in the class definition can
+ // If a non-volatile non-inline const static data member is of integral
+ // or enumeration type, its declaration in the class definition can
// specify a brace-or-equal-initializer in which every initalizer-clause
// that is an assignment-expression is a constant expression. A static
// data member of literal type can be declared in the class definition
@@ -9641,7 +9966,7 @@ void Sema::ActOnInitializerError(Decl *D) {
if (Ty->isDependentType()) return;
// Require a complete type.
- if (RequireCompleteType(VD->getLocation(),
+ if (RequireCompleteType(VD->getLocation(),
Context.getBaseElementType(Ty),
diag::err_typecheck_decl_incomplete_type)) {
VD->setInvalidDecl();
@@ -9684,23 +10009,32 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// the definition of a variable [...] or the declaration of a static data
// member.
if (Var->isConstexpr() && !Var->isThisDeclarationADefinition()) {
- if (Var->isStaticDataMember())
- Diag(Var->getLocation(),
- diag::err_constexpr_static_mem_var_requires_init)
- << Var->getDeclName();
- else
+ if (Var->isStaticDataMember()) {
+ // C++1z removes the relevant rule; the in-class declaration is always
+ // a definition there.
+ if (!getLangOpts().CPlusPlus1z) {
+ Diag(Var->getLocation(),
+ diag::err_constexpr_static_mem_var_requires_init)
+ << Var->getDeclName();
+ Var->setInvalidDecl();
+ return;
+ }
+ } else {
Diag(Var->getLocation(), diag::err_invalid_constexpr_var_decl);
- Var->setInvalidDecl();
- return;
+ Var->setInvalidDecl();
+ return;
+ }
}
// C++ Concepts TS [dcl.spec.concept]p1: [...] A variable template
// definition having the concept specifier is called a variable concept. A
// concept definition refers to [...] a variable concept and its initializer.
- if (Var->isConcept()) {
- Diag(Var->getLocation(), diag::err_var_concept_not_initialized);
- Var->setInvalidDecl();
- return;
+ if (VarTemplateDecl *VTD = Var->getDescribedVarTemplate()) {
+ if (VTD->isConcept()) {
+ Diag(Var->getLocation(), diag::err_var_concept_not_initialized);
+ Var->setInvalidDecl();
+ return;
+ }
}
// OpenCL v1.1 s6.5.3: variables declared in the constant address space must
@@ -9720,17 +10054,17 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
// We have an out-of-line definition of a static data member
// that has an in-class initializer, so we type-check this like
- // a declaration.
+ // a declaration.
//
// Fall through
-
+
case VarDecl::DeclarationOnly:
- // It's only a declaration.
+ // It's only a declaration.
// Block scope. C99 6.7p7: If an identifier for an object is
// declared with no linkage (C99 6.2.2p6), the type for the
// object shall be complete.
- if (!Type->isDependentType() && Var->isLocalVarDecl() &&
+ if (!Type->isDependentType() && Var->isLocalVarDecl() &&
!Var->hasLinkage() && !Var->isInvalidDecl() &&
RequireCompleteType(Var->getLocation(), Type,
diag::err_typecheck_decl_incomplete_type))
@@ -9747,7 +10081,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
Diag(Var->getLocation(), diag::warn_private_extern);
Diag(Var->getLocation(), diag::note_private_extern);
}
-
+
return;
case VarDecl::TentativeDefinition:
@@ -9852,7 +10186,7 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
getCurFunction()->setHasBranchProtectedScope();
}
}
-
+
// C++03 [dcl.init]p9:
// If no initializer is specified for an object, and the
// object is of (possibly cv-qualified) non-POD class type (or
@@ -9886,6 +10220,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl,
}
void Sema::ActOnCXXForRangeDecl(Decl *D) {
+ // If there is no declaration, there was an error parsing it. Ignore it.
+ if (!D)
+ return;
+
VarDecl *VD = dyn_cast<VarDecl>(D);
if (!VD) {
Diag(D->getLocation(), diag::err_for_range_decl_must_be_var);
@@ -9957,6 +10295,18 @@ Sema::ActOnCXXForRangeIdentifier(Scope *S, SourceLocation IdentLoc,
void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (var->isInvalidDecl()) return;
+ if (getLangOpts().OpenCL) {
+ // OpenCL v2.0 s6.12.5 - Every block variable declaration must have an
+ // initialiser
+ if (var->getTypeSourceInfo()->getType()->isBlockPointerType() &&
+ !var->hasInit()) {
+ Diag(var->getLocation(), diag::err_opencl_invalid_block_declaration)
+ << 1 /*Init*/;
+ var->setInvalidDecl();
+ return;
+ }
+ }
+
// In Objective-C, don't allow jumps past the implicit initialization of a
// local retaining variable.
if (getLangOpts().ObjC1 &&
@@ -10014,7 +10364,6 @@ void Sema::CheckCompleteVariableDeclaration(VarDecl *var) {
if (getLangOpts().CPlusPlus11)
Diag(var->getLocation(), diag::note_use_thread_local);
}
-
}
// Apply section attributes and pragmas to global variables.
@@ -10165,15 +10514,63 @@ Sema::FinalizeDeclaration(Decl *ThisDecl) {
}
}
- // Static locals inherit dll attributes from their function.
if (VD->isStaticLocal()) {
if (FunctionDecl *FD =
dyn_cast_or_null<FunctionDecl>(VD->getParentFunctionOrMethod())) {
+ // Static locals inherit dll attributes from their function.
if (Attr *A = getDLLAttr(FD)) {
auto *NewAttr = cast<InheritableAttr>(A->clone(getASTContext()));
NewAttr->setInherited(true);
VD->addAttr(NewAttr);
}
+ // CUDA E.2.9.4: Within the body of a __device__ or __global__
+ // function, only __shared__ variables may be declared with
+ // static storage class.
+ if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice &&
+ (FD->hasAttr<CUDADeviceAttr>() || FD->hasAttr<CUDAGlobalAttr>()) &&
+ !VD->hasAttr<CUDASharedAttr>()) {
+ Diag(VD->getLocation(), diag::err_device_static_local_var);
+ VD->setInvalidDecl();
+ }
+ }
+ }
+
+ // Perform check for initializers of device-side global variables.
+ // CUDA allows empty constructors as initializers (see E.2.3.1, CUDA
+ // 7.5). We must also apply the same checks to all __shared__
+ // variables whether they are local or not. CUDA also allows
+ // constant initializers for __constant__ and __device__ variables.
+ if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
+ const Expr *Init = VD->getInit();
+ if (Init && VD->hasGlobalStorage() &&
+ (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>() ||
+ VD->hasAttr<CUDASharedAttr>())) {
+ assert((!VD->isStaticLocal() || VD->hasAttr<CUDASharedAttr>()));
+ bool AllowedInit = false;
+ if (const CXXConstructExpr *CE = dyn_cast<CXXConstructExpr>(Init))
+ AllowedInit =
+ isEmptyCudaConstructor(VD->getLocation(), CE->getConstructor());
+ // We'll allow constant initializers even if it's a non-empty
+ // constructor according to CUDA rules. This deviates from NVCC,
+ // but allows us to handle things like constexpr constructors.
+ if (!AllowedInit &&
+ (VD->hasAttr<CUDADeviceAttr>() || VD->hasAttr<CUDAConstantAttr>()))
+ AllowedInit = VD->getInit()->isConstantInitializer(
+ Context, VD->getType()->isReferenceType());
+
+ // Also make sure that destructor, if there is one, is empty.
+ if (AllowedInit)
+ if (CXXRecordDecl *RD = VD->getType()->getAsCXXRecordDecl())
+ AllowedInit =
+ isEmptyCudaDestructor(VD->getLocation(), RD->getDestructor());
+
+ if (!AllowedInit) {
+ Diag(VD->getLocation(), VD->hasAttr<CUDASharedAttr>()
+ ? diag::err_shared_var_init
+ : diag::err_dynamic_var_init)
+ << Init->getSourceRange();
+ VD->setInvalidDecl();
+ }
}
}
@@ -10416,6 +10813,9 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
if (DeclSpec::TSCS TSCS = DS.getThreadStorageClassSpec())
Diag(DS.getThreadStorageClassSpecLoc(), diag::err_invalid_thread)
<< DeclSpec::getSpecifierName(TSCS);
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (DS.isConstexprSpecified())
Diag(DS.getConstexprSpecLoc(), diag::err_invalid_constexpr)
<< 0;
@@ -10431,7 +10831,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
// Check that there are no default arguments inside the type of this
// parameter.
CheckExtraCXXDefaultArguments(D);
-
+
// Parameter declarators cannot be qualified (C++ [dcl.meaning]p1).
if (D.getCXXScopeSpec().isSet()) {
Diag(D.getIdentifierLoc(), diag::err_qualified_param_declarator)
@@ -10491,7 +10891,7 @@ Decl *Sema::ActOnParamDeclarator(Scope *S, Declarator &D) {
assert(S->getFunctionPrototypeDepth() >= 1);
New->setScopeInfo(S->getFunctionPrototypeDepth() - 1,
S->getNextFunctionPrototypeIndex());
-
+
// Add the parameter declaration into this scope.
S->AddDecl(New);
if (II)
@@ -10526,26 +10926,23 @@ ParmVarDecl *Sema::BuildParmVarDeclForTypedef(DeclContext *DC,
return Param;
}
-void Sema::DiagnoseUnusedParameters(ParmVarDecl * const *Param,
- ParmVarDecl * const *ParamEnd) {
+void Sema::DiagnoseUnusedParameters(ArrayRef<ParmVarDecl *> Parameters) {
// Don't diagnose unused-parameter errors in template instantiations; we
// will already have done so in the template itself.
if (!ActiveTemplateInstantiations.empty())
return;
- for (; Param != ParamEnd; ++Param) {
- if (!(*Param)->isReferenced() && (*Param)->getDeclName() &&
- !(*Param)->hasAttr<UnusedAttr>()) {
- Diag((*Param)->getLocation(), diag::warn_unused_parameter)
- << (*Param)->getDeclName();
+ for (const ParmVarDecl *Parameter : Parameters) {
+ if (!Parameter->isReferenced() && Parameter->getDeclName() &&
+ !Parameter->hasAttr<UnusedAttr>()) {
+ Diag(Parameter->getLocation(), diag::warn_unused_parameter)
+ << Parameter->getDeclName();
}
}
}
-void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
- ParmVarDecl * const *ParamEnd,
- QualType ReturnTy,
- NamedDecl *D) {
+void Sema::DiagnoseSizeOfParametersAndReturnValue(
+ ArrayRef<ParmVarDecl *> Parameters, QualType ReturnTy, NamedDecl *D) {
if (LangOpts.NumLargeByValueCopy == 0) // No check.
return;
@@ -10560,14 +10957,14 @@ void Sema::DiagnoseSizeOfParametersAndReturnValue(ParmVarDecl * const *Param,
// Warn if any parameter is pass-by-value and larger than the specified
// threshold.
- for (; Param != ParamEnd; ++Param) {
- QualType T = (*Param)->getType();
+ for (const ParmVarDecl *Parameter : Parameters) {
+ QualType T = Parameter->getType();
if (T->isDependentType() || !T.isPODType(Context))
continue;
unsigned Size = Context.getTypeSizeInChars(T).getQuantity();
if (Size > LangOpts.NumLargeByValueCopy)
- Diag((*Param)->getLocation(), diag::warn_parameter_size)
- << (*Param)->getDeclName() << Size;
+ Diag(Parameter->getLocation(), diag::warn_parameter_size)
+ << Parameter->getDeclName() << Size;
}
}
@@ -10599,7 +10996,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
}
ParmVarDecl *New = ParmVarDecl::Create(Context, DC, StartLoc, NameLoc, Name,
- Context.getAdjustedParameterType(T),
+ Context.getAdjustedParameterType(T),
TSInfo, SC, nullptr);
// Parameters can not be abstract class types.
@@ -10613,7 +11010,8 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
// Parameter declarators cannot be interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
- SourceLocation TypeEndLoc = TSInfo->getTypeLoc().getLocEnd();
+ SourceLocation TypeEndLoc =
+ getLocForEndOfToken(TSInfo->getTypeLoc().getLocEnd());
Diag(NameLoc,
diag::err_object_cannot_be_passed_returned_by_value) << 1 << T
<< FixItHint::CreateInsertion(TypeEndLoc, "*");
@@ -10621,7 +11019,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
New->setType(T);
}
- // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
+ // ISO/IEC TR 18037 S6.7.3: "The type of an object with automatic storage
// duration shall not be qualified by an address-space qualifier."
// Since all parameters have automatic store duration, they can not have
// an address space.
@@ -10632,7 +11030,7 @@ ParmVarDecl *Sema::CheckParameter(DeclContext *DC, SourceLocation StartLoc,
Diag(NameLoc, diag::err_arg_with_address_space);
New->setInvalidDecl();
}
- }
+ }
return New;
}
@@ -10686,11 +11084,11 @@ Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Declarator &D,
return ActOnStartOfFunctionDef(FnBodyScope, DP, SkipBody);
}
-void Sema::ActOnFinishInlineMethodDef(CXXMethodDecl *D) {
- Consumer.HandleInlineMethodDefinition(D);
+void Sema::ActOnFinishInlineFunctionDef(FunctionDecl *D) {
+ Consumer.HandleInlineFunctionDefinition(D);
}
-static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
+static bool ShouldWarnAboutMissingPrototype(const FunctionDecl *FD,
const FunctionDecl*& PossibleZeroParamPrototype) {
// Don't warn about invalid declarations.
if (FD->isInvalidDecl())
@@ -10786,11 +11184,10 @@ Sema::CheckForFunctionRedefinition(FunctionDecl *FD,
FD->setInvalidDecl();
}
-
-static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
+static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
Sema &S) {
CXXRecordDecl *const LambdaClass = CallOperator->getParent();
-
+
LambdaScopeInfo *LSI = S.PushLambdaScope();
LSI->CallOperator = CallOperator;
LSI->Lambda = LambdaClass;
@@ -10804,12 +11201,12 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
else if (LCD == LCD_ByRef)
LSI->ImpCaptureStyle = CapturingScopeInfo::ImpCap_LambdaByref;
DeclarationNameInfo DNI = CallOperator->getNameInfo();
-
- LSI->IntroducerRange = DNI.getCXXOperatorNameRange();
+
+ LSI->IntroducerRange = DNI.getCXXOperatorNameRange();
LSI->Mutable = !CallOperator->isConst();
// Add the captures to the LSI so they can be noted as already
- // captured within tryCaptureVar.
+ // captured within tryCaptureVar.
auto I = LambdaClass->field_begin();
for (const auto &C : LambdaClass->captures()) {
if (C.capturesVariable()) {
@@ -10818,15 +11215,16 @@ static void RebuildLambdaScopeInfo(CXXMethodDecl *CallOperator,
S.CurrentInstantiationScope->InstantiatedLocal(VD, VD);
QualType CaptureType = VD->getType();
const bool ByRef = C.getCaptureKind() == LCK_ByRef;
- LSI->addCapture(VD, /*IsBlock*/false, ByRef,
+ LSI->addCapture(VD, /*IsBlock*/false, ByRef,
/*RefersToEnclosingVariableOrCapture*/true, C.getLocation(),
- /*EllipsisLoc*/C.isPackExpansion()
+ /*EllipsisLoc*/C.isPackExpansion()
? C.getEllipsisLoc() : SourceLocation(),
CaptureType, /*Expr*/ nullptr);
} else if (C.capturesThis()) {
- LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
- S.getCurrentThisType(), /*Expr*/ nullptr);
+ LSI->addThisCapture(/*Nested*/ false, C.getLocation(),
+ /*Expr*/ nullptr,
+ C.getCaptureKind() == LCK_StarThis);
} else {
LSI->addVLATypeCapture(C.getLocation(), I->getType());
}
@@ -10838,7 +11236,7 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
SkipBodyInfo *SkipBody) {
// Clear the last template instantiation error context.
LastTemplateInstantiationErrorContext = ActiveTemplateInstantiation();
-
+
if (!D)
return D;
FunctionDecl *FD = nullptr;
@@ -10859,16 +11257,16 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
// If we are instantiating a generic lambda call operator, push
// a LambdaScopeInfo onto the function stack. But use the information
- // that's already been calculated (ActOnLambdaExpr) to prime the current
- // LambdaScopeInfo.
+ // that's already been calculated (ActOnLambdaExpr) to prime the current
+ // LambdaScopeInfo.
// When the template operator is being specialized, the LambdaScopeInfo,
// has to be properly restored so that tryCaptureVariable doesn't try
// and capture any new variables. In addition when calculating potential
- // captures during transformation of nested lambdas, it is necessary to
- // have the LSI properly restored.
+ // captures during transformation of nested lambdas, it is necessary to
+ // have the LSI properly restored.
if (isGenericLambdaCallOperatorSpecialization(FD)) {
assert(ActiveTemplateInstantiations.size() &&
- "There should be an active template instantiation on the stack "
+ "There should be an active template instantiation on the stack "
"when instantiating a generic lambda!");
RebuildLambdaScopeInfo(cast<CXXMethodDecl>(D), *this);
}
@@ -10898,11 +11296,11 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
PushDeclContext(FnBodyScope, FD);
// Check the validity of our function parameters
- CheckParmsForFunctionDef(FD->param_begin(), FD->param_end(),
+ CheckParmsForFunctionDef(FD->parameters(),
/*CheckParameterNames=*/true);
// Introduce our parameters into the function scope
- for (auto Param : FD->params()) {
+ for (auto Param : FD->parameters()) {
Param->setOwningFunction(FD);
// If this has an identifier, add it to the scope stack.
@@ -10965,15 +11363,15 @@ Decl *Sema::ActOnStartOfFunctionDef(Scope *FnBodyScope, Decl *D,
getCurLexicalContext()->getDeclKind() != Decl::ObjCCategoryImpl &&
getCurLexicalContext()->getDeclKind() != Decl::ObjCImplementation)
Diag(FD->getLocation(), diag::warn_function_def_in_objc_container);
-
+
return D;
}
/// \brief Given the set of return statements within a function body,
-/// compute the variables that are subject to the named return value
+/// compute the variables that are subject to the named return value
/// optimization.
///
-/// Each of the variables that is subject to the named return value
+/// Each of the variables that is subject to the named return value
/// optimization will be marked as NRVO variables in the AST, and any
/// return statement that has a marked NRVO variable as its NRVO candidate can
/// use the named return value optimization.
@@ -11033,7 +11431,7 @@ Decl *Sema::ActOnSkippedFunctionBody(Decl *Decl) {
FD->setHasSkippedBody();
else if (ObjCMethodDecl *MD = dyn_cast_or_null<ObjCMethodDecl>(Decl))
MD->setHasSkippedBody();
- return ActOnFinishFunctionBody(Decl, nullptr);
+ return Decl;
}
Decl *Sema::ActOnFinishFunctionBody(Decl *D, Stmt *BodyArg) {
@@ -11053,22 +11451,26 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (FD) {
FD->setBody(Body);
- if (getLangOpts().CPlusPlus14 && !FD->isInvalidDecl() && Body &&
- !FD->isDependentContext() && FD->getReturnType()->isUndeducedType()) {
- // If the function has a deduced result type but contains no 'return'
- // statements, the result type as written must be exactly 'auto', and
- // the deduced result type is 'void'.
- if (!FD->getReturnType()->getAs<AutoType>()) {
- Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
- << FD->getReturnType();
- FD->setInvalidDecl();
- } else {
- // Substitute 'void' for the 'auto' in the type.
- TypeLoc ResultType = getReturnTypeLoc(FD);
- Context.adjustDeducedFunctionResultType(
- FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
+ if (getLangOpts().CPlusPlus14) {
+ if (!FD->isInvalidDecl() && Body && !FD->isDependentContext() &&
+ FD->getReturnType()->isUndeducedType()) {
+ // If the function has a deduced result type but contains no 'return'
+ // statements, the result type as written must be exactly 'auto', and
+ // the deduced result type is 'void'.
+ if (!FD->getReturnType()->getAs<AutoType>()) {
+ Diag(dcl->getLocation(), diag::err_auto_fn_no_return_but_not_auto)
+ << FD->getReturnType();
+ FD->setInvalidDecl();
+ } else {
+ // Substitute 'void' for the 'auto' in the type.
+ TypeLoc ResultType = getReturnTypeLoc(FD);
+ Context.adjustDeducedFunctionResultType(
+ FD, SubstAutoType(ResultType.getType(), Context.VoidTy));
+ }
}
} else if (getLangOpts().CPlusPlus11 && isLambdaCallOperator(FD)) {
+ // In C++11, we don't use 'auto' deduction rules for lambda call
+ // operators because we don't support return type deduction.
auto *LSI = getCurLambda();
if (LSI->HasImplicitReturnType) {
deduceClosureReturnType(*LSI);
@@ -11112,8 +11514,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
if (!FD->isInvalidDecl()) {
// Don't diagnose unused parameters of defaulted or deleted functions.
if (!FD->isDeleted() && !FD->isDefaulted())
- DiagnoseUnusedParameters(FD->param_begin(), FD->param_end());
- DiagnoseSizeOfParametersAndReturnValue(FD->param_begin(), FD->param_end(),
+ DiagnoseUnusedParameters(FD->parameters());
+ DiagnoseSizeOfParametersAndReturnValue(FD->parameters(),
FD->getReturnType(), FD);
// If this is a structor, we need a vtable.
@@ -11121,7 +11523,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
MarkVTableUsed(FD->getLocation(), Constructor->getParent());
else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(FD))
MarkVTableUsed(FD->getLocation(), Destructor->getParent());
-
+
// Try to apply the named return value optimization. We have to check
// if we can do this here because lambdas keep return statements around
// to deduce an implicit return type.
@@ -11184,8 +11586,8 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
assert(MD == getCurMethodDecl() && "Method parsing confused");
MD->setBody(Body);
if (!MD->isInvalidDecl()) {
- DiagnoseUnusedParameters(MD->param_begin(), MD->param_end());
- DiagnoseSizeOfParametersAndReturnValue(MD->param_begin(), MD->param_end(),
+ DiagnoseUnusedParameters(MD->parameters());
+ DiagnoseSizeOfParametersAndReturnValue(MD->parameters(),
MD->getReturnType(), MD);
if (Body)
@@ -11245,7 +11647,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
// Verify this.
if (FD && isa<CXXConstructorDecl>(FD) && isa<CXXTryStmt>(Body))
DiagnoseReturnInConstructorExceptionHandler(cast<CXXTryStmt>(Body));
-
+
// Verify that gotos and switch cases don't jump into scopes illegally.
if (getCurFunction()->NeedsScopeChecking() &&
!PP.isCodeCompletionEnabled())
@@ -11258,7 +11660,7 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
MarkBaseAndMemberDestructorsReferenced(Destructor->getLocation(),
Destructor->getParent());
}
-
+
// If any errors have occurred, clear out any temporaries that may have
// been leftover. This ensures that these temporaries won't be picked up for
// deletion in some later function.
@@ -11292,11 +11694,11 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
assert(ExprCleanupObjects.size() ==
ExprEvalContexts.back().NumCleanupObjects &&
"Leftover temporaries in function");
- assert(!ExprNeedsCleanups && "Unaccounted cleanups in function");
+ assert(!Cleanup.exprNeedsCleanups() && "Unaccounted cleanups in function");
assert(MaybeODRUseExprs.empty() &&
"Leftover expressions for odr-use checking");
}
-
+
if (!IsInstantiation)
PopDeclContext();
@@ -11311,7 +11713,6 @@ Decl *Sema::ActOnFinishFunctionBody(Decl *dcl, Stmt *Body,
return dcl;
}
-
/// When we finish delayed parsing of an attribute, we must attach it to the
/// relevant Decl.
void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
@@ -11319,14 +11720,13 @@ void Sema::ActOnFinishDelayedAttribute(Scope *S, Decl *D,
// Always attach attributes to the underlying decl.
if (TemplateDecl *TD = dyn_cast<TemplateDecl>(D))
D = TD->getTemplatedDecl();
- ProcessDeclAttributeList(S, D, Attrs.getList());
-
+ ProcessDeclAttributeList(S, D, Attrs.getList());
+
if (CXXMethodDecl *Method = dyn_cast_or_null<CXXMethodDecl>(D))
if (Method->isStatic())
checkThisInStaticMemberFunctionAttributes(Method);
}
-
/// ImplicitlyDefineFunction - An undeclared identifier was used in a function
/// call, forming a call to an implicitly defined function (per C99 6.5.1p2).
NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
@@ -11473,14 +11873,15 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
FD->getLocation()));
if (Context.BuiltinInfo.isNoThrow(BuiltinID) && !FD->hasAttr<NoThrowAttr>())
FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation()));
+ if (Context.BuiltinInfo.isPure(BuiltinID) && !FD->hasAttr<PureAttr>())
+ FD->addAttr(PureAttr::CreateImplicit(Context, FD->getLocation()));
if (Context.BuiltinInfo.isConst(BuiltinID) && !FD->hasAttr<ConstAttr>())
FD->addAttr(ConstAttr::CreateImplicit(Context, FD->getLocation()));
- if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads &&
- Context.BuiltinInfo.isTSBuiltin(BuiltinID) &&
+ if (getLangOpts().CUDA && Context.BuiltinInfo.isTSBuiltin(BuiltinID) &&
!FD->hasAttr<CUDADeviceAttr>() && !FD->hasAttr<CUDAHostAttr>()) {
- // Assign appropriate attribute depending on CUDA compilation
- // mode and the target builtin belongs to. E.g. during host
- // compilation, aux builtins are __device__, the rest are __host__.
+ // Add the appropriate attribute, depending on the CUDA compilation mode
+ // and which target the builtin belongs to. For example, during host
+ // compilation, aux builtins are __device__, while the rest are __host__.
if (getLangOpts().CUDAIsDevice !=
Context.BuiltinInfo.isAuxBuiltinID(BuiltinID))
FD->addAttr(CUDADeviceAttr::CreateImplicit(Context, FD->getLocation()));
@@ -11489,6 +11890,16 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
}
}
+ // If C++ exceptions are enabled but we are told extern "C" functions cannot
+ // throw, add an implicit nothrow attribute to any extern "C" function we come
+ // across.
+ if (getLangOpts().CXXExceptions && getLangOpts().ExternCNoUnwind &&
+ FD->isExternC() && !FD->hasAttr<NoThrowAttr>()) {
+ const auto *FPT = FD->getType()->getAs<FunctionProtoType>();
+ if (!FPT || FPT->getExceptionSpecType() == EST_None)
+ FD->addAttr(NoThrowAttr::CreateImplicit(Context, FD->getLocation()));
+ }
+
IdentifierInfo *Name = FD->getIdentifier();
if (!Name)
return;
@@ -11543,7 +11954,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
NewTD->setInvalidDecl();
return NewTD;
}
-
+
if (D.getDeclSpec().isModulePrivateSpecified()) {
if (CurContext->isFunctionOrMethod())
Diag(NewTD->getLocation(), diag::err_module_private_local)
@@ -11553,7 +11964,7 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
else
NewTD->setModulePrivate();
}
-
+
// C++ [dcl.typedef]p8:
// If the typedef declaration defines an unnamed class (or
// enum), the first typedef-name declared by the declaration
@@ -11578,7 +11989,6 @@ TypedefDecl *Sema::ParseTypedefDecl(Scope *S, Declarator &D, QualType T,
return NewTD;
}
-
/// \brief Check that this is a valid underlying type for an enum declaration.
bool Sema::CheckEnumUnderlyingType(TypeSourceInfo *TI) {
SourceLocation UnderlyingLoc = TI->getTypeLoc().getBeginLoc();
@@ -12006,7 +12416,7 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
}
// A tag 'foo::bar' must already exist.
- Diag(NameLoc, diag::err_not_tag_in_scope)
+ Diag(NameLoc, diag::err_not_tag_in_scope)
<< Kind << Name << DC << SS.getRange();
Name = nullptr;
Invalid = true;
@@ -12030,12 +12440,13 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// When declaring or defining a tag, ignore ambiguities introduced
// by types using'ed into this scope.
- if (Previous.isAmbiguous() &&
+ if (Previous.isAmbiguous() &&
(TUK == TUK_Definition || TUK == TUK_Declaration)) {
LookupResult::Filter F = Previous.makeFilter();
while (F.hasNext()) {
NamedDecl *ND = F.next();
- if (ND->getDeclContext()->getRedeclContext() != SearchDC)
+ if (!ND->getDeclContext()->getRedeclContext()->Equals(
+ SearchDC->getRedeclContext()))
F.erase();
}
F.done();
@@ -12106,10 +12517,10 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
DC->Equals(getStdNamespace()) && Name->isStr("bad_alloc")) {
// This is a declaration of or a reference to "std::bad_alloc".
isStdBadAlloc = true;
-
+
if (Previous.empty() && StdBadAlloc) {
// std::bad_alloc has been implicitly declared (but made invisible to
- // name lookup). Fill in this implicit declaration as the previous
+ // name lookup). Fill in this implicit declaration as the previous
// declaration, so that the declarations get chained appropriately.
Previous.addDecl(getStdBadAlloc());
}
@@ -12422,7 +12833,6 @@ Decl *Sema::ActOnTag(Scope *S, unsigned TagSpec, TagUseKind TUK,
// is non-NULL, it's a definition of the tag declared by
// PrevDecl. If it's NULL, we have a new definition.
-
// Otherwise, PrevDecl is not a tag, but was found with tag
// lookup. This is only actually possible in C++, where a few
// things like templates still live in the tag namespace.
@@ -12523,8 +12933,8 @@ CreateNewDecl:
else if (getLangOpts().CPlusPlus)
DiagID = diag::err_forward_ref_enum;
Diag(Loc, DiagID);
-
- // If this is a forward-declared reference to an enumeration, make a
+
+ // If this is a forward-declared reference to an enumeration, make a
// note of it; we won't actually be introducing the declaration into
// the declaration context.
if (TUK == TUK_Reference)
@@ -12540,7 +12950,6 @@ CreateNewDecl:
ED->setIntegerType(QualType(EnumUnderlying.get<const Type*>(), 0));
ED->setPromotionType(ED->getIntegerType());
}
-
} else {
// struct/union/class
@@ -12569,10 +12978,10 @@ CreateNewDecl:
// Maybe add qualifier info.
if (SS.isNotEmpty()) {
if (SS.isSet()) {
- // If this is either a declaration or a definition, check the
+ // If this is either a declaration or a definition, check the
// nested-name-specifier against the current context. We don't do this
// for explicit specializations, because they have similar checking
- // (with more specific diagnostics) in the call to
+ // (with more specific diagnostics) in the call to
// CheckMemberSpecialization, below.
if (!isExplicitSpecialization &&
(TUK == TUK_Definition || TUK == TUK_Declaration) &&
@@ -12681,7 +13090,6 @@ CreateNewDecl:
PushOnScopeChains(New, S, !IsForwardReference);
if (IsForwardReference)
SearchDC->makeDeclVisibleInContext(New);
-
} else {
CurContext->addDecl(New);
}
@@ -12709,7 +13117,7 @@ CreateNewDecl:
void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD);
-
+
// Enter the tag context.
PushDeclContext(S, Tag);
@@ -12721,7 +13129,7 @@ void Sema::ActOnTagStartDefinition(Scope *S, Decl *TagD) {
}
Decl *Sema::ActOnObjCContainerStartDefinition(Decl *IDecl) {
- assert(isa<ObjCContainerDecl>(IDecl) &&
+ assert(isa<ObjCContainerDecl>(IDecl) &&
"ActOnObjCContainerStartDefinition - Not ObjCContainerDecl");
DeclContext *OCD = cast<DeclContext>(IDecl);
assert(getContainingDC(OCD) == CurContext &&
@@ -12768,10 +13176,10 @@ void Sema::ActOnStartCXXMemberDeclarations(Scope *S, Decl *TagD,
}
void Sema::ActOnTagFinishDefinition(Scope *S, Decl *TagD,
- SourceLocation RBraceLoc) {
+ SourceRange BraceRange) {
AdjustDeclIfTemplate(TagD);
TagDecl *Tag = cast<TagDecl>(TagD);
- Tag->setRBraceLoc(RBraceLoc);
+ Tag->setBraceRange(BraceRange);
// Make sure we "complete" the definition even it is invalid.
if (Tag->isBeingDefined()) {
@@ -12826,7 +13234,7 @@ void Sema::ActOnTagDefinitionError(Scope *S, Decl *TagD) {
// ActOnStartCXXMemberDeclarations, so we don't have to mess with
// the FieldCollector.
- PopDeclContext();
+ PopDeclContext();
}
// Note that FieldName may be null for anonymous bitfields.
@@ -12961,15 +13369,19 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
D.setInvalidType();
}
- // OpenCL 1.2 spec, s6.9 r:
- // The event type cannot be used to declare a structure or union field.
- if (LangOpts.OpenCL && T->isEventT()) {
- Diag(Loc, diag::err_event_t_struct_field);
+ // OpenCL v1.2 s6.9b,r & OpenCL v2.0 s6.12.5 - The following types cannot be
+ // used as structure or union field: image, sampler, event or block types.
+ if (LangOpts.OpenCL && (T->isEventT() || T->isImageType() ||
+ T->isSamplerT() || T->isBlockPointerType())) {
+ Diag(Loc, diag::err_opencl_type_struct_or_union_field) << T;
D.setInvalidType();
}
DiagnoseFunctionSpecifiers(D.getDeclSpec());
+ if (D.getDeclSpec().isInlineSpecified())
+ Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
@@ -12984,11 +13396,11 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
case LookupResult::FoundUnresolvedValue:
PrevDecl = Previous.getAsSingle<NamedDecl>();
break;
-
+
case LookupResult::FoundOverloaded:
PrevDecl = Previous.getRepresentativeDecl();
break;
-
+
case LookupResult::NotFound:
case LookupResult::NotFoundInCurrentInstantiation:
case LookupResult::Ambiguous:
@@ -13018,7 +13430,7 @@ FieldDecl *Sema::HandleField(Scope *S, RecordDecl *Record,
if (D.getDeclSpec().isModulePrivateSpecified())
NewFD->setModulePrivate();
-
+
if (NewFD->isInvalidDecl() && PrevDecl) {
// Don't introduce NewFD into scope; there's already something
// with the same name in the same scope.
@@ -13250,9 +13662,9 @@ bool Sema::CheckNontrivialField(FieldDecl *FD) {
if (!getLangOpts().CPlusPlus11 &&
getLangOpts().ObjCAutoRefCount && RDecl->hasObjectMember()) {
// Objective-C++ ARC: it is an error to have a non-trivial field of
- // a union. However, system headers in Objective-C programs
+ // a union. However, system headers in Objective-C programs
// occasionally have Objective-C lifetime objects within unions,
- // and rather than cause the program to fail, we make those
+ // and rather than cause the program to fail, we make those
// members unavailable.
SourceLocation Loc = FD->getLocation();
if (getSourceManager().isInSystemHeader(Loc)) {
@@ -13348,7 +13760,7 @@ Decl *Sema::ActOnIvar(Scope *S,
else
EnclosingContext = EnclosingDecl;
} else {
- if (ObjCCategoryDecl *CDecl =
+ if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
if (LangOpts.ObjCRuntime.isFragile() || !CDecl->IsClassExtension()) {
Diag(Loc, diag::err_misplaced_ivar) << CDecl->IsClassExtension();
@@ -13386,33 +13798,33 @@ Decl *Sema::ActOnIvar(Scope *S,
if (D.getDeclSpec().isModulePrivateSpecified())
NewID->setModulePrivate();
-
+
if (II) {
// FIXME: When interfaces are DeclContexts, we'll need to add
// these to the interface.
S->AddDecl(NewID);
IdResolver.AddDecl(NewID);
}
-
+
if (LangOpts.ObjCRuntime.isNonFragile() &&
!NewID->isInvalidDecl() && isa<ObjCInterfaceDecl>(EnclosingDecl))
Diag(Loc, diag::warn_ivars_in_interface);
-
+
return NewID;
}
-/// ActOnLastBitfield - This routine handles synthesized bitfields rules for
-/// class and class extensions. For every class \@interface and class
-/// extension \@interface, if the last ivar is a bitfield of any type,
+/// ActOnLastBitfield - This routine handles synthesized bitfields rules for
+/// class and class extensions. For every class \@interface and class
+/// extension \@interface, if the last ivar is a bitfield of any type,
/// then add an implicit `char :0` ivar to the end of that interface.
void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
SmallVectorImpl<Decl *> &AllIvarDecls) {
if (LangOpts.ObjCRuntime.isFragile() || AllIvarDecls.empty())
return;
-
+
Decl *ivarDecl = AllIvarDecls[AllIvarDecls.size()-1];
ObjCIvarDecl *Ivar = cast<ObjCIvarDecl>(ivarDecl);
-
+
if (!Ivar->isBitField() || Ivar->getBitWidthValue(Context) == 0)
return;
ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CurContext);
@@ -13431,7 +13843,7 @@ void Sema::ActOnLastBitfield(SourceLocation DeclLoc,
Ivar = ObjCIvarDecl::Create(Context, cast<ObjCContainerDecl>(CurContext),
DeclLoc, DeclLoc, nullptr,
- Context.CharTy,
+ Context.CharTy,
Context.getTrivialTypeSourceInfo(Context.CharTy,
DeclLoc),
ObjCIvarDecl::Private, BW,
@@ -13460,7 +13872,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
break;
}
}
-
+
RecordDecl *Record = dyn_cast<RecordDecl>(EnclosingDecl);
// Start counting up the number of named members; make sure to include
@@ -13514,7 +13926,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
FD->setInvalidDecl();
EnclosingDecl->setInvalidDecl();
continue;
- } else if (FDTy->isIncompleteArrayType() && Record &&
+ } else if (FDTy->isIncompleteArrayType() && Record &&
((i + 1 == Fields.end() && !Record->isUnion()) ||
((getLangOpts().MicrosoftExt ||
getLangOpts().CPlusPlus) &&
@@ -13530,14 +13942,12 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
: getLangOpts().CPlusPlus
? diag::ext_flexible_array_union_gnu
: diag::err_flexible_array_union;
- else if (Fields.size() == 1)
+ else if (NumNamedMembers < 1)
DiagID = getLangOpts().MicrosoftExt
? diag::ext_flexible_array_empty_aggregate_ms
: getLangOpts().CPlusPlus
? diag::ext_flexible_array_empty_aggregate_gnu
- : NumNamedMembers < 1
- ? diag::err_flexible_array_empty_aggregate
- : 0;
+ : diag::err_flexible_array_empty_aggregate;
if (DiagID)
Diag(FD->getLocation(), DiagID) << FD->getDeclName()
@@ -13631,7 +14041,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
UnavailableAttr::IR_ARCFieldWithOwnership, loc));
}
} else {
- Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
+ Diag(FD->getLocation(), diag::err_arc_objc_object_in_tag)
<< T->isBlockPointerType() << Record->getTagKind();
}
ARCErrReported = true;
@@ -13644,7 +14054,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
Record->setHasObjectMember(true);
else if (Context.getAsArrayType(FD->getType())) {
QualType BaseType = Context.getBaseElementType(FD->getType());
- if (BaseType->isRecordType() &&
+ if (BaseType->isRecordType() &&
BaseType->getAs<RecordType>()->getDecl()->hasObjectMember())
Record->setHasObjectMember(true);
else if (BaseType->isObjCObjectPointerType() ||
@@ -13669,51 +14079,53 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
I = CXXRecord->conversion_begin(),
E = CXXRecord->conversion_end(); I != E; ++I)
I.setAccess((*I)->getAccess());
-
- if (!CXXRecord->isDependentType()) {
- if (CXXRecord->hasUserDeclaredDestructor()) {
- // Adjust user-defined destructor exception spec.
- if (getLangOpts().CPlusPlus11)
- AdjustDestructorExceptionSpec(CXXRecord,
- CXXRecord->getDestructor());
- }
+ }
+ if (!CXXRecord->isDependentType()) {
+ if (CXXRecord->hasUserDeclaredDestructor()) {
+ // Adjust user-defined destructor exception spec.
+ if (getLangOpts().CPlusPlus11)
+ AdjustDestructorExceptionSpec(CXXRecord,
+ CXXRecord->getDestructor());
+ }
+
+ if (!CXXRecord->isInvalidDecl()) {
// Add any implicitly-declared members to this class.
AddImplicitlyDeclaredMembersToClass(CXXRecord);
- // If we have virtual base classes, we may end up finding multiple
- // final overriders for a given virtual function. Check for this
+ // If we have virtual base classes, we may end up finding multiple
+ // final overriders for a given virtual function. Check for this
// problem now.
if (CXXRecord->getNumVBases()) {
CXXFinalOverriderMap FinalOverriders;
CXXRecord->getFinalOverriders(FinalOverriders);
-
- for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
+
+ for (CXXFinalOverriderMap::iterator M = FinalOverriders.begin(),
MEnd = FinalOverriders.end();
M != MEnd; ++M) {
- for (OverridingMethods::iterator SO = M->second.begin(),
+ for (OverridingMethods::iterator SO = M->second.begin(),
SOEnd = M->second.end();
SO != SOEnd; ++SO) {
- assert(SO->second.size() > 0 &&
+ assert(SO->second.size() > 0 &&
"Virtual function without overridding functions?");
if (SO->second.size() == 1)
continue;
-
+
// C++ [class.virtual]p2:
// In a derived class, if a virtual member function of a base
// class subobject has more than one final overrider the
// program is ill-formed.
Diag(Record->getLocation(), diag::err_multiple_final_overriders)
<< (const NamedDecl *)M->first << Record;
- Diag(M->first->getLocation(),
+ Diag(M->first->getLocation(),
diag::note_overridden_virtual_function);
- for (OverridingMethods::overriding_iterator
- OM = SO->second.begin(),
+ for (OverridingMethods::overriding_iterator
+ OM = SO->second.begin(),
OMEnd = SO->second.end();
OM != OMEnd; ++OM)
Diag(OM->Method->getLocation(), diag::note_final_overrider)
<< (const NamedDecl *)M->first << OM->Method->getParent();
-
+
Record->setInvalidDecl();
}
}
@@ -13723,7 +14135,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
}
}
}
-
+
if (!Completed)
Record->completeDefinition();
@@ -13812,7 +14224,7 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
CheckImplementationIvars(IMPDecl, ClsFields, RecFields.size(), RBrac);
IMPDecl->setIvarLBraceLoc(LBrac);
IMPDecl->setIvarRBraceLoc(RBrac);
- } else if (ObjCCategoryDecl *CDecl =
+ } else if (ObjCCategoryDecl *CDecl =
dyn_cast<ObjCCategoryDecl>(EnclosingDecl)) {
// case of ivars in class extension; all other cases have been
// reported as errors elsewhere.
@@ -13823,18 +14235,18 @@ void Sema::ActOnFields(Scope *S, SourceLocation RecLoc, Decl *EnclosingDecl,
ObjCInterfaceDecl *IDecl = CDecl->getClassInterface();
for (unsigned i = 0, e = RecFields.size(); i != e; ++i) {
if (IDecl) {
- if (const ObjCIvarDecl *ClsIvar =
+ if (const ObjCIvarDecl *ClsIvar =
IDecl->getIvarDecl(ClsFields[i]->getIdentifier())) {
- Diag(ClsFields[i]->getLocation(),
- diag::err_duplicate_ivar_declaration);
+ Diag(ClsFields[i]->getLocation(),
+ diag::err_duplicate_ivar_declaration);
Diag(ClsIvar->getLocation(), diag::note_previous_definition);
continue;
}
for (const auto *Ext : IDecl->known_extensions()) {
if (const ObjCIvarDecl *ClsExtIvar
= Ext->getIvarDecl(ClsFields[i]->getIdentifier())) {
- Diag(ClsFields[i]->getLocation(),
- diag::err_duplicate_ivar_declaration);
+ Diag(ClsFields[i]->getLocation(),
+ diag::err_duplicate_ivar_declaration);
Diag(ClsExtIvar->getLocation(), diag::note_previous_definition);
continue;
}
@@ -13859,37 +14271,37 @@ static bool isRepresentableIntegerValue(ASTContext &Context,
QualType T) {
assert(T->isIntegralType(Context) && "Integral type required!");
unsigned BitWidth = Context.getIntWidth(T);
-
+
if (Value.isUnsigned() || Value.isNonNegative()) {
- if (T->isSignedIntegerOrEnumerationType())
+ if (T->isSignedIntegerOrEnumerationType())
--BitWidth;
return Value.getActiveBits() <= BitWidth;
- }
+ }
return Value.getMinSignedBits() <= BitWidth;
}
// \brief Given an integral type, return the next larger integral type
// (or a NULL type of no such type exists).
static QualType getNextLargerIntegralType(ASTContext &Context, QualType T) {
- // FIXME: Int128/UInt128 support, which also needs to be introduced into
+ // FIXME: Int128/UInt128 support, which also needs to be introduced into
// enum checking below.
assert(T->isIntegralType(Context) && "Integral type required!");
const unsigned NumTypes = 4;
- QualType SignedIntegralTypes[NumTypes] = {
+ QualType SignedIntegralTypes[NumTypes] = {
Context.ShortTy, Context.IntTy, Context.LongTy, Context.LongLongTy
};
- QualType UnsignedIntegralTypes[NumTypes] = {
- Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy,
+ QualType UnsignedIntegralTypes[NumTypes] = {
+ Context.UnsignedShortTy, Context.UnsignedIntTy, Context.UnsignedLongTy,
Context.UnsignedLongLongTy
};
-
+
unsigned BitWidth = Context.getTypeSize(T);
QualType *Types = T->isSignedIntegerOrEnumerationType()? SignedIntegralTypes
: UnsignedIntegralTypes;
for (unsigned I = 0; I != NumTypes; ++I)
if (Context.getTypeSize(Types[I]) > BitWidth)
return Types[I];
-
+
return QualType();
}
@@ -13945,12 +14357,15 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
} else
Diag(IdLoc, diag::err_enumerator_too_large) << EltTy;
} else
- Val = ImpCastExprToType(Val, EltTy, CK_IntegralCast).get();
+ Val = ImpCastExprToType(Val, EltTy,
+ EltTy->isBooleanType() ?
+ CK_IntegralToBoolean : CK_IntegralCast)
+ .get();
} else if (getLangOpts().CPlusPlus) {
// C++11 [dcl.enum]p5:
// If the underlying type is not fixed, the type of each enumerator
// is the type of its initializing value:
- // - If an initializer is specified for an enumerator, the
+ // - If an initializer is specified for an enumerator, the
// initializing value has the same type as the expression.
EltTy = Val->getType();
} else {
@@ -13981,10 +14396,10 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// C++0x [dcl.enum]p5:
// If the underlying type is not fixed, the type of each enumerator
// is the type of its initializing value:
- // - If no initializer is specified for the first enumerator, the
+ // - If no initializer is specified for the first enumerator, the
// initializing value has an unspecified integral type.
//
- // GCC uses 'int' for its unspecified integral type, as does
+ // GCC uses 'int' for its unspecified integral type, as does
// C99 6.7.2.2p3.
if (Enum->isFixed()) {
EltTy = Enum->getIntegerType();
@@ -14007,12 +14422,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
// - Otherwise the type of the initializing value is the same as
// the type of the initializing value of the preceding enumerator
// unless the incremented value is not representable in that type,
- // in which case the type is an unspecified integral type
+ // in which case the type is an unspecified integral type
// sufficient to contain the incremented value. If no such type
// exists, the program is ill-formed.
QualType T = getNextLargerIntegralType(Context, EltTy);
if (T.isNull() || Enum->isFixed()) {
- // There is no integral type larger enough to represent this
+ // There is no integral type larger enough to represent this
// value. Complain, then allow the value to wrap around.
EnumVal = LastEnumConst->getInitVal();
EnumVal = EnumVal.zext(EnumVal.getBitWidth() * 2);
@@ -14028,15 +14443,15 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
} else {
EltTy = T;
}
-
+
// Retrieve the last enumerator's value, extent that type to the
// type that is supposed to be large enough to represent the incremented
// value, then increment.
EnumVal = LastEnumConst->getInitVal();
EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
EnumVal = EnumVal.zextOrTrunc(Context.getIntWidth(EltTy));
- ++EnumVal;
-
+ ++EnumVal;
+
// If we're not in C++, diagnose the overflow of enumerator values,
// which in C99 means that the enumerator value is not representable in
// an int (C99 6.7.2.2p2). However, we support GCC's extension that
@@ -14054,12 +14469,12 @@ EnumConstantDecl *Sema::CheckEnumConstant(EnumDecl *Enum,
}
if (!EltTy->isDependentType()) {
- // Make the enumerator value match the signedness and size of the
+ // Make the enumerator value match the signedness and size of the
// enumerator's type.
EnumVal = EnumVal.extOrTrunc(Context.getIntWidth(EltTy));
EnumVal.setIsSigned(EltTy->isSignedIntegerOrEnumerationType());
}
-
+
return EnumConstantDecl::Create(Context, Enum, IdLoc, Id, EltTy,
Val, EnumVal);
}
@@ -14114,14 +14529,14 @@ Decl *Sema::ActOnEnumConstant(Scope *S, Decl *theEnumDecl, Decl *lastEnumConst,
}
// C++ [class.mem]p15:
- // If T is the name of a class, then each of the following shall have a name
+ // If T is the name of a class, then each of the following shall have a name
// different from T:
- // - every enumerator of every member of class T that is an unscoped
+ // - every enumerator of every member of class T that is an unscoped
// enumerated type
if (!TheEnumDecl->isScoped())
DiagnoseClassNameShadow(TheEnumDecl->getDeclContext(),
DeclarationNameInfo(Id, IdLoc));
-
+
EnumConstantDecl *New =
CheckEnumConstant(TheEnumDecl, LastEnumConst, IdLoc, Id, Val);
if (!New)
@@ -14360,8 +14775,8 @@ bool Sema::IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
return !(FlagMask & Val) || (AllowMask && !(FlagMask & ~Val));
}
-void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
- SourceLocation RBraceLoc, Decl *EnumDeclX,
+void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceRange BraceRange,
+ Decl *EnumDeclX,
ArrayRef<Decl *> Elements,
Scope *S, AttributeList *Attr) {
EnumDecl *Enum = cast<EnumDecl>(EnumDeclX);
@@ -14430,7 +14845,7 @@ void Sema::ActOnEnumBody(SourceLocation EnumLoc, SourceLocation LBraceLoc,
// int, long long int, or unsigned long long int.
// C99 6.4.4.3p2:
// An identifier declared as an enumeration constant has type int.
- // The C99 rule is modified by a gcc extension
+ // The C99 rule is modified by a gcc extension
QualType BestPromotionType;
bool Packed = Enum->hasAttr<PackedAttr>();
@@ -14646,8 +15061,8 @@ void Sema::diagnoseMisplacedModuleImport(Module *M, SourceLocation ImportLoc) {
return checkModuleImportContext(*this, M, ImportLoc, CurContext);
}
-DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
- SourceLocation ImportLoc,
+DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
+ SourceLocation ImportLoc,
ModuleIdPath Path) {
Module *Mod =
getModuleLoader().loadModule(ImportLoc, Path, Module::AllVisible,
@@ -14663,11 +15078,10 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
// of the same top-level module. Until we do, make it an error rather than
// silently ignoring the import.
if (Mod->getTopLevelModuleName() == getLangOpts().CurrentModule)
- Diag(ImportLoc, diag::err_module_self_import)
+ Diag(ImportLoc, getLangOpts().CompilingModule
+ ? diag::err_module_self_import
+ : diag::err_module_import_in_implementation)
<< Mod->getFullModuleName() << getLangOpts().CurrentModule;
- else if (Mod->getTopLevelModuleName() == getLangOpts().ImplementationOfModule)
- Diag(ImportLoc, diag::err_module_import_in_implementation)
- << Mod->getFullModuleName() << getLangOpts().ImplementationOfModule;
SmallVector<SourceLocation, 2> IdentifierLocs;
Module *ModCheck = Mod;
@@ -14677,13 +15091,13 @@ DeclResult Sema::ActOnModuleImport(SourceLocation AtLoc,
if (!ModCheck)
break;
ModCheck = ModCheck->Parent;
-
+
IdentifierLocs.push_back(Path[I].second);
}
- ImportDecl *Import = ImportDecl::Create(Context,
+ ImportDecl *Import = ImportDecl::Create(Context,
Context.getTranslationUnitDecl(),
- AtLoc.isValid()? AtLoc : ImportLoc,
+ AtLoc.isValid()? AtLoc : ImportLoc,
Mod, IdentifierLocs);
Context.getTranslationUnitDecl()->addDecl(Import);
return Import;
@@ -14701,9 +15115,17 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
TUKind == TU_Module &&
getSourceManager().isWrittenInMainFile(DirectiveLoc);
- // If this module import was due to an inclusion directive, create an
+ // Similarly, if we're in the implementation of a module, don't
+ // synthesize an illegal module import. FIXME: Why not?
+ bool ShouldAddImport =
+ !IsInModuleIncludes &&
+ (getLangOpts().CompilingModule ||
+ getLangOpts().CurrentModule.empty() ||
+ getLangOpts().CurrentModule != Mod->getTopLevelModuleName());
+
+ // If this module import was due to an inclusion directive, create an
// implicit import declaration to capture it in the AST.
- if (!IsInModuleIncludes) {
+ if (ShouldAddImport) {
TranslationUnitDecl *TU = getASTContext().getTranslationUnitDecl();
ImportDecl *ImportD = ImportDecl::CreateImplicit(getASTContext(), TU,
DirectiveLoc, Mod,
@@ -14711,7 +15133,7 @@ void Sema::ActOnModuleInclude(SourceLocation DirectiveLoc, Module *Mod) {
TU->addDecl(ImportD);
Consumer.HandleImplicitImportDecl(ImportD);
}
-
+
getModuleLoader().makeModuleVisible(Mod, Module::AllVisible, DirectiveLoc);
VisibleModules.setVisible(Mod, DirectiveLoc);
}
@@ -14731,6 +15153,9 @@ void Sema::ActOnModuleEnd(SourceLocation DirectiveLoc, Module *Mod) {
VisibleModules = std::move(VisibleModulesStack.back());
VisibleModulesStack.pop_back();
VisibleModules.setVisible(Mod, DirectiveLoc);
+ // Leaving a module hides namespace names, so our visible namespace cache
+ // is now out of date.
+ VisibleNamespaceCache.clear();
}
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
index f94c822b90f5..a5780a7d71fb 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclAttr.cpp
@@ -12,6 +12,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Sema/SemaInternal.h"
+#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/CXXInheritance.h"
#include "clang/AST/DeclCXX.h"
@@ -27,10 +28,12 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/DelayedDiagnostic.h"
+#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/MathExtras.h"
+
using namespace clang;
using namespace sema;
@@ -40,7 +43,7 @@ namespace AttributeLangSupport {
Cpp,
ObjC
};
-}
+} // end namespace AttributeLangSupport
//===----------------------------------------------------------------------===//
// Helper functions
@@ -52,6 +55,7 @@ namespace AttributeLangSupport {
static bool isFunctionOrMethod(const Decl *D) {
return (D->getFunctionType() != nullptr) || isa<ObjCMethodDecl>(D);
}
+
/// \brief Return true if the given decl has function type (function or
/// function-typed variable) or an Objective-C method or a block.
static bool isFunctionOrMethodOrBlock(const Decl *D) {
@@ -801,6 +805,8 @@ static void handleLocksExcludedAttr(Sema &S, Decl *D,
}
static void handleEnableIfAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ S.Diag(Attr.getLoc(), diag::ext_clang_enable_if);
+
Expr *Cond = Attr.getArgAsExpr(0);
if (!Cond->isTypeDependent()) {
ExprResult Converted = S.PerformContextuallyConvertToBool(Cond);
@@ -887,7 +893,6 @@ static void handleConsumableAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
-
static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
const AttributeList &Attr) {
ASTContext &CurrContext = S.getASTContext();
@@ -905,7 +910,6 @@ static bool checkForConsumableClass(Sema &S, const CXXMethodDecl *MD,
return true;
}
-
static void handleCallableWhenAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
@@ -944,7 +948,6 @@ static void handleCallableWhenAttr(Sema &S, Decl *D,
States.size(), Attr.getAttributeSpellingListIndex()));
}
-
static void handleParamTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
ParamTypestateAttr::ConsumedState ParamState;
@@ -982,7 +985,6 @@ static void handleParamTypestateAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-
static void handleReturnTypestateAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
ReturnTypestateAttr::ConsumedState ReturnState;
@@ -1031,7 +1033,6 @@ static void handleReturnTypestateAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-
static void handleSetTypestateAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkForConsumableClass(S, cast<CXXMethodDecl>(D), Attr))
return;
@@ -1548,6 +1549,28 @@ static void handleWeakRefAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static void handleIFuncAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ StringRef Str;
+ if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ return;
+
+ // Aliases should be on declarations, not definitions.
+ const auto *FD = cast<FunctionDecl>(D);
+ if (FD->isThisDeclarationADefinition()) {
+ S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 1;
+ return;
+ }
+ // FIXME: it should be handled as a target specific attribute.
+ if (S.Context.getTargetInfo().getTriple().getObjectFormat() !=
+ llvm::Triple::ELF) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
+ return;
+ }
+
+ D->addAttr(::new (S.Context) IFuncAttr(Attr.getRange(), S.Context, Str,
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
StringRef Str;
if (!S.checkStringLiteralArgumentAttr(Attr, 0, Str))
@@ -1557,17 +1580,20 @@ static void handleAliasAttr(Sema &S, Decl *D, const AttributeList &Attr) {
S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_darwin);
return;
}
+ if (S.Context.getTargetInfo().getTriple().isNVPTX()) {
+ S.Diag(Attr.getLoc(), diag::err_alias_not_supported_on_nvptx);
+ }
// Aliases should be on declarations, not definitions.
if (const auto *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isThisDeclarationADefinition()) {
- S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD;
+ S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << FD << 0;
return;
}
} else {
const auto *VD = cast<VarDecl>(D);
if (VD->isThisDeclarationADefinition() && VD->isExternallyVisible()) {
- S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD;
+ S.Diag(Attr.getLoc(), diag::err_alias_is_definition) << VD << 0;
return;
}
}
@@ -1804,6 +1830,28 @@ static void handleUsedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
Attr.getAttributeSpellingListIndex()));
}
+static void handleUnusedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ bool IsCXX1zAttr = Attr.isCXX11Attribute() && !Attr.getScopeName();
+
+ if (IsCXX1zAttr && isa<VarDecl>(D)) {
+ // The C++1z spelling of this attribute cannot be applied to a static data
+ // member per [dcl.attr.unused]p2.
+ if (cast<VarDecl>(D)->isStaticDataMember()) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedForMaybeUnused;
+ return;
+ }
+ }
+
+ // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // about using it as an extension.
+ if (!S.getLangOpts().CPlusPlus1z && IsCXX1zAttr)
+ S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+
+ D->addAttr(::new (S.Context) UnusedAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
static void handleConstructorAttr(Sema &S, Decl *D, const AttributeList &Attr) {
uint32_t priority = ConstructorAttr::DefaultPriority;
if (Attr.getNumArgs() &&
@@ -1910,11 +1958,14 @@ static bool versionsMatch(const VersionTuple &X, const VersionTuple &Y,
AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
IdentifierInfo *Platform,
+ bool Implicit,
VersionTuple Introduced,
VersionTuple Deprecated,
VersionTuple Obsoleted,
bool IsUnavailable,
StringRef Message,
+ bool IsStrict,
+ StringRef Replacement,
AvailabilityMergeKind AMK,
unsigned AttrSpellingListIndex) {
VersionTuple MergedIntroduced = Introduced;
@@ -1952,14 +2003,14 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
// If there is an existing availability attribute for this platform that
// is explicit and the new one is implicit use the explicit one and
// discard the new implicit attribute.
- if (OldAA->getRange().isValid() && Range.isInvalid()) {
+ if (!OldAA->isImplicit() && Implicit) {
return nullptr;
}
// If there is an existing attribute for this platform that is implicit
// and the new attribute is explicit then erase the old one and
// continue processing the attributes.
- if (Range.isValid() && OldAA->getRange().isInvalid()) {
+ if (!Implicit && OldAA->isImplicit()) {
Attrs.erase(Attrs.begin() + i);
--e;
continue;
@@ -2058,10 +2109,13 @@ AvailabilityAttr *Sema::mergeAvailabilityAttr(NamedDecl *D, SourceRange Range,
if (!checkAvailabilityAttr(*this, Range, Platform, MergedIntroduced,
MergedDeprecated, MergedObsoleted) &&
!OverrideOrImpl) {
- return ::new (Context) AvailabilityAttr(Range, Context, Platform,
+ auto *Avail = ::new (Context) AvailabilityAttr(Range, Context, Platform,
Introduced, Deprecated,
Obsoleted, IsUnavailable, Message,
+ IsStrict, Replacement,
AttrSpellingListIndex);
+ Avail->setImplicit(Implicit);
+ return Avail;
}
return nullptr;
}
@@ -2088,16 +2142,23 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
AvailabilityChange Deprecated = Attr.getAvailabilityDeprecated();
AvailabilityChange Obsoleted = Attr.getAvailabilityObsoleted();
bool IsUnavailable = Attr.getUnavailableLoc().isValid();
+ bool IsStrict = Attr.getStrictLoc().isValid();
StringRef Str;
if (const StringLiteral *SE =
dyn_cast_or_null<StringLiteral>(Attr.getMessageExpr()))
Str = SE->getString();
+ StringRef Replacement;
+ if (const StringLiteral *SE =
+ dyn_cast_or_null<StringLiteral>(Attr.getReplacementExpr()))
+ Replacement = SE->getString();
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND, Attr.getRange(), II,
+ false/*Implicit*/,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
IsUnavailable, Str,
+ IsStrict, Replacement,
Sema::AMK_None,
Index);
if (NewAttr)
@@ -2136,12 +2197,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
auto NewObsoleted = adjustWatchOSVersion(Obsoleted.Version);
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND,
- SourceRange(),
+ Attr.getRange(),
NewII,
+ true/*Implicit*/,
NewIntroduced,
NewDeprecated,
NewObsoleted,
IsUnavailable, Str,
+ IsStrict,
+ Replacement,
Sema::AMK_None,
Index);
if (NewAttr)
@@ -2158,12 +2222,15 @@ static void handleAvailabilityAttr(Sema &S, Decl *D,
if (NewII) {
AvailabilityAttr *NewAttr = S.mergeAvailabilityAttr(ND,
- SourceRange(),
+ Attr.getRange(),
NewII,
+ true/*Implicit*/,
Introduced.Version,
Deprecated.Version,
Obsoleted.Version,
IsUnavailable, Str,
+ IsStrict,
+ Replacement,
Sema::AMK_None,
Index);
if (NewAttr)
@@ -2455,6 +2522,12 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const AttributeList &Attr)
return;
}
+ // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // about using it as an extension.
+ if (!S.getLangOpts().CPlusPlus1z && Attr.isCXX11Attribute() &&
+ !Attr.getScopeName())
+ S.Diag(Attr.getLoc(), diag::ext_cxx1z_attr) << Attr.getName();
+
D->addAttr(::new (S.Context)
WarnUnusedResultAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
@@ -2611,7 +2684,6 @@ static void handleTargetAttr(Sema &S, Decl *D, const AttributeList &Attr) {
D->addAttr(NewAttr);
}
-
static void handleCleanupAttr(Sema &S, Decl *D, const AttributeList &Attr) {
VarDecl *VD = cast<VarDecl>(D);
if (!VD->hasLocalStorage()) {
@@ -3069,7 +3141,6 @@ void Sema::AddAlignValueAttr(SourceRange AttrRange, Decl *D, Expr *E,
// Save dependent expressions in the AST to be instantiated.
D->addAttr(::new (Context) AlignValueAttr(TmpAttr));
- return;
}
static void handleAlignedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3293,6 +3364,8 @@ bool Sema::checkMSInheritanceAttrOnDefinition(
/// attribute.
static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
bool &IntegerMode, bool &ComplexMode) {
+ IntegerMode = true;
+ ComplexMode = false;
switch (Str.size()) {
case 2:
switch (Str[0]) {
@@ -3328,7 +3401,7 @@ static void parseModeAttrArg(Sema &S, StringRef Str, unsigned &DestWidth,
// FIXME: glibc uses 'word' to define register_t; this is narrower than a
// pointer on PIC16 and other embedded platforms.
if (Str == "word")
- DestWidth = S.Context.getTargetInfo().getPointerWidth(0);
+ DestWidth = S.Context.getTargetInfo().getRegisterWidth();
else if (Str == "byte")
DestWidth = S.Context.getTargetInfo().getCharWidth();
break;
@@ -3359,9 +3432,15 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
IdentifierInfo *Name = Attr.getArgAsIdent(0)->Ident;
- StringRef Str = Name->getName();
+ S.AddModeAttr(Attr.getRange(), D, Name, Attr.getAttributeSpellingListIndex());
+}
+
+void Sema::AddModeAttr(SourceRange AttrRange, Decl *D, IdentifierInfo *Name,
+ unsigned SpellingListIndex, bool InInstantiation) {
+ StringRef Str = Name->getName();
normalizeName(Str);
+ SourceLocation AttrLoc = AttrRange.getBegin();
unsigned DestWidth = 0;
bool IntegerMode = true;
@@ -3377,25 +3456,43 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (VectorStringLength &&
!Str.substr(1, VectorStringLength).getAsInteger(10, VectorSize) &&
VectorSize.isPowerOf2()) {
- parseModeAttrArg(S, Str.substr(VectorStringLength + 1), DestWidth,
+ parseModeAttrArg(*this, Str.substr(VectorStringLength + 1), DestWidth,
IntegerMode, ComplexMode);
- S.Diag(Attr.getLoc(), diag::warn_vector_mode_deprecated);
+ // Avoid duplicate warning from template instantiation.
+ if (!InInstantiation)
+ Diag(AttrLoc, diag::warn_vector_mode_deprecated);
} else {
VectorSize = 0;
}
}
if (!VectorSize)
- parseModeAttrArg(S, Str, DestWidth, IntegerMode, ComplexMode);
+ parseModeAttrArg(*this, Str, DestWidth, IntegerMode, ComplexMode);
+
+ // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
+ // and friends, at least with glibc.
+ // FIXME: Make sure floating-point mappings are accurate
+ // FIXME: Support XF and TF types
+ if (!DestWidth) {
+ Diag(AttrLoc, diag::err_machine_mode) << 0 /*Unknown*/ << Name;
+ return;
+ }
QualType OldTy;
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
OldTy = TD->getUnderlyingType();
- else if (ValueDecl *VD = dyn_cast<ValueDecl>(D))
- OldTy = VD->getType();
- else {
- S.Diag(D->getLocation(), diag::err_attr_wrong_decl)
- << Attr.getName() << Attr.getRange();
+ else if (EnumDecl *ED = dyn_cast<EnumDecl>(D)) {
+ // Something like 'typedef enum { X } __attribute__((mode(XX))) T;'.
+ // Try to get type from enum declaration, default to int.
+ OldTy = ED->getIntegerType();
+ if (OldTy.isNull())
+ OldTy = Context.IntTy;
+ } else
+ OldTy = cast<ValueDecl>(D)->getType();
+
+ if (OldTy->isDependentType()) {
+ D->addAttr(::new (Context)
+ ModeAttr(AttrRange, Context, Name, SpellingListIndex));
return;
}
@@ -3405,91 +3502,83 @@ static void handleModeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (const VectorType *VT = OldTy->getAs<VectorType>())
OldElemTy = VT->getElementType();
- if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType())
- S.Diag(Attr.getLoc(), diag::err_mode_not_primitive);
+ // GCC allows 'mode' attribute on enumeration types (even incomplete), except
+ // for vector modes. So, 'enum X __attribute__((mode(QI)));' forms a complete
+ // type, 'enum { A } __attribute__((mode(V4SI)))' is rejected.
+ if ((isa<EnumDecl>(D) || OldElemTy->getAs<EnumType>()) &&
+ VectorSize.getBoolValue()) {
+ Diag(AttrLoc, diag::err_enum_mode_vector_type) << Name << AttrRange;
+ return;
+ }
+ bool IntegralOrAnyEnumType =
+ OldElemTy->isIntegralOrEnumerationType() || OldElemTy->getAs<EnumType>();
+
+ if (!OldElemTy->getAs<BuiltinType>() && !OldElemTy->isComplexType() &&
+ !IntegralOrAnyEnumType)
+ Diag(AttrLoc, diag::err_mode_not_primitive);
else if (IntegerMode) {
- if (!OldElemTy->isIntegralOrEnumerationType())
- S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ if (!IntegralOrAnyEnumType)
+ Diag(AttrLoc, diag::err_mode_wrong_type);
} else if (ComplexMode) {
if (!OldElemTy->isComplexType())
- S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ Diag(AttrLoc, diag::err_mode_wrong_type);
} else {
if (!OldElemTy->isFloatingType())
- S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
- }
-
- // FIXME: Sync this with InitializePredefinedMacros; we need to match int8_t
- // and friends, at least with glibc.
- // FIXME: Make sure floating-point mappings are accurate
- // FIXME: Support XF and TF types
- if (!DestWidth) {
- S.Diag(Attr.getLoc(), diag::err_machine_mode) << 0 /*Unknown*/ << Name;
- return;
+ Diag(AttrLoc, diag::err_mode_wrong_type);
}
QualType NewElemTy;
if (IntegerMode)
- NewElemTy = S.Context.getIntTypeForBitwidth(
- DestWidth, OldElemTy->isSignedIntegerType());
+ NewElemTy = Context.getIntTypeForBitwidth(DestWidth,
+ OldElemTy->isSignedIntegerType());
else
- NewElemTy = S.Context.getRealTypeForBitwidth(DestWidth);
+ NewElemTy = Context.getRealTypeForBitwidth(DestWidth);
if (NewElemTy.isNull()) {
- S.Diag(Attr.getLoc(), diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
+ Diag(AttrLoc, diag::err_machine_mode) << 1 /*Unsupported*/ << Name;
return;
}
if (ComplexMode) {
- NewElemTy = S.Context.getComplexType(NewElemTy);
+ NewElemTy = Context.getComplexType(NewElemTy);
}
QualType NewTy = NewElemTy;
if (VectorSize.getBoolValue()) {
- NewTy = S.Context.getVectorType(NewTy, VectorSize.getZExtValue(),
- VectorType::GenericVector);
+ NewTy = Context.getVectorType(NewTy, VectorSize.getZExtValue(),
+ VectorType::GenericVector);
} else if (const VectorType *OldVT = OldTy->getAs<VectorType>()) {
// Complex machine mode does not support base vector types.
if (ComplexMode) {
- S.Diag(Attr.getLoc(), diag::err_complex_mode_vector_type);
+ Diag(AttrLoc, diag::err_complex_mode_vector_type);
return;
}
- unsigned NumElements = S.Context.getTypeSize(OldElemTy) *
+ unsigned NumElements = Context.getTypeSize(OldElemTy) *
OldVT->getNumElements() /
- S.Context.getTypeSize(NewElemTy);
+ Context.getTypeSize(NewElemTy);
NewTy =
- S.Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind());
+ Context.getVectorType(NewElemTy, NumElements, OldVT->getVectorKind());
}
if (NewTy.isNull()) {
- S.Diag(Attr.getLoc(), diag::err_mode_wrong_type);
+ Diag(AttrLoc, diag::err_mode_wrong_type);
return;
}
// Install the new type.
if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(D))
TD->setModedTypeSourceInfo(TD->getTypeSourceInfo(), NewTy);
+ else if (EnumDecl *ED = dyn_cast<EnumDecl>(D))
+ ED->setIntegerType(NewTy);
else
cast<ValueDecl>(D)->setType(NewTy);
- D->addAttr(::new (S.Context)
- ModeAttr(Attr.getRange(), S.Context, Name,
- Attr.getAttributeSpellingListIndex()));
+ D->addAttr(::new (Context)
+ ModeAttr(AttrRange, Context, Name, SpellingListIndex));
}
static void handleNoDebugAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
- if (!VD->hasGlobalStorage())
- S.Diag(Attr.getLoc(),
- diag::warn_attribute_requires_functions_or_static_globals)
- << Attr.getName();
- } else if (!isFunctionOrMethod(D)) {
- S.Diag(Attr.getLoc(),
- diag::warn_attribute_requires_functions_or_static_globals)
- << Attr.getName();
- return;
- }
-
D->addAttr(::new (S.Context)
NoDebugAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
@@ -3622,11 +3711,21 @@ static void handleGlobalAttr(Sema &S, Decl *D, const AttributeList &Attr) {
: FixItHint());
return;
}
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(FD)) {
+ if (Method->isInstance()) {
+ S.Diag(Method->getLocStart(), diag::err_kern_is_nonstatic_method)
+ << Method;
+ return;
+ }
+ S.Diag(Method->getLocStart(), diag::warn_kern_is_method) << Method;
+ }
+ // Only warn for "inline" when compiling for host, to cut down on noise.
+ if (FD->isInlineSpecified() && !S.getLangOpts().CUDAIsDevice)
+ S.Diag(FD->getLocStart(), diag::warn_kern_is_inline) << FD;
D->addAttr(::new (S.Context)
CUDAGlobalAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
-
}
static void handleGNUInlineAttr(Sema &S, Decl *D, const AttributeList &Attr) {
@@ -3682,6 +3781,11 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
PascalAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
+ case AttributeList::AT_SwiftCall:
+ D->addAttr(::new (S.Context)
+ SwiftCallAttr(Attr.getRange(), S.Context,
+ Attr.getAttributeSpellingListIndex()));
+ return;
case AttributeList::AT_VectorCall:
D->addAttr(::new (S.Context)
VectorCallAttr(Attr.getRange(), S.Context,
@@ -3720,7 +3824,14 @@ static void handleCallConvAttr(Sema &S, Decl *D, const AttributeList &Attr) {
IntelOclBiccAttr(Attr.getRange(), S.Context,
Attr.getAttributeSpellingListIndex()));
return;
-
+ case AttributeList::AT_PreserveMost:
+ D->addAttr(::new (S.Context) PreserveMostAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ return;
+ case AttributeList::AT_PreserveAll:
+ D->addAttr(::new (S.Context) PreserveAllAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+ return;
default:
llvm_unreachable("unexpected attribute kind");
}
@@ -3731,6 +3842,11 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
if (attr.isInvalid())
return true;
+ if (attr.hasProcessingCache()) {
+ CC = (CallingConv) attr.getProcessingCache();
+ return false;
+ }
+
unsigned ReqArgs = attr.getKind() == AttributeList::AT_Pcs ? 1 : 0;
if (!checkAttributeNumArgs(*this, attr, ReqArgs)) {
attr.setInvalid();
@@ -3744,6 +3860,7 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
case AttributeList::AT_StdCall: CC = CC_X86StdCall; break;
case AttributeList::AT_ThisCall: CC = CC_X86ThisCall; break;
case AttributeList::AT_Pascal: CC = CC_X86Pascal; break;
+ case AttributeList::AT_SwiftCall: CC = CC_Swift; break;
case AttributeList::AT_VectorCall: CC = CC_X86VectorCall; break;
case AttributeList::AT_MSABI:
CC = Context.getTargetInfo().getTriple().isOSWindows() ? CC_C :
@@ -3772,6 +3889,8 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
return true;
}
case AttributeList::AT_IntelOclBicc: CC = CC_IntelOclBicc; break;
+ case AttributeList::AT_PreserveMost: CC = CC_PreserveMost; break;
+ case AttributeList::AT_PreserveAll: CC = CC_PreserveAll; break;
default: llvm_unreachable("unexpected attribute kind");
}
@@ -3783,16 +3902,108 @@ bool Sema::CheckCallingConvAttr(const AttributeList &attr, CallingConv &CC,
// This convention is not valid for the target. Use the default function or
// method calling convention.
- TargetInfo::CallingConvMethodType MT = TargetInfo::CCMT_Unknown;
- if (FD)
- MT = FD->isCXXInstanceMember() ? TargetInfo::CCMT_Member :
- TargetInfo::CCMT_NonMember;
- CC = TI.getDefaultCallingConv(MT);
+ bool IsCXXMethod = false, IsVariadic = false;
+ if (FD) {
+ IsCXXMethod = FD->isCXXInstanceMember();
+ IsVariadic = FD->isVariadic();
+ }
+ CC = Context.getDefaultCallingConvention(IsVariadic, IsCXXMethod);
}
+ attr.setProcessingCache((unsigned) CC);
return false;
}
+/// Pointer-like types in the default address space.
+static bool isValidSwiftContextType(QualType type) {
+ if (!type->hasPointerRepresentation())
+ return type->isDependentType();
+ return type->getPointeeType().getAddressSpace() == 0;
+}
+
+/// Pointers and references in the default address space.
+static bool isValidSwiftIndirectResultType(QualType type) {
+ if (auto ptrType = type->getAs<PointerType>()) {
+ type = ptrType->getPointeeType();
+ } else if (auto refType = type->getAs<ReferenceType>()) {
+ type = refType->getPointeeType();
+ } else {
+ return type->isDependentType();
+ }
+ return type.getAddressSpace() == 0;
+}
+
+/// Pointers and references to pointers in the default address space.
+static bool isValidSwiftErrorResultType(QualType type) {
+ if (auto ptrType = type->getAs<PointerType>()) {
+ type = ptrType->getPointeeType();
+ } else if (auto refType = type->getAs<ReferenceType>()) {
+ type = refType->getPointeeType();
+ } else {
+ return type->isDependentType();
+ }
+ if (!type.getQualifiers().empty())
+ return false;
+ return isValidSwiftContextType(type);
+}
+
+static void handleParameterABIAttr(Sema &S, Decl *D, const AttributeList &attr,
+ ParameterABI abi) {
+ S.AddParameterABIAttr(attr.getRange(), D, abi,
+ attr.getAttributeSpellingListIndex());
+}
+
+void Sema::AddParameterABIAttr(SourceRange range, Decl *D, ParameterABI abi,
+ unsigned spellingIndex) {
+
+ QualType type = cast<ParmVarDecl>(D)->getType();
+
+ if (auto existingAttr = D->getAttr<ParameterABIAttr>()) {
+ if (existingAttr->getABI() != abi) {
+ Diag(range.getBegin(), diag::err_attributes_are_not_compatible)
+ << getParameterABISpelling(abi) << existingAttr;
+ Diag(existingAttr->getLocation(), diag::note_conflicting_attribute);
+ return;
+ }
+ }
+
+ switch (abi) {
+ case ParameterABI::Ordinary:
+ llvm_unreachable("explicit attribute for ordinary parameter ABI?");
+
+ case ParameterABI::SwiftContext:
+ if (!isValidSwiftContextType(type)) {
+ Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi)
+ << /*pointer to pointer */ 0 << type;
+ }
+ D->addAttr(::new (Context)
+ SwiftContextAttr(range, Context, spellingIndex));
+ return;
+
+ case ParameterABI::SwiftErrorResult:
+ if (!isValidSwiftErrorResultType(type)) {
+ Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi)
+ << /*pointer to pointer */ 1 << type;
+ }
+ D->addAttr(::new (Context)
+ SwiftErrorResultAttr(range, Context, spellingIndex));
+ return;
+
+ case ParameterABI::SwiftIndirectResult:
+ if (!isValidSwiftIndirectResultType(type)) {
+ Diag(range.getBegin(), diag::err_swift_abi_parameter_wrong_type)
+ << getParameterABISpelling(abi)
+ << /*pointer*/ 0 << type;
+ }
+ D->addAttr(::new (Context)
+ SwiftIndirectResultAttr(range, Context, spellingIndex));
+ return;
+ }
+ llvm_unreachable("bad parameter ABI attribute");
+}
+
/// Checks a regparm attribute, returning true if it is ill-formed and
/// otherwise setting numParams to the appropriate value.
bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
@@ -3829,49 +4040,60 @@ bool Sema::CheckRegparmAttr(const AttributeList &Attr, unsigned &numParams) {
return false;
}
-// Checks whether an argument of launch_bounds attribute is acceptable
-// May output an error.
-static bool checkLaunchBoundsArgument(Sema &S, Expr *E,
- const CUDALaunchBoundsAttr &Attr,
- const unsigned Idx) {
-
+// Checks whether an argument of launch_bounds attribute is
+// acceptable, performs implicit conversion to Rvalue, and returns
+// non-nullptr Expr result on success. Otherwise, it returns nullptr
+// and may output an error.
+static Expr *makeLaunchBoundsArgExpr(Sema &S, Expr *E,
+ const CUDALaunchBoundsAttr &Attr,
+ const unsigned Idx) {
if (S.DiagnoseUnexpandedParameterPack(E))
- return false;
+ return nullptr;
// Accept template arguments for now as they depend on something else.
// We'll get to check them when they eventually get instantiated.
if (E->isValueDependent())
- return true;
+ return E;
llvm::APSInt I(64);
if (!E->isIntegerConstantExpr(I, S.Context)) {
S.Diag(E->getExprLoc(), diag::err_attribute_argument_n_type)
<< &Attr << Idx << AANT_ArgumentIntegerConstant << E->getSourceRange();
- return false;
+ return nullptr;
}
// Make sure we can fit it in 32 bits.
if (!I.isIntN(32)) {
S.Diag(E->getExprLoc(), diag::err_ice_too_large) << I.toString(10, false)
<< 32 << /* Unsigned */ 1;
- return false;
+ return nullptr;
}
if (I < 0)
S.Diag(E->getExprLoc(), diag::warn_attribute_argument_n_negative)
<< &Attr << Idx << E->getSourceRange();
- return true;
+ // We may need to perform implicit conversion of the argument.
+ InitializedEntity Entity = InitializedEntity::InitializeParameter(
+ S.Context, S.Context.getConstType(S.Context.IntTy), /*consume*/ false);
+ ExprResult ValArg = S.PerformCopyInitialization(Entity, SourceLocation(), E);
+ assert(!ValArg.isInvalid() &&
+ "Unexpected PerformCopyInitialization() failure.");
+
+ return ValArg.getAs<Expr>();
}
void Sema::AddLaunchBoundsAttr(SourceRange AttrRange, Decl *D, Expr *MaxThreads,
Expr *MinBlocks, unsigned SpellingListIndex) {
CUDALaunchBoundsAttr TmpAttr(AttrRange, Context, MaxThreads, MinBlocks,
SpellingListIndex);
-
- if (!checkLaunchBoundsArgument(*this, MaxThreads, TmpAttr, 0))
+ MaxThreads = makeLaunchBoundsArgExpr(*this, MaxThreads, TmpAttr, 0);
+ if (MaxThreads == nullptr)
return;
- if (MinBlocks && !checkLaunchBoundsArgument(*this, MinBlocks, TmpAttr, 1))
- return;
+ if (MinBlocks) {
+ MinBlocks = makeLaunchBoundsArgExpr(*this, MinBlocks, TmpAttr, 1);
+ if (MinBlocks == nullptr)
+ return;
+ }
D->addAttr(::new (Context) CUDALaunchBoundsAttr(
AttrRange, Context, MaxThreads, MinBlocks, SpellingListIndex));
@@ -3977,6 +4199,7 @@ static bool isValidSubjectOfNSAttribute(Sema &S, QualType type) {
type->isObjCObjectPointerType() ||
S.Context.isObjCNSObjectType(type);
}
+
static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
return type->isDependentType() ||
type->isPointerType() ||
@@ -3984,36 +4207,49 @@ static bool isValidSubjectOfCFAttribute(Sema &S, QualType type) {
}
static void handleNSConsumedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ S.AddNSConsumedAttr(Attr.getRange(), D, Attr.getAttributeSpellingListIndex(),
+ Attr.getKind() == AttributeList::AT_NSConsumed,
+ /*template instantiation*/ false);
+}
+
+void Sema::AddNSConsumedAttr(SourceRange attrRange, Decl *D,
+ unsigned spellingIndex, bool isNSConsumed,
+ bool isTemplateInstantiation) {
ParmVarDecl *param = cast<ParmVarDecl>(D);
- bool typeOK, cf;
+ bool typeOK;
- if (Attr.getKind() == AttributeList::AT_NSConsumed) {
- typeOK = isValidSubjectOfNSAttribute(S, param->getType());
- cf = false;
+ if (isNSConsumed) {
+ typeOK = isValidSubjectOfNSAttribute(*this, param->getType());
} else {
- typeOK = isValidSubjectOfCFAttribute(S, param->getType());
- cf = true;
+ typeOK = isValidSubjectOfCFAttribute(*this, param->getType());
}
if (!typeOK) {
- S.Diag(D->getLocStart(), diag::warn_ns_attribute_wrong_parameter_type)
- << Attr.getRange() << Attr.getName() << cf;
- return;
- }
-
- if (cf)
- param->addAttr(::new (S.Context)
- CFConsumedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ // These attributes are normally just advisory, but in ARC, ns_consumed
+ // is significant. Allow non-dependent code to contain inappropriate
+ // attributes even in ARC, but require template instantiations to be
+ // set up correctly.
+ Diag(D->getLocStart(),
+ (isTemplateInstantiation && isNSConsumed &&
+ getLangOpts().ObjCAutoRefCount
+ ? diag::err_ns_attribute_wrong_parameter_type
+ : diag::warn_ns_attribute_wrong_parameter_type))
+ << attrRange
+ << (isNSConsumed ? "ns_consumed" : "cf_consumed")
+ << (isNSConsumed ? /*objc pointers*/ 0 : /*cf pointers*/ 1);
+ return;
+ }
+
+ if (isNSConsumed)
+ param->addAttr(::new (Context)
+ NSConsumedAttr(attrRange, Context, spellingIndex));
else
- param->addAttr(::new (S.Context)
- NSConsumedAttr(Attr.getRange(), S.Context,
- Attr.getAttributeSpellingListIndex()));
+ param->addAttr(::new (Context)
+ CFConsumedAttr(attrRange, Context, spellingIndex));
}
static void handleNSReturnsRetainedAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
-
QualType returnType;
if (ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
@@ -4287,10 +4523,9 @@ static void handleObjCRuntimeName(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
-// when a user wants to use objc_boxable with a union or struct
-// but she doesn't have access to the declaration (legacy/third-party code)
-// then she can 'enable' this feature via trick with a typedef
-// e.g.:
+// When a user wants to use objc_boxable with a union or struct
+// but they don't have access to the declaration (legacy/third-party code)
+// then they can 'enable' this feature with a typedef:
// typedef struct __attribute((objc_boxable)) legacy_struct legacy_struct;
static void handleObjCBoxable(Sema &S, Decl *D, const AttributeList &Attr) {
bool notify = false;
@@ -4423,8 +4658,10 @@ static void handleMSInheritanceAttr(Sema &S, Decl *D, const AttributeList &Attr)
D, Attr.getRange(), /*BestCase=*/true,
Attr.getAttributeSpellingListIndex(),
(MSInheritanceAttr::Spelling)Attr.getSemanticSpelling());
- if (IA)
+ if (IA) {
D->addAttr(IA);
+ S.Consumer.AssignInheritanceModel(cast<CXXRecordDecl>(D));
+ }
}
static void handleDeclspecThreadAttr(Sema &S, Decl *D,
@@ -4446,6 +4683,38 @@ static void handleDeclspecThreadAttr(Sema &S, Decl *D,
Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
}
+static void handleAbiTagAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ SmallVector<StringRef, 4> Tags;
+ for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
+ StringRef Tag;
+ if (!S.checkStringLiteralArgumentAttr(Attr, I, Tag))
+ return;
+ Tags.push_back(Tag);
+ }
+
+ if (const auto *NS = dyn_cast<NamespaceDecl>(D)) {
+ if (!NS->isInline()) {
+ S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 0;
+ return;
+ }
+ if (NS->isAnonymousNamespace()) {
+ S.Diag(Attr.getLoc(), diag::warn_attr_abi_tag_namespace) << 1;
+ return;
+ }
+ if (Attr.getNumArgs() == 0)
+ Tags.push_back(NS->getName());
+ } else if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
+ return;
+
+ // Store tags sorted and without duplicates.
+ std::sort(Tags.begin(), Tags.end());
+ Tags.erase(std::unique(Tags.begin(), Tags.end()), Tags.end());
+
+ D->addAttr(::new (S.Context)
+ AbiTagAttr(Attr.getRange(), S.Context, Tags.data(), Tags.size(),
+ Attr.getAttributeSpellingListIndex()));
+}
+
static void handleARMInterruptAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
// Check the attribute arguments.
@@ -4570,17 +4839,90 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D,
Attr.getLoc(), S.Context, Kind, Attr.getAttributeSpellingListIndex()));
}
+static void handleAnyX86InterruptAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ // Semantic checks for a function with the 'interrupt' attribute.
+ // a) Must be a function.
+ // b) Must have the 'void' return type.
+ // c) Must take 1 or 2 arguments.
+ // d) The 1st argument must be a pointer.
+ // e) The 2nd argument (if any) must be an unsigned integer.
+ if (!isFunctionOrMethod(D) || !hasFunctionProto(D) || isInstanceMethod(D) ||
+ CXXMethodDecl::isStaticOverloadedOperator(
+ cast<NamedDecl>(D)->getDeclName().getCXXOverloadedOperator())) {
+ S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type)
+ << Attr.getName() << ExpectedFunctionWithProtoType;
+ return;
+ }
+ // Interrupt handler must have void return type.
+ if (!getFunctionOrMethodResultType(D)->isVoidType()) {
+ S.Diag(getFunctionOrMethodResultSourceRange(D).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 0;
+ return;
+ }
+ // Interrupt handler must have 1 or 2 parameters.
+ unsigned NumParams = getFunctionOrMethodNumParams(D);
+ if (NumParams < 1 || NumParams > 2) {
+ S.Diag(D->getLocStart(), diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 1;
+ return;
+ }
+ // The first argument must be a pointer.
+ if (!getFunctionOrMethodParamType(D, 0)->isPointerType()) {
+ S.Diag(getFunctionOrMethodParamRange(D, 0).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 2;
+ return;
+ }
+ // The second argument, if present, must be an unsigned integer.
+ unsigned TypeSize =
+ S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86_64
+ ? 64
+ : 32;
+ if (NumParams == 2 &&
+ (!getFunctionOrMethodParamType(D, 1)->isUnsignedIntegerType() ||
+ S.Context.getTypeSize(getFunctionOrMethodParamType(D, 1)) != TypeSize)) {
+ S.Diag(getFunctionOrMethodParamRange(D, 1).getBegin(),
+ diag::err_anyx86_interrupt_attribute)
+ << (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::x86
+ ? 0
+ : 1)
+ << 3 << S.Context.getIntTypeForBitwidth(TypeSize, /*Signed=*/false);
+ return;
+ }
+ D->addAttr(::new (S.Context) AnyX86InterruptAttr(
+ Attr.getLoc(), S.Context, Attr.getAttributeSpellingListIndex()));
+ D->addAttr(UsedAttr::CreateImplicit(S.Context));
+}
+
static void handleInterruptAttr(Sema &S, Decl *D, const AttributeList &Attr) {
// Dispatch the interrupt attribute based on the current target.
- if (S.Context.getTargetInfo().getTriple().getArch() == llvm::Triple::msp430)
+ switch (S.Context.getTargetInfo().getTriple().getArch()) {
+ case llvm::Triple::msp430:
handleMSP430InterruptAttr(S, D, Attr);
- else if (S.Context.getTargetInfo().getTriple().getArch() ==
- llvm::Triple::mipsel ||
- S.Context.getTargetInfo().getTriple().getArch() ==
- llvm::Triple::mips)
+ break;
+ case llvm::Triple::mipsel:
+ case llvm::Triple::mips:
handleMipsInterruptAttr(S, D, Attr);
- else
+ break;
+ case llvm::Triple::x86:
+ case llvm::Triple::x86_64:
+ handleAnyX86InterruptAttr(S, D, Attr);
+ break;
+ default:
handleARMInterruptAttr(S, D, Attr);
+ break;
+ }
}
static void handleAMDGPUNumVGPRAttr(Sema &S, Decl *D,
@@ -4634,6 +4976,24 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D,
Attr.getAttributeSpellingListIndex()));
}
+static void handleLayoutVersion(Sema &S, Decl *D, const AttributeList &Attr) {
+ uint32_t Version;
+ Expr *VersionExpr = static_cast<Expr *>(Attr.getArgAsExpr(0));
+ if (!checkUInt32Argument(S, Attr, Attr.getArgAsExpr(0), Version))
+ return;
+
+ // TODO: Investigate what happens with the next major version of MSVC.
+ if (Version != LangOptions::MSVC2015) {
+ S.Diag(Attr.getLoc(), diag::err_attribute_argument_out_of_bounds)
+ << Attr.getName() << Version << VersionExpr->getSourceRange();
+ return;
+ }
+
+ D->addAttr(::new (S.Context)
+ LayoutVersionAttr(Attr.getRange(), S.Context, Version,
+ Attr.getAttributeSpellingListIndex()));
+}
+
DLLImportAttr *Sema::mergeDLLImportAttr(Decl *D, SourceRange Range,
unsigned AttrSpellingListIndex) {
if (D->hasAttr<DLLExportAttr>()) {
@@ -4827,19 +5187,34 @@ static void handleDeprecatedAttr(Sema &S, Decl *D, const AttributeList &Attr) {
}
}
+ // Handle the cases where the attribute has a text message.
+ StringRef Str, Replacement;
+ if (Attr.isArgExpr(0) && Attr.getArgAsExpr(0) &&
+ !S.checkStringLiteralArgumentAttr(Attr, 0, Str))
+ return;
+
+ // Only support a single optional message for Declspec and CXX11.
+ if (Attr.isDeclspecAttribute() || Attr.isCXX11Attribute())
+ checkAttributeAtMostNumArgs(S, Attr, 1);
+ else if (Attr.isArgExpr(1) && Attr.getArgAsExpr(1) &&
+ !S.checkStringLiteralArgumentAttr(Attr, 1, Replacement))
+ return;
+
if (!S.getLangOpts().CPlusPlus14)
if (Attr.isCXX11Attribute() &&
!(Attr.hasScope() && Attr.getScopeName()->isStr("gnu")))
- S.Diag(Attr.getLoc(), diag::ext_deprecated_attr_is_a_cxx14_extension);
+ S.Diag(Attr.getLoc(), diag::ext_cxx14_attr) << Attr.getName();
- handleAttrWithMessage<DeprecatedAttr>(S, D, Attr);
+ D->addAttr(::new (S.Context) DeprecatedAttr(Attr.getRange(), S.Context, Str,
+ Replacement,
+ Attr.getAttributeSpellingListIndex()));
}
static void handleNoSanitizeAttr(Sema &S, Decl *D, const AttributeList &Attr) {
if (!checkAttributeAtLeastNumArgs(S, Attr, 1))
return;
- std::vector<std::string> Sanitizers;
+ std::vector<StringRef> Sanitizers;
for (unsigned I = 0, E = Attr.getNumArgs(); I != E; ++I) {
StringRef SanitizerName;
@@ -4863,8 +5238,8 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D,
const AttributeList &Attr) {
StringRef AttrName = Attr.getName()->getName();
normalizeName(AttrName);
- std::string SanitizerName =
- llvm::StringSwitch<std::string>(AttrName)
+ StringRef SanitizerName =
+ llvm::StringSwitch<StringRef>(AttrName)
.Case("no_address_safety_analysis", "address")
.Case("no_sanitize_address", "address")
.Case("no_sanitize_thread", "thread")
@@ -4882,6 +5257,15 @@ static void handleInternalLinkageAttr(Sema &S, Decl *D,
D->addAttr(Internal);
}
+static void handleOpenCLNoSVMAttr(Sema &S, Decl *D, const AttributeList &Attr) {
+ if (S.LangOpts.OpenCLVersion != 200)
+ S.Diag(Attr.getLoc(), diag::err_attribute_requires_opencl_version)
+ << Attr.getName() << "2.0" << 0;
+ else
+ S.Diag(Attr.getLoc(), diag::warn_opencl_attr_deprecated_ignored)
+ << Attr.getName() << "2.0";
+}
+
/// Handles semantic checking for features that are common to all attributes,
/// such as checking whether a parameter was properly specified, or the correct
/// number of arguments were passed, etc.
@@ -4923,6 +5307,40 @@ static bool handleCommonAttributeFeatures(Sema &S, Scope *scope, Decl *D,
return false;
}
+static void handleOpenCLAccessAttr(Sema &S, Decl *D,
+ const AttributeList &Attr) {
+ if (D->isInvalidDecl())
+ return;
+
+ // Check if there is only one access qualifier.
+ if (D->hasAttr<OpenCLAccessAttr>()) {
+ S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers)
+ << D->getSourceRange();
+ D->setInvalidDecl(true);
+ return;
+ }
+
+ // OpenCL v2.0 s6.6 - read_write can be used for image types to specify that an
+ // image object can be read and written.
+ // OpenCL v2.0 s6.13.6 - A kernel cannot read from and write to the same pipe
+ // object. Using the read_write (or __read_write) qualifier with the pipe
+ // qualifier is a compilation error.
+ if (const ParmVarDecl *PDecl = dyn_cast<ParmVarDecl>(D)) {
+ const Type *DeclTy = PDecl->getType().getCanonicalType().getTypePtr();
+ if (Attr.getName()->getName().find("read_write") != StringRef::npos) {
+ if (S.getLangOpts().OpenCLVersion < 200 || DeclTy->isPipeType()) {
+ S.Diag(Attr.getLoc(), diag::err_opencl_invalid_read_write)
+ << Attr.getName() << PDecl->getType() << DeclTy->isImageType();
+ D->setInvalidDecl(true);
+ return;
+ }
+ }
+ }
+
+ D->addAttr(::new (S.Context) OpenCLAccessAttr(
+ Attr.getRange(), S.Context, Attr.getAttributeSpellingListIndex()));
+}
+
//===----------------------------------------------------------------------===//
// Top Level Sema Entry Points
//===----------------------------------------------------------------------===//
@@ -4958,8 +5376,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
switch (Attr.getKind()) {
default:
- // Type attributes are handled elsewhere; silently move on.
- assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+ if (!Attr.isStmtAttr()) {
+ // Type attributes are handled elsewhere; silently move on.
+ assert(Attr.isTypeAttr() && "Non-type attribute not handled");
+ break;
+ }
+ S.Diag(Attr.getLoc(), diag::err_stmt_attribute_invalid_on_decl)
+ << Attr.getName() << D->getLocation();
break;
case AttributeList::AT_Interrupt:
handleInterruptAttr(S, D, Attr);
@@ -4993,6 +5416,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_IBOutletCollection:
handleIBOutletCollection(S, D, Attr);
break;
+ case AttributeList::AT_IFunc:
+ handleIFuncAttr(S, D, Attr);
+ break;
case AttributeList::AT_Alias:
handleAliasAttr(S, D, Attr);
break;
@@ -5141,53 +5567,45 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_VecReturn:
handleVecReturnAttr(S, D, Attr);
break;
-
case AttributeList::AT_ObjCOwnership:
handleObjCOwnershipAttr(S, D, Attr);
break;
case AttributeList::AT_ObjCPreciseLifetime:
handleObjCPreciseLifetimeAttr(S, D, Attr);
break;
-
case AttributeList::AT_ObjCReturnsInnerPointer:
handleObjCReturnsInnerPointerAttr(S, D, Attr);
break;
-
case AttributeList::AT_ObjCRequiresSuper:
handleObjCRequiresSuperAttr(S, D, Attr);
break;
-
case AttributeList::AT_ObjCBridge:
handleObjCBridgeAttr(S, scope, D, Attr);
break;
-
case AttributeList::AT_ObjCBridgeMutable:
handleObjCBridgeMutableAttr(S, scope, D, Attr);
break;
-
case AttributeList::AT_ObjCBridgeRelated:
handleObjCBridgeRelatedAttr(S, scope, D, Attr);
break;
-
case AttributeList::AT_ObjCDesignatedInitializer:
handleObjCDesignatedInitializer(S, D, Attr);
break;
-
case AttributeList::AT_ObjCRuntimeName:
handleObjCRuntimeName(S, D, Attr);
break;
-
+ case AttributeList::AT_ObjCRuntimeVisible:
+ handleSimpleAttribute<ObjCRuntimeVisibleAttr>(S, D, Attr);
+ break;
case AttributeList::AT_ObjCBoxable:
handleObjCBoxable(S, D, Attr);
break;
-
case AttributeList::AT_CFAuditedTransfer:
handleCFAuditedTransferAttr(S, D, Attr);
break;
case AttributeList::AT_CFUnknownTransfer:
handleCFUnknownTransferAttr(S, D, Attr);
break;
-
case AttributeList::AT_CFConsumed:
case AttributeList::AT_NSConsumed:
handleNSConsumedAttr(S, D, Attr);
@@ -5195,7 +5613,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_NSConsumesSelf:
handleSimpleAttribute<NSConsumesSelfAttr>(S, D, Attr);
break;
-
case AttributeList::AT_NSReturnsAutoreleased:
case AttributeList::AT_NSReturnsNotRetained:
case AttributeList::AT_CFReturnsNotRetained:
@@ -5212,11 +5629,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_VecTypeHint:
handleVecTypeHint(S, D, Attr);
break;
-
case AttributeList::AT_InitPriority:
handleInitPriorityAttr(S, D, Attr);
break;
-
case AttributeList::AT_Packed:
handlePackedAttr(S, D, Attr);
break;
@@ -5242,7 +5657,7 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleSimpleAttribute<ObjCRequiresPropertyDefsAttr>(S, D, Attr);
break;
case AttributeList::AT_Unused:
- handleSimpleAttribute<UnusedAttr>(S, D, Attr);
+ handleUnusedAttr(S, D, Attr);
break;
case AttributeList::AT_ReturnsTwice:
handleSimpleAttribute<ReturnsTwiceAttr>(S, D, Attr);
@@ -5324,24 +5739,48 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_FastCall:
case AttributeList::AT_ThisCall:
case AttributeList::AT_Pascal:
+ case AttributeList::AT_SwiftCall:
case AttributeList::AT_VectorCall:
case AttributeList::AT_MSABI:
case AttributeList::AT_SysVABI:
case AttributeList::AT_Pcs:
case AttributeList::AT_IntelOclBicc:
+ case AttributeList::AT_PreserveMost:
+ case AttributeList::AT_PreserveAll:
handleCallConvAttr(S, D, Attr);
break;
case AttributeList::AT_OpenCLKernel:
handleSimpleAttribute<OpenCLKernelAttr>(S, D, Attr);
break;
- case AttributeList::AT_OpenCLImageAccess:
- handleSimpleAttribute<OpenCLImageAccessAttr>(S, D, Attr);
+ case AttributeList::AT_OpenCLAccess:
+ handleOpenCLAccessAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_OpenCLNoSVM:
+ handleOpenCLNoSVMAttr(S, D, Attr);
+ break;
+ case AttributeList::AT_SwiftContext:
+ handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftContext);
+ break;
+ case AttributeList::AT_SwiftErrorResult:
+ handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftErrorResult);
+ break;
+ case AttributeList::AT_SwiftIndirectResult:
+ handleParameterABIAttr(S, D, Attr, ParameterABI::SwiftIndirectResult);
break;
case AttributeList::AT_InternalLinkage:
handleInternalLinkageAttr(S, D, Attr);
break;
+ case AttributeList::AT_LTOVisibilityPublic:
+ handleSimpleAttribute<LTOVisibilityPublicAttr>(S, D, Attr);
+ break;
// Microsoft attributes:
+ case AttributeList::AT_EmptyBases:
+ handleSimpleAttribute<EmptyBasesAttr>(S, D, Attr);
+ break;
+ case AttributeList::AT_LayoutVersion:
+ handleLayoutVersion(S, D, Attr);
+ break;
case AttributeList::AT_MSNoVTable:
handleSimpleAttribute<MSNoVTableAttr>(S, D, Attr);
break;
@@ -5361,6 +5800,10 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
handleDeclspecThreadAttr(S, D, Attr);
break;
+ case AttributeList::AT_AbiTag:
+ handleAbiTagAttr(S, D, Attr);
+ break;
+
// Thread safety attributes:
case AttributeList::AT_AssertExclusiveLock:
handleAssertExclusiveLockAttr(S, D, Attr);
@@ -5466,6 +5909,13 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
case AttributeList::AT_TypeTagForDatatype:
handleTypeTagForDatatypeAttr(S, D, Attr);
break;
+ case AttributeList::AT_RenderScriptKernel:
+ handleSimpleAttribute<RenderScriptKernelAttr>(S, D, Attr);
+ break;
+ // XRay attributes.
+ case AttributeList::AT_XRayInstrument:
+ handleSimpleAttribute<XRayInstrumentAttr>(S, D, Attr);
+ break;
}
}
@@ -5744,7 +6194,6 @@ static void handleDelayedForbiddenType(Sema &S, DelayedDiagnostic &diag,
diag.Triggered = true;
}
-
static bool isDeclDeprecated(Decl *D) {
do {
if (D->isDeprecated())
@@ -5769,6 +6218,34 @@ static bool isDeclUnavailable(Decl *D) {
return false;
}
+static const AvailabilityAttr *getAttrForPlatform(ASTContext &Context,
+ const Decl *D) {
+ // Check each AvailabilityAttr to find the one for this platform.
+ for (const auto *A : D->attrs()) {
+ if (const auto *Avail = dyn_cast<AvailabilityAttr>(A)) {
+ // FIXME: this is copied from CheckAvailability. We should try to
+ // de-duplicate.
+
+ // Check if this is an App Extension "platform", and if so chop off
+ // the suffix for matching with the actual platform.
+ StringRef ActualPlatform = Avail->getPlatform()->getName();
+ StringRef RealizedPlatform = ActualPlatform;
+ if (Context.getLangOpts().AppExt) {
+ size_t suffix = RealizedPlatform.rfind("_app_extension");
+ if (suffix != StringRef::npos)
+ RealizedPlatform = RealizedPlatform.slice(0, suffix);
+ }
+
+ StringRef TargetPlatform = Context.getTargetInfo().getPlatformName();
+
+ // Match the platform name.
+ if (RealizedPlatform == TargetPlatform)
+ return Avail;
+ }
+ }
+ return nullptr;
+}
+
static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
Decl *Ctx, const NamedDecl *D,
StringRef Message, SourceLocation Loc,
@@ -5850,7 +6327,6 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
}
}
}
-
break;
case Sema::AD_Partial:
@@ -5862,23 +6338,61 @@ static void DoEmitAvailabilityWarning(Sema &S, Sema::AvailabilityDiagnostic K,
break;
}
+ CharSourceRange UseRange;
+ StringRef Replacement;
+ if (K == Sema::AD_Deprecation) {
+ if (auto attr = D->getAttr<DeprecatedAttr>())
+ Replacement = attr->getReplacement();
+ if (auto attr = getAttrForPlatform(S.Context, D))
+ Replacement = attr->getReplacement();
+
+ if (!Replacement.empty())
+ UseRange =
+ CharSourceRange::getCharRange(Loc, S.getLocForEndOfToken(Loc));
+ }
+
if (!Message.empty()) {
- S.Diag(Loc, diag_message) << D << Message;
+ S.Diag(Loc, diag_message) << D << Message
+ << (UseRange.isValid() ?
+ FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else if (!UnknownObjCClass) {
- S.Diag(Loc, diag) << D;
+ S.Diag(Loc, diag) << D
+ << (UseRange.isValid() ?
+ FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
if (ObjCProperty)
S.Diag(ObjCProperty->getLocation(), diag::note_property_attribute)
<< ObjCProperty->getDeclName() << property_note_select;
} else {
- S.Diag(Loc, diag_fwdclass_message) << D;
+ S.Diag(Loc, diag_fwdclass_message) << D
+ << (UseRange.isValid() ?
+ FixItHint::CreateReplacement(UseRange, Replacement) : FixItHint());
S.Diag(UnknownObjCClass->getLocation(), diag::note_forward_class);
}
- S.Diag(D->getLocation(), diag_available_here)
- << D << available_here_select_kind;
+ // The declaration can have multiple availability attributes, we are looking
+ // at one of them.
+ const AvailabilityAttr *A = getAttrForPlatform(S.Context, D);
+ if (A && A->isInherited()) {
+ for (const Decl *Redecl = D->getMostRecentDecl(); Redecl;
+ Redecl = Redecl->getPreviousDecl()) {
+ const AvailabilityAttr *AForRedecl = getAttrForPlatform(S.Context,
+ Redecl);
+ if (AForRedecl && !AForRedecl->isInherited()) {
+ // If D is a declaration with inherited attributes, the note should
+ // point to the declaration with actual attributes.
+ S.Diag(Redecl->getLocation(), diag_available_here) << D
+ << available_here_select_kind;
+ break;
+ }
+ }
+ }
+ else
+ S.Diag(D->getLocation(), diag_available_here)
+ << D << available_here_select_kind;
+
if (K == Sema::AD_Partial)
S.Diag(Loc, diag::note_partial_availability_silence) << D;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
index 82d81a85fa90..e161c87f1739 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclCXX.cpp
@@ -471,7 +471,7 @@ bool Sema::MergeCXXFunctionDecl(FunctionDecl *New, FunctionDecl *Old,
continue;
}
- // We found our guy.
+ // We found the right previous declaration.
break;
}
@@ -3356,34 +3356,7 @@ BuildImplicitBaseInitializer(Sema &SemaRef, CXXConstructorDecl *Constructor,
ExprResult BaseInit;
switch (ImplicitInitKind) {
- case IIK_Inherit: {
- const CXXRecordDecl *Inherited =
- Constructor->getInheritedConstructor()->getParent();
- const CXXRecordDecl *Base = BaseSpec->getType()->getAsCXXRecordDecl();
- if (Base && Inherited->getCanonicalDecl() == Base->getCanonicalDecl()) {
- // C++11 [class.inhctor]p8:
- // Each expression in the expression-list is of the form
- // static_cast<T&&>(p), where p is the name of the corresponding
- // constructor parameter and T is the declared type of p.
- SmallVector<Expr*, 16> Args;
- for (unsigned I = 0, E = Constructor->getNumParams(); I != E; ++I) {
- ParmVarDecl *PD = Constructor->getParamDecl(I);
- ExprResult ArgExpr =
- SemaRef.BuildDeclRefExpr(PD, PD->getType().getNonReferenceType(),
- VK_LValue, SourceLocation());
- if (ArgExpr.isInvalid())
- return true;
- Args.push_back(CastForMoving(SemaRef, ArgExpr.get(), PD->getType()));
- }
-
- InitializationKind InitKind = InitializationKind::CreateDirect(
- Constructor->getLocation(), SourceLocation(), SourceLocation());
- InitializationSequence InitSeq(SemaRef, InitEntity, InitKind, Args);
- BaseInit = InitSeq.Perform(SemaRef, InitEntity, InitKind, Args);
- break;
- }
- }
- // Fall through.
+ case IIK_Inherit:
case IIK_Default: {
InitializationKind InitKind
= InitializationKind::CreateDefault(Constructor->getLocation());
@@ -3694,12 +3667,12 @@ struct BaseAndFieldInfo {
BaseAndFieldInfo(Sema &S, CXXConstructorDecl *Ctor, bool ErrorsInInits)
: S(S), Ctor(Ctor), AnyErrorsInInits(ErrorsInInits) {
bool Generated = Ctor->isImplicit() || Ctor->isDefaulted();
- if (Generated && Ctor->isCopyConstructor())
+ if (Ctor->getInheritedConstructor())
+ IIK = IIK_Inherit;
+ else if (Generated && Ctor->isCopyConstructor())
IIK = IIK_Copy;
else if (Generated && Ctor->isMoveConstructor())
IIK = IIK_Move;
- else if (Ctor->getInheritedConstructor())
- IIK = IIK_Inherit;
else
IIK = IIK_Default;
}
@@ -4774,7 +4747,6 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
// The class is either imported or exported.
const bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
- const bool ClassImported = !ClassExported;
TemplateSpecializationKind TSK = Class->getTemplateSpecializationKind();
@@ -4809,11 +4781,20 @@ void Sema::checkClassLevelDLLAttribute(CXXRecordDecl *Class) {
if (!Context.getTargetInfo().getCXXABI().isMicrosoft())
continue;
- // MSVC versions before 2015 don't export the move assignment operators,
- // so don't attempt to import them if we have a definition.
- if (ClassImported && MD->isMoveAssignmentOperator() &&
+ // MSVC versions before 2015 don't export the move assignment operators
+ // and move constructor, so don't attempt to import/export them if
+ // we have a definition.
+ auto *Ctor = dyn_cast<CXXConstructorDecl>(MD);
+ if ((MD->isMoveAssignmentOperator() ||
+ (Ctor && Ctor->isMoveConstructor())) &&
!getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015))
continue;
+
+ // MSVC2015 doesn't export trivial defaulted x-tor but copy assign
+ // operator is exported anyway.
+ if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ (Ctor || isa<CXXDestructorDecl>(MD)) && MD->isTrivial())
+ continue;
}
}
@@ -4887,6 +4868,33 @@ void Sema::propagateDLLAttrToBaseClassTemplate(
}
}
+static void DefineImplicitSpecialMember(Sema &S, CXXMethodDecl *MD,
+ SourceLocation DefaultLoc) {
+ switch (S.getSpecialMember(MD)) {
+ case Sema::CXXDefaultConstructor:
+ S.DefineImplicitDefaultConstructor(DefaultLoc,
+ cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXCopyConstructor:
+ S.DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXCopyAssignment:
+ S.DefineImplicitCopyAssignment(DefaultLoc, MD);
+ break;
+ case Sema::CXXDestructor:
+ S.DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
+ break;
+ case Sema::CXXMoveConstructor:
+ S.DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
+ break;
+ case Sema::CXXMoveAssignment:
+ S.DefineImplicitMoveAssignment(DefaultLoc, MD);
+ break;
+ case Sema::CXXInvalid:
+ llvm_unreachable("Invalid special member.");
+ }
+}
+
/// \brief Perform semantic checks on a class definition that has been
/// completing, introducing implicitly-declared members, checking for
/// abstract types, etc.
@@ -4982,8 +4990,8 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
// For an explicitly defaulted or deleted special member, we defer
// determining triviality until the class is complete. That time is now!
+ CXXSpecialMember CSM = getSpecialMember(M);
if (!M->isImplicit() && !M->isUserProvided()) {
- CXXSpecialMember CSM = getSpecialMember(M);
if (CSM != CXXInvalid) {
M->setTrivial(SpecialMemberIsTrivial(M, CSM));
@@ -4991,6 +4999,20 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Record->finishedDefaultedOrDeletedMember(M);
}
}
+
+ if (!M->isInvalidDecl() && M->isExplicitlyDefaulted() &&
+ M->hasAttr<DLLExportAttr>()) {
+ if (getLangOpts().isCompatibleWithMSVC(LangOptions::MSVC2015) &&
+ M->isTrivial() &&
+ (CSM == CXXDefaultConstructor || CSM == CXXCopyConstructor ||
+ CSM == CXXDestructor))
+ M->dropAttr<DLLExportAttr>();
+
+ if (M->hasAttr<DLLExportAttr>()) {
+ DefineImplicitSpecialMember(*this, M, M->getLocation());
+ ActOnFinishInlineFunctionDef(M);
+ }
+ }
}
}
@@ -5016,15 +5038,6 @@ void Sema::CheckCompletedCXXClass(CXXRecordDecl *Record) {
Diag(Record->getLocation(), diag::warn_cxx_ms_struct);
}
- // Declare inheriting constructors. We do this eagerly here because:
- // - The standard requires an eager diagnostic for conflicting inheriting
- // constructors from different classes.
- // - The lazy declaration of the other implicit constructors is so as to not
- // waste space and performance on classes that are not meant to be
- // instantiated (e.g. meta-functions). This doesn't apply to classes that
- // have inheriting constructors.
- DeclareInheritingConstructors(Record);
-
checkClassLevelDLLAttribute(Record);
}
@@ -5058,11 +5071,108 @@ static Sema::SpecialMemberOverloadResult *lookupCallFromSpecialMember(
LHSQuals & Qualifiers::Volatile);
}
+class Sema::InheritedConstructorInfo {
+ Sema &S;
+ SourceLocation UseLoc;
+
+ /// A mapping from the base classes through which the constructor was
+ /// inherited to the using shadow declaration in that base class (or a null
+ /// pointer if the constructor was declared in that base class).
+ llvm::DenseMap<CXXRecordDecl *, ConstructorUsingShadowDecl *>
+ InheritedFromBases;
+
+public:
+ InheritedConstructorInfo(Sema &S, SourceLocation UseLoc,
+ ConstructorUsingShadowDecl *Shadow)
+ : S(S), UseLoc(UseLoc) {
+ bool DiagnosedMultipleConstructedBases = false;
+ CXXRecordDecl *ConstructedBase = nullptr;
+ UsingDecl *ConstructedBaseUsing = nullptr;
+
+ // Find the set of such base class subobjects and check that there's a
+ // unique constructed subobject.
+ for (auto *D : Shadow->redecls()) {
+ auto *DShadow = cast<ConstructorUsingShadowDecl>(D);
+ auto *DNominatedBase = DShadow->getNominatedBaseClass();
+ auto *DConstructedBase = DShadow->getConstructedBaseClass();
+
+ InheritedFromBases.insert(
+ std::make_pair(DNominatedBase->getCanonicalDecl(),
+ DShadow->getNominatedBaseClassShadowDecl()));
+ if (DShadow->constructsVirtualBase())
+ InheritedFromBases.insert(
+ std::make_pair(DConstructedBase->getCanonicalDecl(),
+ DShadow->getConstructedBaseClassShadowDecl()));
+ else
+ assert(DNominatedBase == DConstructedBase);
+
+ // [class.inhctor.init]p2:
+ // If the constructor was inherited from multiple base class subobjects
+ // of type B, the program is ill-formed.
+ if (!ConstructedBase) {
+ ConstructedBase = DConstructedBase;
+ ConstructedBaseUsing = D->getUsingDecl();
+ } else if (ConstructedBase != DConstructedBase &&
+ !Shadow->isInvalidDecl()) {
+ if (!DiagnosedMultipleConstructedBases) {
+ S.Diag(UseLoc, diag::err_ambiguous_inherited_constructor)
+ << Shadow->getTargetDecl();
+ S.Diag(ConstructedBaseUsing->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << ConstructedBase;
+ DiagnosedMultipleConstructedBases = true;
+ }
+ S.Diag(D->getUsingDecl()->getLocation(),
+ diag::note_ambiguous_inherited_constructor_using)
+ << DConstructedBase;
+ }
+ }
+
+ if (DiagnosedMultipleConstructedBases)
+ Shadow->setInvalidDecl();
+ }
+
+ /// Find the constructor to use for inherited construction of a base class,
+ /// and whether that base class constructor inherits the constructor from a
+ /// virtual base class (in which case it won't actually invoke it).
+ std::pair<CXXConstructorDecl *, bool>
+ findConstructorForBase(CXXRecordDecl *Base, CXXConstructorDecl *Ctor) const {
+ auto It = InheritedFromBases.find(Base->getCanonicalDecl());
+ if (It == InheritedFromBases.end())
+ return std::make_pair(nullptr, false);
+
+ // This is an intermediary class.
+ if (It->second)
+ return std::make_pair(
+ S.findInheritingConstructor(UseLoc, Ctor, It->second),
+ It->second->constructsVirtualBase());
+
+ // This is the base class from which the constructor was inherited.
+ return std::make_pair(Ctor, false);
+ }
+};
+
/// Is the special member function which would be selected to perform the
/// specified operation on the specified class type a constexpr constructor?
-static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
- Sema::CXXSpecialMember CSM,
- unsigned Quals, bool ConstRHS) {
+static bool
+specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
+ Sema::CXXSpecialMember CSM, unsigned Quals,
+ bool ConstRHS,
+ CXXConstructorDecl *InheritedCtor = nullptr,
+ Sema::InheritedConstructorInfo *Inherited = nullptr) {
+ // If we're inheriting a constructor, see if we need to call it for this base
+ // class.
+ if (InheritedCtor) {
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto BaseCtor =
+ Inherited->findConstructorForBase(ClassDecl, InheritedCtor).first;
+ if (BaseCtor)
+ return BaseCtor->isConstexpr();
+ }
+
+ if (CSM == Sema::CXXDefaultConstructor)
+ return ClassDecl->hasConstexprDefaultConstructor();
+
Sema::SpecialMemberOverloadResult *SMOR =
lookupCallFromSpecialMember(S, ClassDecl, CSM, Quals, ConstRHS);
if (!SMOR || !SMOR->getMethod())
@@ -5074,9 +5184,10 @@ static bool specialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
/// Determine whether the specified special member function would be constexpr
/// if it were implicitly defined.
-static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
- Sema::CXXSpecialMember CSM,
- bool ConstArg) {
+static bool defaultedSpecialMemberIsConstexpr(
+ Sema &S, CXXRecordDecl *ClassDecl, Sema::CXXSpecialMember CSM,
+ bool ConstArg, CXXConstructorDecl *InheritedCtor = nullptr,
+ Sema::InheritedConstructorInfo *Inherited = nullptr) {
if (!S.getLangOpts().CPlusPlus11)
return false;
@@ -5085,6 +5196,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
bool Ctor = true;
switch (CSM) {
case Sema::CXXDefaultConstructor:
+ if (Inherited)
+ break;
// Since default constructor lookup is essentially trivial (and cannot
// involve, for instance, template instantiation), we compute whether a
// defaulted default constructor is constexpr directly within CXXRecordDecl.
@@ -5119,7 +5232,10 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
// will be initialized (if the constructor isn't deleted), we just don't know
// which one.
if (Ctor && ClassDecl->isUnion())
- return true;
+ return CSM == Sema::CXXDefaultConstructor
+ ? ClassDecl->hasInClassInitializer() ||
+ !ClassDecl->hasVariantMembers()
+ : true;
// -- the class shall not have any virtual base classes;
if (Ctor && ClassDecl->getNumVBases())
@@ -5139,7 +5255,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
if (!BaseType) continue;
CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg))
+ if (!specialMemberIsConstexpr(S, BaseClassDecl, CSM, 0, ConstArg,
+ InheritedCtor, Inherited))
return false;
}
@@ -5153,6 +5270,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
for (const auto *F : ClassDecl->fields()) {
if (F->isInvalidDecl())
continue;
+ if (CSM == Sema::CXXDefaultConstructor && F->hasInClassInitializer())
+ continue;
QualType BaseType = S.Context.getBaseElementType(F->getType());
if (const RecordType *RecordTy = BaseType->getAs<RecordType>()) {
CXXRecordDecl *FieldRecDecl = cast<CXXRecordDecl>(RecordTy->getDecl());
@@ -5160,6 +5279,8 @@ static bool defaultedSpecialMemberIsConstexpr(Sema &S, CXXRecordDecl *ClassDecl,
BaseType.getCVRQualifiers(),
ConstArg && !F->isMutable()))
return false;
+ } else if (CSM == Sema::CXXDefaultConstructor) {
+ return false;
}
}
@@ -5187,7 +5308,8 @@ computeImplicitExceptionSpec(Sema &S, SourceLocation Loc, CXXMethodDecl *MD) {
}
assert(cast<CXXConstructorDecl>(MD)->getInheritedConstructor() &&
"only special members have implicit exception specs");
- return S.ComputeInheritingCtorExceptionSpec(cast<CXXConstructorDecl>(MD));
+ return S.ComputeInheritingCtorExceptionSpec(Loc,
+ cast<CXXConstructorDecl>(MD));
}
static FunctionProtoType::ExtProtoInfo getImplicitMethodEPI(Sema &S,
@@ -5384,7 +5506,7 @@ void Sema::CheckExplicitlyDefaultedSpecialMember(CXXMethodDecl *MD) {
// [For a] user-provided explicitly-defaulted function [...] if such a
// function is implicitly defined as deleted, the program is ill-formed.
Diag(MD->getLocation(), diag::err_out_of_line_default_deletes) << CSM;
- ShouldDeleteSpecialMember(MD, CSM, /*Diagnose*/true);
+ ShouldDeleteSpecialMember(MD, CSM, nullptr, /*Diagnose*/true);
HadError = true;
}
}
@@ -5445,6 +5567,7 @@ struct SpecialMemberDeletionInfo {
Sema &S;
CXXMethodDecl *MD;
Sema::CXXSpecialMember CSM;
+ Sema::InheritedConstructorInfo *ICI;
bool Diagnose;
// Properties of the special member, computed for convenience.
@@ -5454,11 +5577,11 @@ struct SpecialMemberDeletionInfo {
bool AllFieldsAreConst;
SpecialMemberDeletionInfo(Sema &S, CXXMethodDecl *MD,
- Sema::CXXSpecialMember CSM, bool Diagnose)
- : S(S), MD(MD), CSM(CSM), Diagnose(Diagnose),
- IsConstructor(false), IsAssignment(false), IsMove(false),
- ConstArg(false), Loc(MD->getLocation()),
- AllFieldsAreConst(true) {
+ Sema::CXXSpecialMember CSM,
+ Sema::InheritedConstructorInfo *ICI, bool Diagnose)
+ : S(S), MD(MD), CSM(CSM), ICI(ICI), Diagnose(Diagnose),
+ IsConstructor(false), IsAssignment(false), IsMove(false),
+ ConstArg(false), Loc(MD->getLocation()), AllFieldsAreConst(true) {
switch (CSM) {
case Sema::CXXDefaultConstructor:
case Sema::CXXCopyConstructor:
@@ -5490,6 +5613,10 @@ struct SpecialMemberDeletionInfo {
bool inUnion() const { return MD->getParent()->isUnion(); }
+ Sema::CXXSpecialMember getEffectiveCSM() {
+ return ICI ? Sema::CXXInvalid : CSM;
+ }
+
/// Look up the corresponding special member in the given class.
Sema::SpecialMemberOverloadResult *lookupIn(CXXRecordDecl *Class,
unsigned Quals, bool IsMutable) {
@@ -5566,13 +5693,13 @@ bool SpecialMemberDeletionInfo::shouldDeleteForSubobjectCall(
if (Field) {
S.Diag(Field->getLocation(),
diag::note_deleted_special_member_class_subobject)
- << CSM << MD->getParent() << /*IsField*/true
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/true
<< Field << DiagKind << IsDtorCallInCtor;
} else {
CXXBaseSpecifier *Base = Subobj.get<CXXBaseSpecifier*>();
S.Diag(Base->getLocStart(),
diag::note_deleted_special_member_class_subobject)
- << CSM << MD->getParent() << /*IsField*/false
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/false
<< Base->getType() << DiagKind << IsDtorCallInCtor;
}
@@ -5631,7 +5758,29 @@ bool SpecialMemberDeletionInfo::shouldDeleteForBase(CXXBaseSpecifier *Base) {
CXXRecordDecl *BaseClass = Base->getType()->getAsCXXRecordDecl();
// If program is correct, BaseClass cannot be null, but if it is, the error
// must be reported elsewhere.
- return BaseClass && shouldDeleteForClassSubobject(BaseClass, Base, 0);
+ if (!BaseClass)
+ return false;
+ // If we have an inheriting constructor, check whether we're calling an
+ // inherited constructor instead of a default constructor.
+ if (ICI) {
+ assert(CSM == Sema::CXXDefaultConstructor);
+ auto *BaseCtor =
+ ICI->findConstructorForBase(BaseClass, cast<CXXConstructorDecl>(MD)
+ ->getInheritedConstructor()
+ .getConstructor())
+ .first;
+ if (BaseCtor) {
+ if (BaseCtor->isDeleted() && Diagnose) {
+ S.Diag(Base->getLocStart(),
+ diag::note_deleted_special_member_class_subobject)
+ << getEffectiveCSM() << MD->getParent() << /*IsField*/false
+ << Base->getType() << /*Deleted*/1 << /*IsDtorCallInCtor*/false;
+ S.NoteDeletedFunction(BaseCtor);
+ }
+ return BaseCtor->isDeleted();
+ }
+ }
+ return shouldDeleteForClassSubobject(BaseClass, Base, 0);
}
/// Check whether we should delete a special member function due to the class
@@ -5646,7 +5795,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (FieldType->isReferenceType() && !FD->hasInClassInitializer()) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
- << MD->getParent() << FD << FieldType << /*Reference*/0;
+ << !!ICI << MD->getParent() << FD << FieldType << /*Reference*/0;
return true;
}
// C++11 [class.ctor]p5: any non-variant non-static data member of
@@ -5658,7 +5807,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
(!FieldRecord || !FieldRecord->hasUserProvidedDefaultConstructor())) {
if (Diagnose)
S.Diag(FD->getLocation(), diag::note_deleted_default_ctor_uninit_field)
- << MD->getParent() << FD << FD->getType() << /*Const*/1;
+ << !!ICI << MD->getParent() << FD << FD->getType() << /*Const*/1;
return true;
}
@@ -5717,7 +5866,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForField(FieldDecl *FD) {
if (Diagnose)
S.Diag(FieldRecord->getLocation(),
diag::note_deleted_default_ctor_all_const)
- << MD->getParent() << /*anonymous union*/1;
+ << !!ICI << MD->getParent() << /*anonymous union*/1;
return true;
}
@@ -5745,7 +5894,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
if (Diagnose)
S.Diag(MD->getParent()->getLocation(),
diag::note_deleted_default_ctor_all_const)
- << MD->getParent() << /*not anonymous union*/0;
+ << !!ICI << MD->getParent() << /*not anonymous union*/0;
return true;
}
return false;
@@ -5755,6 +5904,7 @@ bool SpecialMemberDeletionInfo::shouldDeleteForAllConstMembers() {
/// deleted, as specified in C++11 [class.ctor]p5, C++11 [class.copy]p11,
/// C++11 [class.copy]p23, and C++11 [class.dtor]p5.
bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
+ InheritedConstructorInfo *ICI,
bool Diagnose) {
if (MD->isInvalidDecl())
return false;
@@ -5844,7 +5994,7 @@ bool Sema::ShouldDeleteSpecialMember(CXXMethodDecl *MD, CXXSpecialMember CSM,
}
}
- SpecialMemberDeletionInfo SMI(*this, MD, CSM, Diagnose);
+ SpecialMemberDeletionInfo SMI(*this, MD, CSM, ICI, Diagnose);
for (auto &BI : RD->bases())
if (!BI.isVirtual() &&
@@ -6452,27 +6602,33 @@ void Sema::ActOnFinishCXXMemberSpecification(Scope* S, SourceLocation RLoc,
/// [special]p1). This routine can only be executed just before the
/// definition of the class is complete.
void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
- if (!ClassDecl->hasUserDeclaredConstructor())
+ if (ClassDecl->needsImplicitDefaultConstructor()) {
++ASTContext::NumImplicitDefaultConstructors;
- if (!ClassDecl->hasUserDeclaredCopyConstructor()) {
+ if (ClassDecl->hasInheritedConstructor())
+ DeclareImplicitDefaultConstructor(ClassDecl);
+ }
+
+ if (ClassDecl->needsImplicitCopyConstructor()) {
++ASTContext::NumImplicitCopyConstructors;
// If the properties or semantics of the copy constructor couldn't be
// determined while the class was being declared, force a declaration
// of it now.
- if (ClassDecl->needsOverloadResolutionForCopyConstructor())
+ if (ClassDecl->needsOverloadResolutionForCopyConstructor() ||
+ ClassDecl->hasInheritedConstructor())
DeclareImplicitCopyConstructor(ClassDecl);
}
if (getLangOpts().CPlusPlus11 && ClassDecl->needsImplicitMoveConstructor()) {
++ASTContext::NumImplicitMoveConstructors;
- if (ClassDecl->needsOverloadResolutionForMoveConstructor())
+ if (ClassDecl->needsOverloadResolutionForMoveConstructor() ||
+ ClassDecl->hasInheritedConstructor())
DeclareImplicitMoveConstructor(ClassDecl);
}
- if (!ClassDecl->hasUserDeclaredCopyAssignment()) {
+ if (ClassDecl->needsImplicitCopyAssignment()) {
++ASTContext::NumImplicitCopyAssignmentOperators;
// If we have a dynamic class, then the copy assignment operator may be
@@ -6480,7 +6636,8 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// it shows up in the right place in the vtable and that we diagnose
// problems with the implicit exception specification.
if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForCopyAssignment())
+ ClassDecl->needsOverloadResolutionForCopyAssignment() ||
+ ClassDecl->hasInheritedAssignment())
DeclareImplicitCopyAssignment(ClassDecl);
}
@@ -6489,11 +6646,12 @@ void Sema::AddImplicitlyDeclaredMembersToClass(CXXRecordDecl *ClassDecl) {
// Likewise for the move assignment operator.
if (ClassDecl->isDynamicClass() ||
- ClassDecl->needsOverloadResolutionForMoveAssignment())
+ ClassDecl->needsOverloadResolutionForMoveAssignment() ||
+ ClassDecl->hasInheritedAssignment())
DeclareImplicitMoveAssignment(ClassDecl);
}
- if (!ClassDecl->hasUserDeclaredDestructor()) {
+ if (ClassDecl->needsImplicitDestructor()) {
++ASTContext::NumImplicitDestructors;
// If we have a dynamic class, then the destructor may be virtual, so we
@@ -7738,7 +7896,7 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
// function will silently decide not to build a shadow decl, which
// will pre-empt further diagnostics.
//
- // We don't need to do this in C++0x because we do the check once on
+ // We don't need to do this in C++11 because we do the check once on
// the qualifier.
//
// FIXME: diagnose the following if we care enough:
@@ -7796,6 +7954,12 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
for (LookupResult::iterator I = Previous.begin(), E = Previous.end();
I != E; ++I) {
NamedDecl *D = (*I)->getUnderlyingDecl();
+ // We can have UsingDecls in our Previous results because we use the same
+ // LookupResult for checking whether the UsingDecl itself is a valid
+ // redeclaration.
+ if (isa<UsingDecl>(D))
+ continue;
+
if (IsEquivalentForUsingDecl(Context, D, Target)) {
if (UsingShadowDecl *Shadow = dyn_cast<UsingShadowDecl>(*I))
PrevShadow = Shadow;
@@ -7863,12 +8027,21 @@ bool Sema::CheckUsingShadowDecl(UsingDecl *Using, NamedDecl *Orig,
return true;
}
+/// Determine whether a direct base class is a virtual base class.
+static bool isVirtualDirectBase(CXXRecordDecl *Derived, CXXRecordDecl *Base) {
+ if (!Derived->getNumVBases())
+ return false;
+ for (auto &B : Derived->bases())
+ if (B.getType()->getAsCXXRecordDecl() == Base)
+ return B.isVirtual();
+ llvm_unreachable("not a direct base class");
+}
+
/// Builds a shadow declaration corresponding to a 'using' declaration.
UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
UsingDecl *UD,
NamedDecl *Orig,
UsingShadowDecl *PrevDecl) {
-
// If we resolved to another shadow declaration, just coalesce them.
NamedDecl *Target = Orig;
if (isa<UsingShadowDecl>(Target)) {
@@ -7876,9 +8049,21 @@ UsingShadowDecl *Sema::BuildUsingShadowDecl(Scope *S,
assert(!isa<UsingShadowDecl>(Target) && "nested shadow declaration");
}
- UsingShadowDecl *Shadow
- = UsingShadowDecl::Create(Context, CurContext,
- UD->getLocation(), UD, Target);
+ NamedDecl *NonTemplateTarget = Target;
+ if (auto *TargetTD = dyn_cast<TemplateDecl>(Target))
+ NonTemplateTarget = TargetTD->getTemplatedDecl();
+
+ UsingShadowDecl *Shadow;
+ if (isa<CXXConstructorDecl>(NonTemplateTarget)) {
+ bool IsVirtualBase =
+ isVirtualDirectBase(cast<CXXRecordDecl>(CurContext),
+ UD->getQualifier()->getAsRecordDecl());
+ Shadow = ConstructorUsingShadowDecl::Create(
+ Context, CurContext, UD->getLocation(), UD, Orig, IsVirtualBase);
+ } else {
+ Shadow = UsingShadowDecl::Create(Context, CurContext, UD->getLocation(), UD,
+ Target);
+ }
UD->addShadowDecl(Shadow);
Shadow->setAccess(UD->getAccess());
@@ -7980,6 +8165,9 @@ public:
if (Candidate.WillReplaceSpecifier() && !Candidate.getCorrectionSpecifier())
return false;
+ // FIXME: Don't correct to a name that CheckUsingDeclRedeclaration would
+ // reject.
+
if (RequireMemberOf) {
auto *FoundRecord = dyn_cast<CXXRecordDecl>(ND);
if (FoundRecord && FoundRecord->isInjectedClassName()) {
@@ -8060,8 +8248,17 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return nullptr;
}
+ // For an inheriting constructor declaration, the name of the using
+ // declaration is the name of a constructor in this class, not in the
+ // base class.
+ DeclarationNameInfo UsingName = NameInfo;
+ if (UsingName.getName().getNameKind() == DeclarationName::CXXConstructorName)
+ if (auto *RD = dyn_cast<CXXRecordDecl>(CurContext))
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(RD))));
+
// Do the redeclaration lookup in the current scope.
- LookupResult Previous(*this, NameInfo, LookupUsingDeclName,
+ LookupResult Previous(*this, UsingName, LookupUsingDeclName,
ForRedeclaration);
Previous.setHideTags(false);
if (S) {
@@ -8118,8 +8315,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
auto Build = [&](bool Invalid) {
UsingDecl *UD =
- UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc, NameInfo,
- HasTypenameKeyword);
+ UsingDecl::Create(Context, CurContext, UsingLoc, QualifierLoc,
+ UsingName, HasTypenameKeyword);
UD->setAccess(AS);
CurContext->addDecl(UD);
UD->setInvalidDecl(Invalid);
@@ -8174,6 +8371,9 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
// If we corrected to an inheriting constructor, handle it as one.
auto *RD = dyn_cast<CXXRecordDecl>(ND);
if (RD && RD->isInjectedClassName()) {
+ // The parent of the injected class name is the class itself.
+ RD = cast<CXXRecordDecl>(RD->getParent());
+
// Fix up the information we'll use to build the using declaration.
if (Corrected.WillReplaceSpecifier()) {
NestedNameSpecifierLocBuilder Builder;
@@ -8182,13 +8382,19 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
QualifierLoc = Builder.getWithLocInContext(Context);
}
- NameInfo.setName(Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(RD))));
- NameInfo.setNamedTypeInfo(nullptr);
+ // In this case, the name we introduce is the name of a derived class
+ // constructor.
+ auto *CurClass = cast<CXXRecordDecl>(CurContext);
+ UsingName.setName(Context.DeclarationNames.getCXXConstructorName(
+ Context.getCanonicalType(Context.getRecordType(CurClass))));
+ UsingName.setNamedTypeInfo(nullptr);
for (auto *Ctor : LookupConstructors(RD))
R.addDecl(Ctor);
+ R.resolveKind();
} else {
- // FIXME: Pick up all the declarations if we found an overloaded function.
+ // FIXME: Pick up all the declarations if we found an overloaded
+ // function.
+ UsingName.setName(ND->getDeclName());
R.addDecl(ND);
}
} else {
@@ -8221,7 +8427,7 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
}
}
- // C++0x N2914 [namespace.udecl]p6:
+ // C++14 [namespace.udecl]p6:
// A using-declaration shall not name a namespace.
if (R.getAsSingle<NamespaceDecl>()) {
Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_namespace)
@@ -8229,19 +8435,28 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
return BuildInvalid();
}
+ // C++14 [namespace.udecl]p7:
+ // A using-declaration shall not name a scoped enumerator.
+ if (auto *ED = R.getAsSingle<EnumConstantDecl>()) {
+ if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) {
+ Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum)
+ << SS.getRange();
+ return BuildInvalid();
+ }
+ }
+
UsingDecl *UD = BuildValid();
- // The normal rules do not apply to inheriting constructor declarations.
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ // Some additional rules apply to inheriting constructors.
+ if (UsingName.getName().getNameKind() ==
+ DeclarationName::CXXConstructorName) {
// Suppress access diagnostics; the access check is instead performed at the
// point of use for an inheriting constructor.
R.suppressDiagnostics();
- CheckInheritingConstructorUsingDecl(UD);
- return UD;
+ if (CheckInheritingConstructorUsingDecl(UD))
+ return UD;
}
- // Otherwise, look up the target name.
-
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I) {
UsingShadowDecl *PrevDecl = nullptr;
if (!CheckUsingShadowDecl(UD, *I, Previous, PrevDecl))
@@ -8353,8 +8568,10 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
// If we weren't able to compute a valid scope, it must be a
// dependent class scope.
- if (!NamedContext || NamedContext->isRecord()) {
- auto *RD = dyn_cast_or_null<CXXRecordDecl>(NamedContext);
+ if (!NamedContext || NamedContext->getRedeclContext()->isRecord()) {
+ auto *RD = NamedContext
+ ? cast<CXXRecordDecl>(NamedContext->getRedeclContext())
+ : nullptr;
if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
RD = nullptr;
@@ -8403,6 +8620,20 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
<< 2 // reference declaration
<< FixIt;
+ } else if (R.getAsSingle<EnumConstantDecl>()) {
+ // Don't provide a fixit outside C++11 mode; we don't want to suggest
+ // repeating the type of the enumeration here, and we can't do so if
+ // the type is anonymous.
+ FixItHint FixIt;
+ if (getLangOpts().CPlusPlus11) {
+ // Convert 'using X::Y;' to 'auto &Y = X::Y;'.
+ FixIt = FixItHint::CreateReplacement(
+ UsingLoc, "constexpr auto " + NameInfo.getName().getAsString() + " = ");
+ }
+
+ Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
+ << (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable
+ << FixIt;
}
return true;
}
@@ -8438,7 +8669,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
return true;
if (getLangOpts().CPlusPlus11) {
- // C++0x [namespace.udecl]p3:
+ // C++11 [namespace.udecl]p3:
// In a using-declaration used as a member-declaration, the
// nested-name-specifier shall name a base class of the class
// being defined.
@@ -8579,6 +8810,10 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
}
TemplateParameterList *TemplateParams = TemplateParamLists[0];
+ // Check that we can declare a template here.
+ if (CheckTemplateDeclScope(S, TemplateParams))
+ return nullptr;
+
// Only consider previous declarations in the same scope.
FilterLookupForScope(Previous, CurContext, S, /*ConsiderLinkage*/false,
/*ExplicitInstantiationOrSpecialization*/false);
@@ -8650,9 +8885,7 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S,
NewND = NewTD;
}
- if (!Redeclaration)
- PushOnScopeChains(NewND, S);
-
+ PushOnScopeChains(NewND, S);
ActOnDocumentableDecl(NewND);
return NewND;
}
@@ -8796,7 +9029,8 @@ Sema::ComputeDefaultedDefaultCtorExceptionSpec(SourceLocation Loc,
}
Sema::ImplicitExceptionSpecification
-Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
+Sema::ComputeInheritingCtorExceptionSpec(SourceLocation Loc,
+ CXXConstructorDecl *CD) {
CXXRecordDecl *ClassDecl = CD->getParent();
// C++ [except.spec]p14:
@@ -8805,36 +9039,26 @@ Sema::ComputeInheritingCtorExceptionSpec(CXXConstructorDecl *CD) {
if (ClassDecl->isInvalidDecl())
return ExceptSpec;
- // Inherited constructor.
- const CXXConstructorDecl *InheritedCD = CD->getInheritedConstructor();
- const CXXRecordDecl *InheritedDecl = InheritedCD->getParent();
- // FIXME: Copying or moving the parameters could add extra exceptions to the
- // set, as could the default arguments for the inherited constructor. This
- // will be addressed when we implement the resolution of core issue 1351.
- ExceptSpec.CalledDecl(CD->getLocStart(), InheritedCD);
+ auto Inherited = CD->getInheritedConstructor();
+ InheritedConstructorInfo ICI(*this, Loc, Inherited.getShadowDecl());
- // Direct base-class constructors.
- for (const auto &B : ClassDecl->bases()) {
- if (B.isVirtual()) // Handled below.
- continue;
-
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (BaseClassDecl == InheritedDecl)
+ // Direct and virtual base-class constructors.
+ for (bool VBase : {false, true}) {
+ for (CXXBaseSpecifier &B :
+ VBase ? ClassDecl->vbases() : ClassDecl->bases()) {
+ // Don't visit direct vbases twice.
+ if (B.isVirtual() != VBase)
continue;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
- if (Constructor)
- ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
- }
- }
- // Virtual base-class constructors.
- for (const auto &B : ClassDecl->vbases()) {
- if (const RecordType *BaseType = B.getType()->getAs<RecordType>()) {
- CXXRecordDecl *BaseClassDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (BaseClassDecl == InheritedDecl)
+ CXXRecordDecl *BaseClass = B.getType()->getAsCXXRecordDecl();
+ if (!BaseClass)
continue;
- CXXConstructorDecl *Constructor = LookupDefaultConstructor(BaseClassDecl);
+
+ CXXConstructorDecl *Constructor =
+ ICI.findConstructorForBase(BaseClass, Inherited.getConstructor())
+ .first;
+ if (!Constructor)
+ Constructor = LookupDefaultConstructor(BaseClass);
if (Constructor)
ExceptSpec.CalledDecl(B.getLocStart(), Constructor);
}
@@ -8862,10 +9086,11 @@ namespace {
struct DeclaringSpecialMember {
Sema &S;
Sema::SpecialMemberDecl D;
+ Sema::ContextRAII SavedContext;
bool WasAlreadyBeingDeclared;
DeclaringSpecialMember(Sema &S, CXXRecordDecl *RD, Sema::CXXSpecialMember CSM)
- : S(S), D(RD, CSM) {
+ : S(S), D(RD, CSM), SavedContext(S, RD) {
WasAlreadyBeingDeclared = !S.SpecialMembersBeingDeclared.insert(D).second;
if (WasAlreadyBeingDeclared)
// This almost never happens, but if it does, ensure that our cache
@@ -8887,6 +9112,21 @@ struct DeclaringSpecialMember {
};
}
+void Sema::CheckImplicitSpecialMemberDeclaration(Scope *S, FunctionDecl *FD) {
+ // Look up any existing declarations, but don't trigger declaration of all
+ // implicit special members with this name.
+ DeclarationName Name = FD->getDeclName();
+ LookupResult R(*this, Name, SourceLocation(), LookupOrdinaryName,
+ ForRedeclaration);
+ for (auto *D : FD->getParent()->lookup(Name))
+ if (auto *Acceptable = R.getAcceptableDecl(D))
+ R.addDecl(Acceptable);
+ R.resolveKind();
+ R.suppressDiagnostics();
+
+ CheckFunctionDeclaration(S, FD, R, /*IsExplicitSpecialization*/false);
+}
+
CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
CXXRecordDecl *ClassDecl) {
// C++ [class.ctor]p5:
@@ -8935,13 +9175,16 @@ CXXConstructorDecl *Sema::DeclareImplicitDefaultConstructor(
// constructors is easy to compute.
DefaultCon->setTrivial(ClassDecl->hasTrivialDefaultConstructor());
- if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
- SetDeclDeleted(DefaultCon, ClassLoc);
-
// Note that we have declared this constructor.
++ASTContext::NumImplicitDefaultConstructorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, DefaultCon);
+
+ if (ShouldDeleteSpecialMember(DefaultCon, CXXDefaultConstructor))
+ SetDeclDeleted(DefaultCon, ClassLoc);
+
+ if (S)
PushOnScopeChains(DefaultCon, S, false);
ClassDecl->addDecl(DefaultCon);
@@ -8993,325 +9236,167 @@ void Sema::ActOnFinishDelayedMemberInitializers(Decl *D) {
CheckDelayedMemberExceptionSpecs();
}
-namespace {
-/// Information on inheriting constructors to declare.
-class InheritingConstructorInfo {
-public:
- InheritingConstructorInfo(Sema &SemaRef, CXXRecordDecl *Derived)
- : SemaRef(SemaRef), Derived(Derived) {
- // Mark the constructors that we already have in the derived class.
- //
- // C++11 [class.inhctor]p3: [...] a constructor is implicitly declared [...]
- // unless there is a user-declared constructor with the same signature in
- // the class where the using-declaration appears.
- visitAll(Derived, &InheritingConstructorInfo::noteDeclaredInDerived);
- }
+/// Find or create the fake constructor we synthesize to model constructing an
+/// object of a derived class via a constructor of a base class.
+CXXConstructorDecl *
+Sema::findInheritingConstructor(SourceLocation Loc,
+ CXXConstructorDecl *BaseCtor,
+ ConstructorUsingShadowDecl *Shadow) {
+ CXXRecordDecl *Derived = Shadow->getParent();
+ SourceLocation UsingLoc = Shadow->getLocation();
+
+ // FIXME: Add a new kind of DeclarationName for an inherited constructor.
+ // For now we use the name of the base class constructor as a member of the
+ // derived class to indicate a (fake) inherited constructor name.
+ DeclarationName Name = BaseCtor->getDeclName();
+
+ // Check to see if we already have a fake constructor for this inherited
+ // constructor call.
+ for (NamedDecl *Ctor : Derived->lookup(Name))
+ if (declaresSameEntity(cast<CXXConstructorDecl>(Ctor)
+ ->getInheritedConstructor()
+ .getConstructor(),
+ BaseCtor))
+ return cast<CXXConstructorDecl>(Ctor);
+
+ DeclarationNameInfo NameInfo(Name, UsingLoc);
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(BaseCtor->getType(), UsingLoc);
+ FunctionProtoTypeLoc ProtoLoc =
+ TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
+
+ // Check the inherited constructor is valid and find the list of base classes
+ // from which it was inherited.
+ InheritedConstructorInfo ICI(*this, Loc, Shadow);
+
+ bool Constexpr =
+ BaseCtor->isConstexpr() &&
+ defaultedSpecialMemberIsConstexpr(*this, Derived, CXXDefaultConstructor,
+ false, BaseCtor, &ICI);
+
+ CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
+ Context, Derived, UsingLoc, NameInfo, TInfo->getType(), TInfo,
+ BaseCtor->isExplicit(), /*Inline=*/true,
+ /*ImplicitlyDeclared=*/true, Constexpr,
+ InheritedConstructor(Shadow, BaseCtor));
+ if (Shadow->isInvalidDecl())
+ DerivedCtor->setInvalidDecl();
+
+ // Build an unevaluated exception specification for this fake constructor.
+ const FunctionProtoType *FPT = TInfo->getType()->castAs<FunctionProtoType>();
+ FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
+ EPI.ExceptionSpec.Type = EST_Unevaluated;
+ EPI.ExceptionSpec.SourceDecl = DerivedCtor;
+ DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
+ FPT->getParamTypes(), EPI));
- void inheritAll(CXXRecordDecl *RD) {
- visitAll(RD, &InheritingConstructorInfo::inherit);
+ // Build the parameter declarations.
+ SmallVector<ParmVarDecl *, 16> ParamDecls;
+ for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
+ TypeSourceInfo *TInfo =
+ Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
+ ParmVarDecl *PD = ParmVarDecl::Create(
+ Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
+ FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
+ PD->setScopeInfo(0, I);
+ PD->setImplicit();
+ // Ensure attributes are propagated onto parameters (this matters for
+ // format, pass_object_size, ...).
+ mergeDeclAttributes(PD, BaseCtor->getParamDecl(I));
+ ParamDecls.push_back(PD);
+ ProtoLoc.setParam(I, PD);
}
-private:
- /// Information about an inheriting constructor.
- struct InheritingConstructor {
- InheritingConstructor()
- : DeclaredInDerived(false), BaseCtor(nullptr), DerivedCtor(nullptr) {}
-
- /// If \c true, a constructor with this signature is already declared
- /// in the derived class.
- bool DeclaredInDerived;
-
- /// The constructor which is inherited.
- const CXXConstructorDecl *BaseCtor;
-
- /// The derived constructor we declared.
- CXXConstructorDecl *DerivedCtor;
- };
-
- /// Inheriting constructors with a given canonical type. There can be at
- /// most one such non-template constructor, and any number of templated
- /// constructors.
- struct InheritingConstructorsForType {
- InheritingConstructor NonTemplate;
- SmallVector<std::pair<TemplateParameterList *, InheritingConstructor>, 4>
- Templates;
-
- InheritingConstructor &getEntry(Sema &S, const CXXConstructorDecl *Ctor) {
- if (FunctionTemplateDecl *FTD = Ctor->getDescribedFunctionTemplate()) {
- TemplateParameterList *ParamList = FTD->getTemplateParameters();
- for (unsigned I = 0, N = Templates.size(); I != N; ++I)
- if (S.TemplateParameterListsAreEqual(ParamList, Templates[I].first,
- false, S.TPL_TemplateMatch))
- return Templates[I].second;
- Templates.push_back(std::make_pair(ParamList, InheritingConstructor()));
- return Templates.back().second;
- }
+ // Set up the new constructor.
+ assert(!BaseCtor->isDeleted() && "should not use deleted constructor");
+ DerivedCtor->setAccess(BaseCtor->getAccess());
+ DerivedCtor->setParams(ParamDecls);
+ Derived->addDecl(DerivedCtor);
- return NonTemplate;
- }
- };
+ if (ShouldDeleteSpecialMember(DerivedCtor, CXXDefaultConstructor, &ICI))
+ SetDeclDeleted(DerivedCtor, UsingLoc);
- /// Get or create the inheriting constructor record for a constructor.
- InheritingConstructor &getEntry(const CXXConstructorDecl *Ctor,
- QualType CtorType) {
- return Map[CtorType.getCanonicalType()->castAs<FunctionProtoType>()]
- .getEntry(SemaRef, Ctor);
- }
+ return DerivedCtor;
+}
- typedef void (InheritingConstructorInfo::*VisitFn)(const CXXConstructorDecl*);
+void Sema::NoteDeletedInheritingConstructor(CXXConstructorDecl *Ctor) {
+ InheritedConstructorInfo ICI(*this, Ctor->getLocation(),
+ Ctor->getInheritedConstructor().getShadowDecl());
+ ShouldDeleteSpecialMember(Ctor, CXXDefaultConstructor, &ICI,
+ /*Diagnose*/true);
+}
- /// Process all constructors for a class.
- void visitAll(const CXXRecordDecl *RD, VisitFn Callback) {
- for (const auto *Ctor : RD->ctors())
- (this->*Callback)(Ctor);
- for (CXXRecordDecl::specific_decl_iterator<FunctionTemplateDecl>
- I(RD->decls_begin()), E(RD->decls_end());
- I != E; ++I) {
- const FunctionDecl *FD = (*I)->getTemplatedDecl();
- if (const CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(FD))
- (this->*Callback)(CD);
- }
- }
+void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
+ CXXConstructorDecl *Constructor) {
+ CXXRecordDecl *ClassDecl = Constructor->getParent();
+ assert(Constructor->getInheritedConstructor() &&
+ !Constructor->doesThisDeclarationHaveABody() &&
+ !Constructor->isDeleted());
+ if (Constructor->isInvalidDecl())
+ return;
- /// Note that a constructor (or constructor template) was declared in Derived.
- void noteDeclaredInDerived(const CXXConstructorDecl *Ctor) {
- getEntry(Ctor, Ctor->getType()).DeclaredInDerived = true;
- }
+ ConstructorUsingShadowDecl *Shadow =
+ Constructor->getInheritedConstructor().getShadowDecl();
+ CXXConstructorDecl *InheritedCtor =
+ Constructor->getInheritedConstructor().getConstructor();
- /// Inherit a single constructor.
- void inherit(const CXXConstructorDecl *Ctor) {
- const FunctionProtoType *CtorType =
- Ctor->getType()->castAs<FunctionProtoType>();
- ArrayRef<QualType> ArgTypes = CtorType->getParamTypes();
- FunctionProtoType::ExtProtoInfo EPI = CtorType->getExtProtoInfo();
+ // [class.inhctor.init]p1:
+ // initialization proceeds as if a defaulted default constructor is used to
+ // initialize the D object and each base class subobject from which the
+ // constructor was inherited
- SourceLocation UsingLoc = getUsingLoc(Ctor->getParent());
+ InheritedConstructorInfo ICI(*this, CurrentLocation, Shadow);
+ CXXRecordDecl *RD = Shadow->getParent();
+ SourceLocation InitLoc = Shadow->getLocation();
- // Core issue (no number yet): the ellipsis is always discarded.
- if (EPI.Variadic) {
- SemaRef.Diag(UsingLoc, diag::warn_using_decl_constructor_ellipsis);
- SemaRef.Diag(Ctor->getLocation(),
- diag::note_using_decl_constructor_ellipsis);
- EPI.Variadic = false;
- }
+ // Initializations are performed "as if by a defaulted default constructor",
+ // so enter the appropriate scope.
+ SynthesizedFunctionScope Scope(*this, Constructor);
+ DiagnosticErrorTrap Trap(Diags);
- // Declare a constructor for each number of parameters.
- //
- // C++11 [class.inhctor]p1:
- // The candidate set of inherited constructors from the class X named in
- // the using-declaration consists of [... modulo defects ...] for each
- // constructor or constructor template of X, the set of constructors or
- // constructor templates that results from omitting any ellipsis parameter
- // specification and successively omitting parameters with a default
- // argument from the end of the parameter-type-list
- unsigned MinParams = minParamsToInherit(Ctor);
- unsigned Params = Ctor->getNumParams();
- if (Params >= MinParams) {
- do
- declareCtor(UsingLoc, Ctor,
- SemaRef.Context.getFunctionType(
- Ctor->getReturnType(), ArgTypes.slice(0, Params), EPI));
- while (Params > MinParams &&
- Ctor->getParamDecl(--Params)->hasDefaultArg());
- }
- }
-
- /// Find the using-declaration which specified that we should inherit the
- /// constructors of \p Base.
- SourceLocation getUsingLoc(const CXXRecordDecl *Base) {
- // No fancy lookup required; just look for the base constructor name
- // directly within the derived class.
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Base)));
- DeclContext::lookup_result Decls = Derived->lookup(Name);
- return Decls.empty() ? Derived->getLocation() : Decls[0]->getLocation();
- }
-
- unsigned minParamsToInherit(const CXXConstructorDecl *Ctor) {
- // C++11 [class.inhctor]p3:
- // [F]or each constructor template in the candidate set of inherited
- // constructors, a constructor template is implicitly declared
- if (Ctor->getDescribedFunctionTemplate())
- return 0;
-
- // For each non-template constructor in the candidate set of inherited
- // constructors other than a constructor having no parameters or a
- // copy/move constructor having a single parameter, a constructor is
- // implicitly declared [...]
- if (Ctor->getNumParams() == 0)
- return 1;
- if (Ctor->isCopyOrMoveConstructor())
- return 2;
-
- // Per discussion on core reflector, never inherit a constructor which
- // would become a default, copy, or move constructor of Derived either.
- const ParmVarDecl *PD = Ctor->getParamDecl(0);
- const ReferenceType *RT = PD->getType()->getAs<ReferenceType>();
- return (RT && RT->getPointeeCXXRecordDecl() == Derived) ? 2 : 1;
- }
-
- /// Declare a single inheriting constructor, inheriting the specified
- /// constructor, with the given type.
- void declareCtor(SourceLocation UsingLoc, const CXXConstructorDecl *BaseCtor,
- QualType DerivedType) {
- InheritingConstructor &Entry = getEntry(BaseCtor, DerivedType);
-
- // C++11 [class.inhctor]p3:
- // ... a constructor is implicitly declared with the same constructor
- // characteristics unless there is a user-declared constructor with
- // the same signature in the class where the using-declaration appears
- if (Entry.DeclaredInDerived)
- return;
+ // Build explicit initializers for all base classes from which the
+ // constructor was inherited.
+ SmallVector<CXXCtorInitializer*, 8> Inits;
+ for (bool VBase : {false, true}) {
+ for (CXXBaseSpecifier &B : VBase ? RD->vbases() : RD->bases()) {
+ if (B.isVirtual() != VBase)
+ continue;
- // C++11 [class.inhctor]p7:
- // If two using-declarations declare inheriting constructors with the
- // same signature, the program is ill-formed
- if (Entry.DerivedCtor) {
- if (BaseCtor->getParent() != Entry.BaseCtor->getParent()) {
- // Only diagnose this once per constructor.
- if (Entry.DerivedCtor->isInvalidDecl())
- return;
- Entry.DerivedCtor->setInvalidDecl();
-
- SemaRef.Diag(UsingLoc, diag::err_using_decl_constructor_conflict);
- SemaRef.Diag(BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_current_ctor);
- SemaRef.Diag(Entry.BaseCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_ctor);
- SemaRef.Diag(Entry.DerivedCtor->getLocation(),
- diag::note_using_decl_constructor_conflict_previous_using);
- } else {
- // Core issue (no number): if the same inheriting constructor is
- // produced by multiple base class constructors from the same base
- // class, the inheriting constructor is defined as deleted.
- SemaRef.SetDeclDeleted(Entry.DerivedCtor, UsingLoc);
- }
+ auto *BaseRD = B.getType()->getAsCXXRecordDecl();
+ if (!BaseRD)
+ continue;
- return;
- }
+ auto BaseCtor = ICI.findConstructorForBase(BaseRD, InheritedCtor);
+ if (!BaseCtor.first)
+ continue;
- ASTContext &Context = SemaRef.Context;
- DeclarationName Name = Context.DeclarationNames.getCXXConstructorName(
- Context.getCanonicalType(Context.getRecordType(Derived)));
- DeclarationNameInfo NameInfo(Name, UsingLoc);
+ MarkFunctionReferenced(CurrentLocation, BaseCtor.first);
+ ExprResult Init = new (Context) CXXInheritedCtorInitExpr(
+ InitLoc, B.getType(), BaseCtor.first, VBase, BaseCtor.second);
- TemplateParameterList *TemplateParams = nullptr;
- if (const FunctionTemplateDecl *FTD =
- BaseCtor->getDescribedFunctionTemplate()) {
- TemplateParams = FTD->getTemplateParameters();
- // We're reusing template parameters from a different DeclContext. This
- // is questionable at best, but works out because the template depth in
- // both places is guaranteed to be 0.
- // FIXME: Rebuild the template parameters in the new context, and
- // transform the function type to refer to them.
+ auto *TInfo = Context.getTrivialTypeSourceInfo(B.getType(), InitLoc);
+ Inits.push_back(new (Context) CXXCtorInitializer(
+ Context, TInfo, VBase, InitLoc, Init.get(), InitLoc,
+ SourceLocation()));
}
-
- // Build type source info pointing at the using-declaration. This is
- // required by template instantiation.
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(DerivedType, UsingLoc);
- FunctionProtoTypeLoc ProtoLoc =
- TInfo->getTypeLoc().IgnoreParens().castAs<FunctionProtoTypeLoc>();
-
- CXXConstructorDecl *DerivedCtor = CXXConstructorDecl::Create(
- Context, Derived, UsingLoc, NameInfo, DerivedType,
- TInfo, BaseCtor->isExplicit(), /*Inline=*/true,
- /*ImplicitlyDeclared=*/true, /*Constexpr=*/BaseCtor->isConstexpr());
-
- // Build an unevaluated exception specification for this constructor.
- const FunctionProtoType *FPT = DerivedType->castAs<FunctionProtoType>();
- FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
- EPI.ExceptionSpec.Type = EST_Unevaluated;
- EPI.ExceptionSpec.SourceDecl = DerivedCtor;
- DerivedCtor->setType(Context.getFunctionType(FPT->getReturnType(),
- FPT->getParamTypes(), EPI));
-
- // Build the parameter declarations.
- SmallVector<ParmVarDecl *, 16> ParamDecls;
- for (unsigned I = 0, N = FPT->getNumParams(); I != N; ++I) {
- TypeSourceInfo *TInfo =
- Context.getTrivialTypeSourceInfo(FPT->getParamType(I), UsingLoc);
- ParmVarDecl *PD = ParmVarDecl::Create(
- Context, DerivedCtor, UsingLoc, UsingLoc, /*IdentifierInfo=*/nullptr,
- FPT->getParamType(I), TInfo, SC_None, /*DefaultArg=*/nullptr);
- PD->setScopeInfo(0, I);
- PD->setImplicit();
- ParamDecls.push_back(PD);
- ProtoLoc.setParam(I, PD);
- }
-
- // Set up the new constructor.
- DerivedCtor->setAccess(BaseCtor->getAccess());
- DerivedCtor->setParams(ParamDecls);
- DerivedCtor->setInheritedConstructor(BaseCtor);
- if (BaseCtor->isDeleted())
- SemaRef.SetDeclDeleted(DerivedCtor, UsingLoc);
-
- // If this is a constructor template, build the template declaration.
- if (TemplateParams) {
- FunctionTemplateDecl *DerivedTemplate =
- FunctionTemplateDecl::Create(SemaRef.Context, Derived, UsingLoc, Name,
- TemplateParams, DerivedCtor);
- DerivedTemplate->setAccess(BaseCtor->getAccess());
- DerivedCtor->setDescribedFunctionTemplate(DerivedTemplate);
- Derived->addDecl(DerivedTemplate);
- } else {
- Derived->addDecl(DerivedCtor);
- }
-
- Entry.BaseCtor = BaseCtor;
- Entry.DerivedCtor = DerivedCtor;
}
- Sema &SemaRef;
- CXXRecordDecl *Derived;
- typedef llvm::DenseMap<const Type *, InheritingConstructorsForType> MapType;
- MapType Map;
-};
-}
-
-void Sema::DeclareInheritingConstructors(CXXRecordDecl *ClassDecl) {
- // Defer declaring the inheriting constructors until the class is
- // instantiated.
- if (ClassDecl->isDependentContext())
- return;
-
- // Find base classes from which we might inherit constructors.
- SmallVector<CXXRecordDecl*, 4> InheritedBases;
- for (const auto &BaseIt : ClassDecl->bases())
- if (BaseIt.getInheritConstructors())
- InheritedBases.push_back(BaseIt.getType()->getAsCXXRecordDecl());
-
- // Go no further if we're not inheriting any constructors.
- if (InheritedBases.empty())
- return;
-
- // Declare the inherited constructors.
- InheritingConstructorInfo ICI(*this, ClassDecl);
- for (unsigned I = 0, N = InheritedBases.size(); I != N; ++I)
- ICI.inheritAll(InheritedBases[I]);
-}
+ // We now proceed as if for a defaulted default constructor, with the relevant
+ // initializers replaced.
-void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
- CXXConstructorDecl *Constructor) {
- CXXRecordDecl *ClassDecl = Constructor->getParent();
- assert(Constructor->getInheritedConstructor() &&
- !Constructor->doesThisDeclarationHaveABody() &&
- !Constructor->isDeleted());
-
- SynthesizedFunctionScope Scope(*this, Constructor);
- DiagnosticErrorTrap Trap(Diags);
- if (SetCtorInitializers(Constructor, /*AnyErrors=*/false) ||
- Trap.hasErrorOccurred()) {
- Diag(CurrentLocation, diag::note_inhctor_synthesized_at)
- << Context.getTagDeclType(ClassDecl);
+ bool HadError = SetCtorInitializers(Constructor, /*AnyErrors*/false, Inits);
+ if (HadError || Trap.hasErrorOccurred()) {
+ Diag(CurrentLocation, diag::note_inhctor_synthesized_at) << RD;
Constructor->setInvalidDecl();
return;
}
- SourceLocation Loc = Constructor->getLocation();
- Constructor->setBody(new (Context) CompoundStmt(Loc));
+ // The exception specification is needed because we are defining the
+ // function.
+ ResolveExceptionSpec(CurrentLocation,
+ Constructor->getType()->castAs<FunctionProtoType>());
+
+ Constructor->setBody(new (Context) CompoundStmt(InitLoc));
Constructor->markUsed(Context);
MarkVTableUsed(CurrentLocation, ClassDecl);
@@ -9319,8 +9404,9 @@ void Sema::DefineInheritingConstructor(SourceLocation CurrentLocation,
if (ASTMutationListener *L = getASTMutationListener()) {
L->CompletedImplicitDefinition(Constructor);
}
-}
+ DiagnoseUninitializedFields(*this, Constructor);
+}
Sema::ImplicitExceptionSpecification
Sema::ComputeDefaultedDtorExceptionSpec(CXXMethodDecl *MD) {
@@ -9397,20 +9483,21 @@ CXXDestructorDecl *Sema::DeclareImplicitDestructor(CXXRecordDecl *ClassDecl) {
FunctionProtoType::ExtProtoInfo EPI = getImplicitMethodEPI(*this, Destructor);
Destructor->setType(Context.getFunctionType(Context.VoidTy, None, EPI));
- AddOverriddenMethods(ClassDecl, Destructor);
-
// We don't need to use SpecialMemberIsTrivial here; triviality for
// destructors is easy to compute.
Destructor->setTrivial(ClassDecl->hasTrivialDestructor());
- if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
- SetDeclDeleted(Destructor, ClassLoc);
-
// Note that we have declared this destructor.
++ASTContext::NumImplicitDestructorsDeclared;
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, Destructor);
+
+ if (ShouldDeleteSpecialMember(Destructor, CXXDestructor))
+ SetDeclDeleted(Destructor, ClassLoc);
+
// Introduce this destructor into its scope.
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(Destructor, S, false);
ClassDecl->addDecl(Destructor);
@@ -9533,6 +9620,10 @@ void Sema::ActOnFinishCXXNonNestedClass(Decl *D) {
if (RD && Context.getTargetInfo().getCXXABI().isMicrosoft())
getDefaultArgExprsForConstructors(*this, RD);
+ referenceDLLExportedClassMethods();
+}
+
+void Sema::referenceDLLExportedClassMethods() {
if (!DelayedDllExportClasses.empty()) {
// Calling ReferenceDllExportedMethods might cause the current function to
// be called again, so use a local copy of DelayedDllExportClasses.
@@ -9969,10 +10060,10 @@ buildSingleCopyAssignRecursively(Sema &S, SourceLocation Loc, QualType T,
SizeType, VK_LValue, OK_Ordinary, Loc);
// Construct the loop that copies all elements of this array.
- return S.ActOnForStmt(Loc, Loc, InitStmt,
- S.MakeFullExpr(Comparison),
- nullptr, S.MakeFullDiscardedValueExpr(Increment),
- Loc, Copy.get());
+ return S.ActOnForStmt(
+ Loc, Loc, InitStmt,
+ S.ActOnCondition(nullptr, Loc, Comparison, Sema::ConditionKind::Boolean),
+ S.MakeFullDiscardedValueExpr(Increment), Loc, Copy.get());
}
static StmtResult
@@ -10107,20 +10198,21 @@ CXXMethodDecl *Sema::DeclareImplicitCopyAssignment(CXXRecordDecl *ClassDecl) {
nullptr);
CopyAssignment->setParams(FromParam);
- AddOverriddenMethods(ClassDecl, CopyAssignment);
-
CopyAssignment->setTrivial(
ClassDecl->needsOverloadResolutionForCopyAssignment()
? SpecialMemberIsTrivial(CopyAssignment, CXXCopyAssignment)
: ClassDecl->hasTrivialCopyAssignment());
- if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
- SetDeclDeleted(CopyAssignment, ClassLoc);
-
// Note that we have added this copy-assignment operator.
++ASTContext::NumImplicitCopyAssignmentOperatorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, CopyAssignment);
+
+ if (ShouldDeleteSpecialMember(CopyAssignment, CXXCopyAssignment))
+ SetDeclDeleted(CopyAssignment, ClassLoc);
+
+ if (S)
PushOnScopeChains(CopyAssignment, S, false);
ClassDecl->addDecl(CopyAssignment);
@@ -10498,22 +10590,23 @@ CXXMethodDecl *Sema::DeclareImplicitMoveAssignment(CXXRecordDecl *ClassDecl) {
nullptr);
MoveAssignment->setParams(FromParam);
- AddOverriddenMethods(ClassDecl, MoveAssignment);
-
MoveAssignment->setTrivial(
ClassDecl->needsOverloadResolutionForMoveAssignment()
? SpecialMemberIsTrivial(MoveAssignment, CXXMoveAssignment)
: ClassDecl->hasTrivialMoveAssignment());
+ // Note that we have added this copy-assignment operator.
+ ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
+
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, MoveAssignment);
+
if (ShouldDeleteSpecialMember(MoveAssignment, CXXMoveAssignment)) {
ClassDecl->setImplicitMoveAssignmentIsDeleted();
SetDeclDeleted(MoveAssignment, ClassLoc);
}
- // Note that we have added this copy-assignment operator.
- ++ASTContext::NumImplicitMoveAssignmentOperatorsDeclared;
-
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(MoveAssignment, S, false);
ClassDecl->addDecl(MoveAssignment);
@@ -10939,13 +11032,16 @@ CXXConstructorDecl *Sema::DeclareImplicitCopyConstructor(
? SpecialMemberIsTrivial(CopyConstructor, CXXCopyConstructor)
: ClassDecl->hasTrivialCopyConstructor());
- if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
- SetDeclDeleted(CopyConstructor, ClassLoc);
-
// Note that we have declared this constructor.
++ASTContext::NumImplicitCopyConstructorsDeclared;
- if (Scope *S = getScopeForContext(ClassDecl))
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, CopyConstructor);
+
+ if (ShouldDeleteSpecialMember(CopyConstructor, CXXCopyConstructor))
+ SetDeclDeleted(CopyConstructor, ClassLoc);
+
+ if (S)
PushOnScopeChains(CopyConstructor, S, false);
ClassDecl->addDecl(CopyConstructor);
@@ -11116,15 +11212,18 @@ CXXConstructorDecl *Sema::DeclareImplicitMoveConstructor(
? SpecialMemberIsTrivial(MoveConstructor, CXXMoveConstructor)
: ClassDecl->hasTrivialMoveConstructor());
+ // Note that we have declared this constructor.
+ ++ASTContext::NumImplicitMoveConstructorsDeclared;
+
+ Scope *S = getScopeForContext(ClassDecl);
+ CheckImplicitSpecialMemberDeclaration(S, MoveConstructor);
+
if (ShouldDeleteSpecialMember(MoveConstructor, CXXMoveConstructor)) {
ClassDecl->setImplicitMoveConstructorIsDeleted();
SetDeclDeleted(MoveConstructor, ClassLoc);
}
- // Note that we have declared this constructor.
- ++ASTContext::NumImplicitMoveConstructorsDeclared;
-
- if (Scope *S = getScopeForContext(ClassDecl))
+ if (S)
PushOnScopeChains(MoveConstructor, S, false);
ClassDecl->addDecl(MoveConstructor);
@@ -11329,6 +11428,7 @@ static bool hasOneRealArgument(MultiExprArg Args) {
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ NamedDecl *FoundDecl,
CXXConstructorDecl *Constructor,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
@@ -11349,24 +11449,51 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
// with the same cv-unqualified type, the copy/move operation
// can be omitted by constructing the temporary object
// directly into the target of the omitted copy/move
- if (ConstructKind == CXXConstructExpr::CK_Complete &&
+ if (ConstructKind == CXXConstructExpr::CK_Complete && Constructor &&
Constructor->isCopyOrMoveConstructor() && hasOneRealArgument(ExprArgs)) {
Expr *SubExpr = ExprArgs[0];
- Elidable = SubExpr->isTemporaryObject(Context, Constructor->getParent());
+ Elidable = SubExpr->isTemporaryObject(
+ Context, cast<CXXRecordDecl>(FoundDecl->getDeclContext()));
}
- return BuildCXXConstructExpr(ConstructLoc, DeclInitType, Constructor,
+ return BuildCXXConstructExpr(ConstructLoc, DeclInitType,
+ FoundDecl, Constructor,
Elidable, ExprArgs, HadMultipleCandidates,
IsListInitialization,
IsStdInitListInitialization, RequiresZeroInit,
ConstructKind, ParenRange);
}
+ExprResult
+Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
+ NamedDecl *FoundDecl,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
+ MultiExprArg ExprArgs,
+ bool HadMultipleCandidates,
+ bool IsListInitialization,
+ bool IsStdInitListInitialization,
+ bool RequiresZeroInit,
+ unsigned ConstructKind,
+ SourceRange ParenRange) {
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl)) {
+ Constructor = findInheritingConstructor(ConstructLoc, Constructor, Shadow);
+ if (DiagnoseUseOfDecl(Constructor, ConstructLoc))
+ return ExprError();
+ }
+
+ return BuildCXXConstructExpr(
+ ConstructLoc, DeclInitType, Constructor, Elidable, ExprArgs,
+ HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
+ RequiresZeroInit, ConstructKind, ParenRange);
+}
+
/// BuildCXXConstructExpr - Creates a complete call to a constructor,
/// including handling of its default argument expressions.
ExprResult
Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
- CXXConstructorDecl *Constructor, bool Elidable,
+ CXXConstructorDecl *Constructor,
+ bool Elidable,
MultiExprArg ExprArgs,
bool HadMultipleCandidates,
bool IsListInitialization,
@@ -11374,11 +11501,16 @@ Sema::BuildCXXConstructExpr(SourceLocation ConstructLoc, QualType DeclInitType,
bool RequiresZeroInit,
unsigned ConstructKind,
SourceRange ParenRange) {
+ assert(declaresSameEntity(
+ Constructor->getParent(),
+ DeclInitType->getBaseElementTypeUnsafe()->getAsCXXRecordDecl()) &&
+ "given constructor for wrong type");
MarkFunctionReferenced(ConstructLoc, Constructor);
+
return CXXConstructExpr::Create(
- Context, DeclInitType, ConstructLoc, Constructor, Elidable, ExprArgs,
- HadMultipleCandidates, IsListInitialization, IsStdInitListInitialization,
- RequiresZeroInit,
+ Context, DeclInitType, ConstructLoc, Constructor, Elidable,
+ ExprArgs, HadMultipleCandidates, IsListInitialization,
+ IsStdInitListInitialization, RequiresZeroInit,
static_cast<CXXConstructExpr::ConstructionKind>(ConstructKind),
ParenRange);
}
@@ -11398,8 +11530,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
CXXRecordDecl *ClassPattern = ParentRD->getTemplateInstantiationPattern();
DeclContext::lookup_result Lookup =
ClassPattern->lookup(Field->getDeclName());
- assert(Lookup.size() == 1);
- FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]);
+
+ // Lookup can return at most two results: the pattern for the field, or the
+ // injected class name of the parent record. No other member can have the
+ // same name as the field.
+ assert(!Lookup.empty() && Lookup.size() <= 2 &&
+ "more than two lookup results for field name");
+ FieldDecl *Pattern = dyn_cast<FieldDecl>(Lookup[0]);
+ if (!Pattern) {
+ assert(isa<CXXRecordDecl>(Lookup[0]) &&
+ "cannot have other non-field member with same name");
+ Pattern = cast<FieldDecl>(Lookup[1]);
+ }
+
if (InstantiateInClassInitializer(Loc, Field, Pattern,
getTemplateInstantiationArgs(Field)))
return ExprError();
@@ -11660,7 +11803,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
diag::err_operator_overload_static) << FnDecl->getDeclName();
} else {
bool ClassOrEnumParam = false;
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
QualType ParamType = Param->getType().getNonReferenceType();
if (ParamType->isDependentType() || ParamType->isRecordType() ||
ParamType->isEnumeralType()) {
@@ -11682,7 +11825,7 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
// Only the function-call operator allows default arguments
// (C++ [over.call]p1).
if (Op != OO_Call) {
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
if (Param->hasDefaultArg())
return Diag(Param->getLocation(),
diag::err_operator_overload_default_arg)
@@ -11765,6 +11908,49 @@ bool Sema::CheckOverloadedOperatorDeclaration(FunctionDecl *FnDecl) {
return false;
}
+static bool
+checkLiteralOperatorTemplateParameterList(Sema &SemaRef,
+ FunctionTemplateDecl *TpDecl) {
+ TemplateParameterList *TemplateParams = TpDecl->getTemplateParameters();
+
+ // Must have one or two template parameters.
+ if (TemplateParams->size() == 1) {
+ NonTypeTemplateParmDecl *PmDecl =
+ dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(0));
+
+ // The template parameter must be a char parameter pack.
+ if (PmDecl && PmDecl->isTemplateParameterPack() &&
+ SemaRef.Context.hasSameType(PmDecl->getType(), SemaRef.Context.CharTy))
+ return false;
+
+ } else if (TemplateParams->size() == 2) {
+ TemplateTypeParmDecl *PmType =
+ dyn_cast<TemplateTypeParmDecl>(TemplateParams->getParam(0));
+ NonTypeTemplateParmDecl *PmArgs =
+ dyn_cast<NonTypeTemplateParmDecl>(TemplateParams->getParam(1));
+
+ // The second template parameter must be a parameter pack with the
+ // first template parameter as its type.
+ if (PmType && PmArgs && !PmType->isTemplateParameterPack() &&
+ PmArgs->isTemplateParameterPack()) {
+ const TemplateTypeParmType *TArgs =
+ PmArgs->getType()->getAs<TemplateTypeParmType>();
+ if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
+ TArgs->getIndex() == PmType->getIndex()) {
+ if (SemaRef.ActiveTemplateInstantiations.empty())
+ SemaRef.Diag(TpDecl->getLocation(),
+ diag::ext_string_literal_operator_template);
+ return false;
+ }
+ }
+ }
+
+ SemaRef.Diag(TpDecl->getTemplateParameters()->getSourceRange().getBegin(),
+ diag::err_literal_operator_template)
+ << TpDecl->getTemplateParameters()->getSourceRange();
+ return true;
+}
+
/// CheckLiteralOperatorDeclaration - Check whether the declaration
/// of this literal operator function is well-formed. If so, returns
/// false; otherwise, emits appropriate diagnostics and returns true.
@@ -11780,10 +11966,9 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
return true;
}
- bool Valid = false;
-
// This might be the definition of a literal operator template.
FunctionTemplateDecl *TpDecl = FnDecl->getDescribedFunctionTemplate();
+
// This might be a specialization of a literal operator template.
if (!TpDecl)
TpDecl = FnDecl->getPrimaryTemplate();
@@ -11792,104 +11977,120 @@ bool Sema::CheckLiteralOperatorDeclaration(FunctionDecl *FnDecl) {
// template <class T, T...> type operator "" name() are the only valid
// template signatures, and the only valid signatures with no parameters.
if (TpDecl) {
- if (FnDecl->param_size() == 0) {
- // Must have one or two template parameters
- TemplateParameterList *Params = TpDecl->getTemplateParameters();
- if (Params->size() == 1) {
- NonTypeTemplateParmDecl *PmDecl =
- dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(0));
-
- // The template parameter must be a char parameter pack.
- if (PmDecl && PmDecl->isTemplateParameterPack() &&
- Context.hasSameType(PmDecl->getType(), Context.CharTy))
- Valid = true;
- } else if (Params->size() == 2) {
- TemplateTypeParmDecl *PmType =
- dyn_cast<TemplateTypeParmDecl>(Params->getParam(0));
- NonTypeTemplateParmDecl *PmArgs =
- dyn_cast<NonTypeTemplateParmDecl>(Params->getParam(1));
-
- // The second template parameter must be a parameter pack with the
- // first template parameter as its type.
- if (PmType && PmArgs &&
- !PmType->isTemplateParameterPack() &&
- PmArgs->isTemplateParameterPack()) {
- const TemplateTypeParmType *TArgs =
- PmArgs->getType()->getAs<TemplateTypeParmType>();
- if (TArgs && TArgs->getDepth() == PmType->getDepth() &&
- TArgs->getIndex() == PmType->getIndex()) {
- Valid = true;
- if (ActiveTemplateInstantiations.empty())
- Diag(FnDecl->getLocation(),
- diag::ext_string_literal_operator_template);
- }
- }
+ if (FnDecl->param_size() != 0) {
+ Diag(FnDecl->getLocation(),
+ diag::err_literal_operator_template_with_params);
+ return true;
+ }
+
+ if (checkLiteralOperatorTemplateParameterList(*this, TpDecl))
+ return true;
+
+ } else if (FnDecl->param_size() == 1) {
+ const ParmVarDecl *Param = FnDecl->getParamDecl(0);
+
+ QualType ParamType = Param->getType().getUnqualifiedType();
+
+ // Only unsigned long long int, long double, any character type, and const
+ // char * are allowed as the only parameters.
+ if (ParamType->isSpecificBuiltinType(BuiltinType::ULongLong) ||
+ ParamType->isSpecificBuiltinType(BuiltinType::LongDouble) ||
+ Context.hasSameType(ParamType, Context.CharTy) ||
+ Context.hasSameType(ParamType, Context.WideCharTy) ||
+ Context.hasSameType(ParamType, Context.Char16Ty) ||
+ Context.hasSameType(ParamType, Context.Char32Ty)) {
+ } else if (const PointerType *Ptr = ParamType->getAs<PointerType>()) {
+ QualType InnerType = Ptr->getPointeeType();
+
+ // Pointer parameter must be a const char *.
+ if (!(Context.hasSameType(InnerType.getUnqualifiedType(),
+ Context.CharTy) &&
+ InnerType.isConstQualified() && !InnerType.isVolatileQualified())) {
+ Diag(Param->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << ParamType << "'const char *'" << Param->getSourceRange();
+ return true;
}
+
+ } else if (ParamType->isRealFloatingType()) {
+ Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
+ << ParamType << Context.LongDoubleTy << Param->getSourceRange();
+ return true;
+
+ } else if (ParamType->isIntegerType()) {
+ Diag(Param->getSourceRange().getBegin(), diag::err_literal_operator_param)
+ << ParamType << Context.UnsignedLongLongTy << Param->getSourceRange();
+ return true;
+
+ } else {
+ Diag(Param->getSourceRange().getBegin(),
+ diag::err_literal_operator_invalid_param)
+ << ParamType << Param->getSourceRange();
+ return true;
}
- } else if (FnDecl->param_size()) {
- // Check the first parameter
+
+ } else if (FnDecl->param_size() == 2) {
FunctionDecl::param_iterator Param = FnDecl->param_begin();
- QualType T = (*Param)->getType().getUnqualifiedType();
-
- // unsigned long long int, long double, and any character type are allowed
- // as the only parameters.
- if (Context.hasSameType(T, Context.UnsignedLongLongTy) ||
- Context.hasSameType(T, Context.LongDoubleTy) ||
- Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WideCharTy) ||
- Context.hasSameType(T, Context.Char16Ty) ||
- Context.hasSameType(T, Context.Char32Ty)) {
- if (++Param == FnDecl->param_end())
- Valid = true;
- goto FinishedParams;
- }
-
- // Otherwise it must be a pointer to const; let's strip those qualifiers.
- const PointerType *PT = T->getAs<PointerType>();
- if (!PT)
- goto FinishedParams;
- T = PT->getPointeeType();
- if (!T.isConstQualified() || T.isVolatileQualified())
- goto FinishedParams;
- T = T.getUnqualifiedType();
-
- // Move on to the second parameter;
- ++Param;
+ // First, verify that the first parameter is correct.
- // If there is no second parameter, the first must be a const char *
- if (Param == FnDecl->param_end()) {
- if (Context.hasSameType(T, Context.CharTy))
- Valid = true;
- goto FinishedParams;
+ QualType FirstParamType = (*Param)->getType().getUnqualifiedType();
+
+ // Two parameter function must have a pointer to const as a
+ // first parameter; let's strip those qualifiers.
+ const PointerType *PT = FirstParamType->getAs<PointerType>();
+
+ if (!PT) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
+ }
+
+ QualType PointeeType = PT->getPointeeType();
+ // First parameter must be const
+ if (!PointeeType.isConstQualified() || PointeeType.isVolatileQualified()) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
}
- // const char *, const wchar_t*, const char16_t*, and const char32_t*
+ QualType InnerType = PointeeType.getUnqualifiedType();
+ // Only const char *, const wchar_t*, const char16_t*, and const char32_t*
// are allowed as the first parameter to a two-parameter function
- if (!(Context.hasSameType(T, Context.CharTy) ||
- Context.hasSameType(T, Context.WideCharTy) ||
- Context.hasSameType(T, Context.Char16Ty) ||
- Context.hasSameType(T, Context.Char32Ty)))
- goto FinishedParams;
-
- // The second and final parameter must be an std::size_t
- T = (*Param)->getType().getUnqualifiedType();
- if (Context.hasSameType(T, Context.getSizeType()) &&
- ++Param == FnDecl->param_end())
- Valid = true;
- }
-
- // FIXME: This diagnostic is absolutely terrible.
-FinishedParams:
- if (!Valid) {
- Diag(FnDecl->getLocation(), diag::err_literal_operator_params)
- << FnDecl->getDeclName();
+ if (!(Context.hasSameType(InnerType, Context.CharTy) ||
+ Context.hasSameType(InnerType, Context.WideCharTy) ||
+ Context.hasSameType(InnerType, Context.Char16Ty) ||
+ Context.hasSameType(InnerType, Context.Char32Ty))) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << FirstParamType << "'const char *'" << (*Param)->getSourceRange();
+ return true;
+ }
+
+ // Move on to the second and final parameter.
+ ++Param;
+
+ // The second parameter must be a std::size_t.
+ QualType SecondParamType = (*Param)->getType().getUnqualifiedType();
+ if (!Context.hasSameType(SecondParamType, Context.getSizeType())) {
+ Diag((*Param)->getSourceRange().getBegin(),
+ diag::err_literal_operator_param)
+ << SecondParamType << Context.getSizeType()
+ << (*Param)->getSourceRange();
+ return true;
+ }
+ } else {
+ Diag(FnDecl->getLocation(), diag::err_literal_operator_bad_param_count);
return true;
}
+ // Parameters are good.
+
// A parameter-declaration-clause containing a default argument is not
// equivalent to any of the permitted forms.
- for (auto Param : FnDecl->params()) {
+ for (auto Param : FnDecl->parameters()) {
if (Param->hasDefaultArg()) {
Diag(Param->getDefaultArgRange().getBegin(),
diag::err_literal_operator_default_argument)
@@ -12003,6 +12204,11 @@ VarDecl *Sema::BuildExceptionDeclaration(Scope *S,
Invalid = true;
}
+ if (ExDeclType->isVariablyModifiedType()) {
+ Diag(Loc, diag::err_catch_variably_modified) << ExDeclType;
+ Invalid = true;
+ }
+
QualType BaseType = ExDeclType;
int Mode = 0; // 0 for direct type, 1 for pointer, 2 for reference
unsigned DK = diag::err_catch_incomplete;
@@ -12468,10 +12674,9 @@ Decl *Sema::ActOnFriendTypeDecl(Scope *S, const DeclSpec &DS,
// friend a member of an arbitrary specialization of your template).
Decl *D;
- if (unsigned NumTempParamLists = TempParams.size())
+ if (!TempParams.empty())
D = FriendTemplateDecl::Create(Context, CurContext, Loc,
- NumTempParamLists,
- TempParams.data(),
+ TempParams,
TSI,
DS.getFriendSpecLoc());
else
@@ -12894,44 +13099,20 @@ void Sema::SetDeclDefaulted(Decl *Dcl, SourceLocation DefaultLoc) {
// the record is complete.
const FunctionDecl *Primary = MD;
if (const FunctionDecl *Pattern = MD->getTemplateInstantiationPattern())
- // Find the uninstantiated declaration that actually had the '= default'
- // on it.
- Pattern->isDefined(Primary);
+ // Ask the template instantiation pattern that actually had the
+ // '= default' on it.
+ Primary = Pattern;
// If the method was defaulted on its first declaration, we will have
// already performed the checking in CheckCompletedCXXClass. Such a
// declaration doesn't trigger an implicit definition.
- if (Primary == Primary->getCanonicalDecl())
+ if (Primary->getCanonicalDecl()->isDefaulted())
return;
CheckExplicitlyDefaultedSpecialMember(MD);
- if (MD->isInvalidDecl())
- return;
-
- switch (Member) {
- case CXXDefaultConstructor:
- DefineImplicitDefaultConstructor(DefaultLoc,
- cast<CXXConstructorDecl>(MD));
- break;
- case CXXCopyConstructor:
- DefineImplicitCopyConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
- break;
- case CXXCopyAssignment:
- DefineImplicitCopyAssignment(DefaultLoc, MD);
- break;
- case CXXDestructor:
- DefineImplicitDestructor(DefaultLoc, cast<CXXDestructorDecl>(MD));
- break;
- case CXXMoveConstructor:
- DefineImplicitMoveConstructor(DefaultLoc, cast<CXXConstructorDecl>(MD));
- break;
- case CXXMoveAssignment:
- DefineImplicitMoveAssignment(DefaultLoc, MD);
- break;
- case CXXInvalid:
- llvm_unreachable("Invalid special member.");
- }
+ if (!MD->isInvalidDecl())
+ DefineImplicitSpecialMember(*this, MD, DefaultLoc);
} else {
Diag(DefaultLoc, diag::err_default_special_members);
}
@@ -13020,19 +13201,20 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
return true;
}
- // C++ [class.virtual]p6:
- // If the return type of D::f differs from the return type of B::f, the
- // class type in the return type of D::f shall be complete at the point of
- // declaration of D::f or shall be the class type D.
- if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
- if (!RT->isBeingDefined() &&
- RequireCompleteType(New->getLocation(), NewClassTy,
- diag::err_covariant_return_incomplete,
- New->getDeclName()))
- return true;
- }
-
if (!Context.hasSameUnqualifiedType(NewClassTy, OldClassTy)) {
+ // C++14 [class.virtual]p8:
+ // If the class type in the covariant return type of D::f differs from
+ // that of B::f, the class type in the return type of D::f shall be
+ // complete at the point of declaration of D::f or shall be the class
+ // type D.
+ if (const RecordType *RT = NewClassTy->getAs<RecordType>()) {
+ if (!RT->isBeingDefined() &&
+ RequireCompleteType(New->getLocation(), NewClassTy,
+ diag::err_covariant_return_incomplete,
+ New->getDeclName()))
+ return true;
+ }
+
// Check if the new class derives from the old class.
if (!IsDerivedFrom(New->getLocation(), NewClassTy, OldClassTy)) {
Diag(New->getLocation(), diag::err_covariant_return_not_derived)
@@ -13069,7 +13251,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
<< Old->getReturnTypeSourceRange();
return true;
- };
+ }
// The new class type must have the same or less qualifiers as the old type.
@@ -13081,7 +13263,7 @@ bool Sema::CheckOverridingFunctionReturnType(const CXXMethodDecl *New,
Diag(Old->getLocation(), diag::note_overridden_virtual_function)
<< Old->getReturnTypeSourceRange();
return true;
- };
+ }
return false;
}
@@ -13240,14 +13422,19 @@ void Sema::MarkVTableUsed(SourceLocation Loc, CXXRecordDecl *Class,
// checks (i.e. operator delete() lookup) when the vtable is marked used, as
// the deleting destructor is emitted with the vtable, not with the
// destructor definition as in the Itanium ABI.
- // If it has a definition, we do the check at that point instead.
- if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
- Class->hasUserDeclaredDestructor() &&
- !Class->getDestructor()->isDefined() &&
- !Class->getDestructor()->isDeleted()) {
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft()) {
CXXDestructorDecl *DD = Class->getDestructor();
- ContextRAII SavedContext(*this, DD);
- CheckDestructor(DD);
+ if (DD && DD->isVirtual() && !DD->isDeleted()) {
+ if (Class->hasUserDeclaredDestructor() && !DD->isDefined()) {
+ // If this is an out-of-line declaration, marking it referenced will
+ // not do anything. Manually call CheckDestructor to look up operator
+ // delete().
+ ContextRAII SavedContext(*this, DD);
+ CheckDestructor(DD);
+ } else {
+ MarkFunctionReferenced(Loc, Class->getDestructor());
+ }
+ }
}
}
@@ -13785,6 +13972,9 @@ MSPropertyDecl *Sema::HandleMSProperty(Scope *S, RecordDecl *Record,
DiagnoseFunctionSpecifiers(D.getDeclSpec());
+ if (D.getDeclSpec().isInlineSpecified())
+ Diag(D.getDeclSpec().getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
index a2f41a7cc30a..738de77cecb7 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaDeclObjC.cpp
@@ -21,7 +21,6 @@
#include "clang/AST/ExprObjC.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
@@ -320,11 +319,11 @@ void Sema::ActOnStartOfObjCMethodDef(Scope *FnBodyScope, Decl *D) {
PushOnScopeChains(MDecl->getCmdDecl(), FnBodyScope);
// The ObjC parser requires parameter names so there's no need to check.
- CheckParmsForFunctionDef(MDecl->param_begin(), MDecl->param_end(),
+ CheckParmsForFunctionDef(MDecl->parameters(),
/*CheckParameterNames=*/false);
// Introduce all of the other parameters into this scope.
- for (auto *Param : MDecl->params()) {
+ for (auto *Param : MDecl->parameters()) {
if (!Param->isInvalidDecl() &&
getLangOpts().ObjCAutoRefCount &&
!HasExplicitOwnershipAttr(*this, Param))
@@ -1303,6 +1302,16 @@ class ObjCTypeArgOrProtocolValidatorCCC : public CorrectionCandidateCallback {
};
} // end anonymous namespace
+void Sema::DiagnoseTypeArgsAndProtocols(IdentifierInfo *ProtocolId,
+ SourceLocation ProtocolLoc,
+ IdentifierInfo *TypeArgId,
+ SourceLocation TypeArgLoc,
+ bool SelectProtocolFirst) {
+ Diag(TypeArgLoc, diag::err_objc_type_args_and_protocols)
+ << SelectProtocolFirst << TypeArgId << ProtocolId
+ << SourceRange(ProtocolLoc);
+}
+
void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
Scope *S,
ParsedType baseType,
@@ -1493,6 +1502,7 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
SourceLocation(),
SourceLocation(),
SourceLocation(),
+ SourceLocation(),
SourceLocation()),
parsedAttrs,
starLoc);
@@ -1570,11 +1580,9 @@ void Sema::actOnObjCTypeArgsOrProtocolQualifiers(
// We have a conflict: some names refer to protocols and others
// refer to types.
- Diag(identifierLocs[i], diag::err_objc_type_args_and_protocols)
- << (protocols[i] != nullptr)
- << identifiers[i]
- << identifiers[0]
- << SourceRange(identifierLocs[0]);
+ DiagnoseTypeArgsAndProtocols(identifiers[0], identifierLocs[0],
+ identifiers[i], identifierLocs[i],
+ protocols[i] != nullptr);
protocols.clear();
typeArgs.clear();
@@ -1831,6 +1839,13 @@ Decl *Sema::ActOnStartCategoryImplementation(
if (IDecl)
DiagnoseUseOfDecl(IDecl, ClassLoc);
+ // If the interface has the objc_runtime_visible attribute, we
+ // cannot implement a category for it.
+ if (IDecl && IDecl->hasAttr<ObjCRuntimeVisibleAttr>()) {
+ Diag(ClassLoc, diag::err_objc_runtime_visible_category)
+ << IDecl->getDeclName();
+ }
+
/// Check that CatName, category name, is not used in another implementation.
if (CatIDecl) {
if (CatIDecl->getImplementation()) {
@@ -1968,6 +1983,16 @@ Decl *Sema::ActOnStartClassImplementation(
dyn_cast<NamedDecl>(IDecl),
IMPDecl->getLocation(), 1);
}
+
+ // If the superclass has the objc_runtime_visible attribute, we
+ // cannot implement a subclass of it.
+ if (IDecl->getSuperClass() &&
+ IDecl->getSuperClass()->hasAttr<ObjCRuntimeVisibleAttr>()) {
+ Diag(ClassLoc, diag::err_objc_runtime_visible_subclass)
+ << IDecl->getDeclName()
+ << IDecl->getSuperClass()->getDeclName();
+ }
+
return ActOnObjCContainerStartDefinition(IMPDecl);
}
@@ -2734,7 +2759,8 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
for (auto *I : CDecl->class_methods()) {
if (!ClsMapSeen.insert(I->getSelector()).second)
continue;
- if (!ClsMap.count(I->getSelector())) {
+ if (!I->isPropertyAccessor() &&
+ !ClsMap.count(I->getSelector())) {
if (ImmediateClass)
WarnUndefinedMethod(*this, IMPDecl->getLocation(), I, IncompleteImpl,
diag::warn_undef_method_impl);
@@ -2743,12 +2769,14 @@ void Sema::MatchAllMethodDeclarations(const SelectorSet &InsMap,
IMPDecl->getClassMethod(I->getSelector());
assert(CDecl->getClassMethod(I->getSelector()) &&
"Expected to find the method through lookup as well");
- if (!WarnCategoryMethodImpl)
- WarnConflictingTypedMethods(ImpMethodDecl, I,
- isa<ObjCProtocolDecl>(CDecl));
- else
- WarnExactTypedMethods(ImpMethodDecl, I,
- isa<ObjCProtocolDecl>(CDecl));
+ // ImpMethodDecl may be null as in a @dynamic property.
+ if (ImpMethodDecl) {
+ if (!WarnCategoryMethodImpl)
+ WarnConflictingTypedMethods(ImpMethodDecl, I,
+ isa<ObjCProtocolDecl>(CDecl));
+ else if (!I->isPropertyAccessor())
+ WarnExactTypedMethods(ImpMethodDecl, I, isa<ObjCProtocolDecl>(CDecl));
+ }
}
}
@@ -3147,6 +3175,26 @@ bool Sema::MatchTwoMethodDeclarations(const ObjCMethodDecl *left,
return true;
}
+static bool isMethodContextSameForKindofLookup(ObjCMethodDecl *Method,
+ ObjCMethodDecl *MethodInList) {
+ auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext());
+ auto *MethodInListProtocol =
+ dyn_cast<ObjCProtocolDecl>(MethodInList->getDeclContext());
+ // If this method belongs to a protocol but the method in list does not, or
+ // vice versa, we say the context is not the same.
+ if ((MethodProtocol && !MethodInListProtocol) ||
+ (!MethodProtocol && MethodInListProtocol))
+ return false;
+
+ if (MethodProtocol && MethodInListProtocol)
+ return true;
+
+ ObjCInterfaceDecl *MethodInterface = Method->getClassInterface();
+ ObjCInterfaceDecl *MethodInListInterface =
+ MethodInList->getClassInterface();
+ return MethodInterface == MethodInListInterface;
+}
+
void Sema::addMethodToGlobalList(ObjCMethodList *List,
ObjCMethodDecl *Method) {
// Record at the head of the list whether there were 0, 1, or >= 2 methods
@@ -3166,17 +3214,42 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,
// We've seen a method with this name, see if we have already seen this type
// signature.
ObjCMethodList *Previous = List;
+ ObjCMethodList *ListWithSameDeclaration = nullptr;
for (; List; Previous = List, List = List->getNext()) {
// If we are building a module, keep all of the methods.
- if (getLangOpts().Modules && !getLangOpts().CurrentModule.empty())
+ if (getLangOpts().CompilingModule)
continue;
- if (!MatchTwoMethodDeclarations(Method, List->getMethod())) {
+ bool SameDeclaration = MatchTwoMethodDeclarations(Method,
+ List->getMethod());
+ // Looking for method with a type bound requires the correct context exists.
+ // We need to insert a method into the list if the context is different.
+ // If the method's declaration matches the list
+ // a> the method belongs to a different context: we need to insert it, in
+ // order to emit the availability message, we need to prioritize over
+ // availability among the methods with the same declaration.
+ // b> the method belongs to the same context: there is no need to insert a
+ // new entry.
+ // If the method's declaration does not match the list, we insert it to the
+ // end.
+ if (!SameDeclaration ||
+ !isMethodContextSameForKindofLookup(Method, List->getMethod())) {
// Even if two method types do not match, we would like to say
// there is more than one declaration so unavailability/deprecated
// warning is not too noisy.
if (!Method->isDefined())
List->setHasMoreThanOneDecl(true);
+
+ // For methods with the same declaration, the one that is deprecated
+ // should be put in the front for better diagnostics.
+ if (Method->isDeprecated() && SameDeclaration &&
+ !ListWithSameDeclaration && !List->getMethod()->isDeprecated())
+ ListWithSameDeclaration = List;
+
+ if (Method->isUnavailable() && SameDeclaration &&
+ !ListWithSameDeclaration &&
+ List->getMethod()->getAvailability() < AR_Deprecated)
+ ListWithSameDeclaration = List;
continue;
}
@@ -3212,6 +3285,16 @@ void Sema::addMethodToGlobalList(ObjCMethodList *List,
// We have a new signature for an existing method - add it.
// This is extremely rare. Only 1% of Cocoa selectors are "overloaded".
ObjCMethodList *Mem = BumpAlloc.Allocate<ObjCMethodList>();
+
+ // We insert it right before ListWithSameDeclaration.
+ if (ListWithSameDeclaration) {
+ auto *List = new (Mem) ObjCMethodList(*ListWithSameDeclaration);
+ // FIXME: should we clear the other bits in ListWithSameDeclaration?
+ ListWithSameDeclaration->setMethod(Method);
+ ListWithSameDeclaration->setNext(List);
+ return;
+ }
+
Previous->setNext(new (Mem) ObjCMethodList(Method));
}
@@ -3222,6 +3305,12 @@ void Sema::ReadMethodPool(Selector Sel) {
ExternalSource->ReadMethodPool(Sel);
}
+void Sema::updateOutOfDateSelector(Selector Sel) {
+ if (!ExternalSource)
+ return;
+ ExternalSource->updateOutOfDateSelector(Sel);
+}
+
void Sema::AddMethodToGlobalPool(ObjCMethodDecl *Method, bool impl,
bool instance) {
// Ignore methods of invalid containers.
@@ -3261,25 +3350,95 @@ static bool isAcceptableMethodMismatch(ObjCMethodDecl *chosen,
return (chosen->getReturnType()->isIntegerType());
}
+/// Return true if the given method is wthin the type bound.
+static bool FilterMethodsByTypeBound(ObjCMethodDecl *Method,
+ const ObjCObjectType *TypeBound) {
+ if (!TypeBound)
+ return true;
+
+ if (TypeBound->isObjCId())
+ // FIXME: should we handle the case of bounding to id<A, B> differently?
+ return true;
+
+ auto *BoundInterface = TypeBound->getInterface();
+ assert(BoundInterface && "unexpected object type!");
+
+ // Check if the Method belongs to a protocol. We should allow any method
+ // defined in any protocol, because any subclass could adopt the protocol.
+ auto *MethodProtocol = dyn_cast<ObjCProtocolDecl>(Method->getDeclContext());
+ if (MethodProtocol) {
+ return true;
+ }
+
+ // If the Method belongs to a class, check if it belongs to the class
+ // hierarchy of the class bound.
+ if (ObjCInterfaceDecl *MethodInterface = Method->getClassInterface()) {
+ // We allow methods declared within classes that are part of the hierarchy
+ // of the class bound (superclass of, subclass of, or the same as the class
+ // bound).
+ return MethodInterface == BoundInterface ||
+ MethodInterface->isSuperClassOf(BoundInterface) ||
+ BoundInterface->isSuperClassOf(MethodInterface);
+ }
+ llvm_unreachable("unknow method context");
+}
+
+/// We first select the type of the method: Instance or Factory, then collect
+/// all methods with that type.
bool Sema::CollectMultipleMethodsInGlobalPool(
- Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods, bool instance) {
+ Selector Sel, SmallVectorImpl<ObjCMethodDecl *> &Methods,
+ bool InstanceFirst, bool CheckTheOther,
+ const ObjCObjectType *TypeBound) {
if (ExternalSource)
ReadMethodPool(Sel);
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
if (Pos == MethodPool.end())
return false;
+
// Gather the non-hidden methods.
- ObjCMethodList &MethList = instance ? Pos->second.first : Pos->second.second;
+ ObjCMethodList &MethList = InstanceFirst ? Pos->second.first :
+ Pos->second.second;
for (ObjCMethodList *M = &MethList; M; M = M->getNext())
- if (M->getMethod() && !M->getMethod()->isHidden())
- Methods.push_back(M->getMethod());
+ if (M->getMethod() && !M->getMethod()->isHidden()) {
+ if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
+ Methods.push_back(M->getMethod());
+ }
+
+ // Return if we find any method with the desired kind.
+ if (!Methods.empty())
+ return Methods.size() > 1;
+
+ if (!CheckTheOther)
+ return false;
+
+ // Gather the other kind.
+ ObjCMethodList &MethList2 = InstanceFirst ? Pos->second.second :
+ Pos->second.first;
+ for (ObjCMethodList *M = &MethList2; M; M = M->getNext())
+ if (M->getMethod() && !M->getMethod()->isHidden()) {
+ if (FilterMethodsByTypeBound(M->getMethod(), TypeBound))
+ Methods.push_back(M->getMethod());
+ }
+
return Methods.size() > 1;
}
-bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMethod,
- SourceRange R,
- bool receiverIdOrClass) {
+bool Sema::AreMultipleMethodsInGlobalPool(
+ Selector Sel, ObjCMethodDecl *BestMethod, SourceRange R,
+ bool receiverIdOrClass, SmallVectorImpl<ObjCMethodDecl *> &Methods) {
+ // Diagnose finding more than one method in global pool.
+ SmallVector<ObjCMethodDecl *, 4> FilteredMethods;
+ FilteredMethods.push_back(BestMethod);
+
+ for (auto *M : Methods)
+ if (M != BestMethod && !M->hasAttr<UnavailableAttr>())
+ FilteredMethods.push_back(M);
+
+ if (FilteredMethods.size() > 1)
+ DiagnoseMultipleMethodInGlobalPool(FilteredMethods, Sel, R,
+ receiverIdOrClass);
+
GlobalMethodPool::iterator Pos = MethodPool.find(Sel);
// Test for no method in the pool which should not trigger any warning by
// caller.
@@ -3287,17 +3446,6 @@ bool Sema::AreMultipleMethodsInGlobalPool(Selector Sel, ObjCMethodDecl *BestMeth
return true;
ObjCMethodList &MethList =
BestMethod->isInstanceMethod() ? Pos->second.first : Pos->second.second;
-
- // Diagnose finding more than one method in global pool
- SmallVector<ObjCMethodDecl *, 4> Methods;
- Methods.push_back(BestMethod);
- for (ObjCMethodList *ML = &MethList; ML; ML = ML->getNext())
- if (ObjCMethodDecl *M = ML->getMethod())
- if (!M->isHidden() && M != BestMethod && !M->hasAttr<UnavailableAttr>())
- Methods.push_back(M);
- if (Methods.size() > 1)
- DiagnoseMultipleMethodInGlobalPool(Methods, Sel, R, receiverIdOrClass);
-
return MethList.hasMoreThanOneDecl();
}
@@ -3650,10 +3798,11 @@ Decl *Sema::ActOnAtEnd(Scope *S, SourceRange AtEnd, ArrayRef<Decl *> allMethods,
// property will be synthesized when property with same name is
// seen in the @implementation.
for (const auto *Ext : IDecl->visible_extensions()) {
- for (const auto *Property : Ext->properties()) {
+ for (const auto *Property : Ext->instance_properties()) {
// Skip over properties declared @dynamic
if (const ObjCPropertyImplDecl *PIDecl
- = IC->FindPropertyImplDecl(Property->getIdentifier()))
+ = IC->FindPropertyImplDecl(Property->getIdentifier(),
+ Property->getQueryKind()))
if (PIDecl->getPropertyImplementation()
== ObjCPropertyImplDecl::Dynamic)
continue;
@@ -3839,7 +3988,7 @@ public:
}
}
- typedef llvm::SmallPtrSet<ObjCMethodDecl*, 128>::iterator iterator;
+ typedef llvm::SmallPtrSetImpl<ObjCMethodDecl*>::iterator iterator;
iterator begin() const { return Overridden.begin(); }
iterator end() const { return Overridden.end(); }
@@ -4463,6 +4612,9 @@ Decl *Sema::ActOnObjCExceptionDecl(Scope *S, Declarator &D) {
Diag(DS.getStorageClassSpecLoc(), diag::err_storage_spec_on_catch_parm)
<< DeclSpec::getSpecifierName(SCS);
}
+ if (DS.isInlineSpecified())
+ Diag(DS.getInlineSpecLoc(), diag::err_inline_non_function)
+ << getLangOpts().CPlusPlus1z;
if (DeclSpec::TSCS TSCS = D.getDeclSpec().getThreadStorageClassSpec())
Diag(D.getDeclSpec().getThreadStorageClassSpecLoc(),
diag::err_invalid_thread)
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
index f12bf2415dba..4a21eb308fe5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExceptionSpec.cpp
@@ -110,11 +110,17 @@ bool Sema::CheckSpecifiedExceptionType(QualType &T, SourceRange Range) {
// A type denoted in an exception-specification shall not denote a
// pointer or reference to an incomplete type, other than (cv) void* or a
// pointer or reference to a class currently being defined.
+ // In Microsoft mode, downgrade this to a warning.
+ unsigned DiagID = diag::err_incomplete_in_exception_spec;
+ bool ReturnValueOnError = true;
+ if (getLangOpts().MicrosoftExt) {
+ DiagID = diag::ext_incomplete_in_exception_spec;
+ ReturnValueOnError = false;
+ }
if (!(PointeeT->isRecordType() &&
PointeeT->getAs<RecordType>()->isBeingDefined()) &&
- RequireCompleteType(Range.getBegin(), PointeeT,
- diag::err_incomplete_in_exception_spec, Kind, Range))
- return true;
+ RequireCompleteType(Range.getBegin(), PointeeT, DiagID, Kind, Range))
+ return ReturnValueOnError;
return false;
}
@@ -995,6 +1001,10 @@ CanThrowResult Sema::canThrow(const Expr *E) {
return mergeCanThrow(CT, canSubExprsThrow(*this, E));
}
+ case Expr::CXXInheritedCtorInitExprClass:
+ return canCalleeThrow(*this, E,
+ cast<CXXInheritedCtorInitExpr>(E)->getConstructor());
+
case Expr::LambdaExprClass: {
const LambdaExpr *Lambda = cast<LambdaExpr>(E);
CanThrowResult CT = CT_Cannot;
@@ -1136,6 +1146,7 @@ CanThrowResult Sema::canThrow(const Expr *E) {
case Expr::ObjCIndirectCopyRestoreExprClass:
case Expr::ObjCProtocolExprClass:
case Expr::ObjCSelectorExprClass:
+ case Expr::ObjCAvailabilityCheckExprClass:
case Expr::OffsetOfExprClass:
case Expr::PackExpansionExprClass:
case Expr::PseudoObjectExprClass:
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
index 5a2eb6060ee9..57159fb59715 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExpr.cpp
@@ -49,7 +49,7 @@ using namespace sema;
/// \brief Determine whether the use of this declaration is valid, without
/// emitting diagnostics.
-bool Sema::CanUseDecl(NamedDecl *D) {
+bool Sema::CanUseDecl(NamedDecl *D, bool TreatUnavailableAsInvalid) {
// See if this is an auto-typed variable whose initializer we are parsing.
if (ParsingInitForAutoVars.count(D))
return false;
@@ -67,7 +67,7 @@ bool Sema::CanUseDecl(NamedDecl *D) {
}
// See if this function is unavailable.
- if (D->getAvailability() == AR_Unavailable &&
+ if (TreatUnavailableAsInvalid && D->getAvailability() == AR_Unavailable &&
cast<Decl>(CurContext)->getAvailability() != AR_Unavailable)
return false;
@@ -76,10 +76,14 @@ bool Sema::CanUseDecl(NamedDecl *D) {
static void DiagnoseUnusedOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc) {
// Warn if this is used but marked unused.
- if (D->hasAttr<UnusedAttr>()) {
- const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
- if (DC && !DC->hasAttr<UnusedAttr>())
- S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ if (const auto *A = D->getAttr<UnusedAttr>()) {
+ // [[maybe_unused]] should not diagnose uses, but __attribute__((unused))
+ // should diagnose them.
+ if (A->getSemanticSpelling() != UnusedAttr::CXX11_maybe_unused) {
+ const Decl *DC = cast_or_null<Decl>(S.getCurObjCLexicalContext());
+ if (DC && !DC->hasAttr<UnusedAttr>())
+ S.Diag(Loc, diag::warn_used_but_marked_unused) << D->getDeclName();
+ }
}
}
@@ -137,7 +141,7 @@ DiagnoseAvailabilityOfDecl(Sema &S, NamedDecl *D, SourceLocation Loc,
const ObjCPropertyDecl *ObjCPDecl = nullptr;
if (Result == AR_Deprecated || Result == AR_Unavailable ||
- AR_NotYetIntroduced) {
+ Result == AR_NotYetIntroduced) {
if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
if (const ObjCPropertyDecl *PD = MD->findPropertyDecl()) {
AvailabilityResult PDeclResult = PD->getAvailability(nullptr);
@@ -212,25 +216,14 @@ void Sema::NoteDeletedFunction(FunctionDecl *Decl) {
// deleted. This might fail, if that reason no longer applies.
CXXSpecialMember CSM = getSpecialMember(Method);
if (CSM != CXXInvalid)
- ShouldDeleteSpecialMember(Method, CSM, /*Diagnose=*/true);
+ ShouldDeleteSpecialMember(Method, CSM, nullptr, /*Diagnose=*/true);
return;
}
- if (CXXConstructorDecl *CD = dyn_cast<CXXConstructorDecl>(Decl)) {
- if (CXXConstructorDecl *BaseCD =
- const_cast<CXXConstructorDecl*>(CD->getInheritedConstructor())) {
- Diag(Decl->getLocation(), diag::note_inherited_deleted_here);
- if (BaseCD->isDeleted()) {
- NoteDeletedFunction(BaseCD);
- } else {
- // FIXME: An explanation of why exactly it can't be inherited
- // would be nice.
- Diag(BaseCD->getLocation(), diag::note_cannot_inherit);
- }
- return;
- }
- }
+ auto *Ctor = dyn_cast<CXXConstructorDecl>(Decl);
+ if (Ctor && Ctor->isInheritingConstructor())
+ return NoteDeletedInheritingConstructor(Ctor);
Diag(Decl->getLocation(), diag::note_availability_specified_here)
<< Decl << true;
@@ -357,7 +350,13 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
// See if this is a deleted function.
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isDeleted()) {
- Diag(Loc, diag::err_deleted_function_use);
+ auto *Ctor = dyn_cast<CXXConstructorDecl>(FD);
+ if (Ctor && Ctor->isInheritingConstructor())
+ Diag(Loc, diag::err_deleted_inherited_ctor_use)
+ << Ctor->getParent()
+ << Ctor->getInheritedConstructor().getConstructor()->getParent();
+ else
+ Diag(Loc, diag::err_deleted_function_use);
NoteDeletedFunction(FD);
return true;
}
@@ -368,6 +367,19 @@ bool Sema::DiagnoseUseOfDecl(NamedDecl *D, SourceLocation Loc,
DeduceReturnType(FD, Loc))
return true;
}
+
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
+ // Only the variables omp_in and omp_out are allowed in the combiner.
+ // Only the variables omp_priv and omp_orig are allowed in the
+ // initializer-clause.
+ auto *DRD = dyn_cast<OMPDeclareReductionDecl>(CurContext);
+ if (LangOpts.OpenMP && DRD && !CurContext->containsDecl(D) &&
+ isa<VarDecl>(D)) {
+ Diag(Loc, diag::err_omp_wrong_var_in_declare_reduction)
+ << getCurFunction()->HasOMPDeclareReductionCombiner;
+ Diag(D->getLocation(), diag::note_entity_declared_at) << D;
+ return true;
+ }
DiagnoseAvailabilityOfDecl(*this, D, Loc, UnknownObjCClass,
ObjCPropertyAccess);
@@ -695,7 +707,7 @@ ExprResult Sema::DefaultLvalueConversion(Expr *E) {
// balance that.
if (getLangOpts().ObjCAutoRefCount &&
E->getType().getObjCLifetime() == Qualifiers::OCL_Weak)
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
ExprResult Res = ImplicitCastExpr::Create(Context, T, CK_LValueToRValue, E,
nullptr, VK_RValue);
@@ -1138,6 +1150,48 @@ static QualType handleFloatConversion(Sema &S, ExprResult &LHS,
/*convertFloat=*/!IsCompAssign);
}
+/// \brief Diagnose attempts to convert between __float128 and long double if
+/// there is no support for such conversion. Helper function of
+/// UsualArithmeticConversions().
+static bool unsupportedTypeConversion(const Sema &S, QualType LHSType,
+ QualType RHSType) {
+ /* No issue converting if at least one of the types is not a floating point
+ type or the two types have the same rank.
+ */
+ if (!LHSType->isFloatingType() || !RHSType->isFloatingType() ||
+ S.Context.getFloatingTypeOrder(LHSType, RHSType) == 0)
+ return false;
+
+ assert(LHSType->isFloatingType() && RHSType->isFloatingType() &&
+ "The remaining types must be floating point types.");
+
+ auto *LHSComplex = LHSType->getAs<ComplexType>();
+ auto *RHSComplex = RHSType->getAs<ComplexType>();
+
+ QualType LHSElemType = LHSComplex ?
+ LHSComplex->getElementType() : LHSType;
+ QualType RHSElemType = RHSComplex ?
+ RHSComplex->getElementType() : RHSType;
+
+ // No issue if the two types have the same representation
+ if (&S.Context.getFloatTypeSemantics(LHSElemType) ==
+ &S.Context.getFloatTypeSemantics(RHSElemType))
+ return false;
+
+ bool Float128AndLongDouble = (LHSElemType == S.Context.Float128Ty &&
+ RHSElemType == S.Context.LongDoubleTy);
+ Float128AndLongDouble |= (LHSElemType == S.Context.LongDoubleTy &&
+ RHSElemType == S.Context.Float128Ty);
+
+ /* We've handled the situation where __float128 and long double have the same
+ representation. The only other allowable conversion is if long double is
+ really just double.
+ */
+ return Float128AndLongDouble &&
+ (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) !=
+ &llvm::APFloat::IEEEdouble);
+}
+
typedef ExprResult PerformCastFn(Sema &S, Expr *operand, QualType toType);
namespace {
@@ -1301,6 +1355,11 @@ QualType Sema::UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
// At this point, we have two different arithmetic types.
+ // Diagnose attempts to convert between __float128 and long double where
+ // such conversions currently can't be handled.
+ if (unsupportedTypeConversion(*this, LHSType, RHSType))
+ return QualType();
+
// Handle complex types first (C99 6.3.1.8p1).
if (LHSType->isComplexType() || RHSType->isComplexType())
return handleComplexFloatConversion(*this, LHS, RHS, LHSType, RHSType,
@@ -1719,10 +1778,12 @@ Sema::BuildDeclRefExpr(ValueDecl *D, QualType Ty, ExprValueKind VK,
!Diags.isIgnored(diag::warn_arc_repeated_use_of_weak, E->getLocStart()))
recordUseOfEvaluatedWeak(E);
- // Just in case we're building an illegal pointer-to-member.
- FieldDecl *FD = dyn_cast<FieldDecl>(D);
- if (FD && FD->isBitField())
- E->setObjectKind(OK_BitField);
+ if (FieldDecl *FD = dyn_cast<FieldDecl>(D)) {
+ UnusedPrivateFields.remove(FD);
+ // Just in case we're building an illegal pointer-to-member.
+ if (FD->isBitField())
+ E->setObjectKind(OK_BitField);
+ }
return E;
}
@@ -2840,6 +2901,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
// Unresolved using declarations are dependent.
case Decl::EnumConstant:
case Decl::UnresolvedUsingValue:
+ case Decl::OMPDeclareReduction:
valueKind = VK_RValue;
break;
@@ -2877,6 +2939,7 @@ ExprResult Sema::BuildDeclarationNameExpr(
case Decl::Var:
case Decl::VarTemplateSpecialization:
case Decl::VarTemplatePartialSpecialization:
+ case Decl::OMPCapturedExpr:
// In C, "extern void blah;" is valid and is an r-value.
if (!getLangOpts().CPlusPlus &&
!type.hasQualifiers() &&
@@ -3297,12 +3360,21 @@ ExprResult Sema::ActOnNumericConstant(const Token &Tok, Scope *UDLScope) {
if (Literal.isFloatingLiteral()) {
QualType Ty;
- if (Literal.isFloat)
+ if (Literal.isHalf){
+ if (getOpenCLOptions().cl_khr_fp16)
+ Ty = Context.HalfTy;
+ else {
+ Diag(Tok.getLocation(), diag::err_half_const_requires_fp16);
+ return ExprError();
+ }
+ } else if (Literal.isFloat)
Ty = Context.FloatTy;
- else if (!Literal.isLong)
- Ty = Context.DoubleTy;
- else
+ else if (Literal.isLong)
Ty = Context.LongDoubleTy;
+ else if (Literal.isFloat128)
+ Ty = Context.Float128Ty;
+ else
+ Ty = Context.DoubleTy;
Res = BuildFloatingLiteral(*this, Literal, Ty, Tok.getLocation());
@@ -3890,14 +3962,24 @@ Sema::CreateUnaryExprOrTypeTraitExpr(TypeSourceInfo *TInfo,
if (T->isVariablyModifiedType() && FunctionScopes.size() > 1) {
if (auto *TT = T->getAs<TypedefType>()) {
- if (auto *CSI = dyn_cast<CapturingScopeInfo>(FunctionScopes.back())) {
+ for (auto I = FunctionScopes.rbegin(),
+ E = std::prev(FunctionScopes.rend());
+ I != E; ++I) {
+ auto *CSI = dyn_cast<CapturingScopeInfo>(*I);
+ if (CSI == nullptr)
+ break;
DeclContext *DC = nullptr;
- if (auto LSI = dyn_cast<LambdaScopeInfo>(CSI))
+ if (auto *LSI = dyn_cast<LambdaScopeInfo>(CSI))
DC = LSI->CallOperator;
- else if (auto CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI))
+ else if (auto *CRSI = dyn_cast<CapturedRegionScopeInfo>(CSI))
DC = CRSI->TheCapturedDecl;
- if (DC && TT->getDecl()->getDeclContext() != DC)
+ else if (auto *BSI = dyn_cast<BlockScopeInfo>(CSI))
+ DC = BSI->TheDecl;
+ if (DC) {
+ if (DC->containsDecl(TT->getDecl()))
+ break;
captureVariablyModifiedType(Context, T, CSI);
+ }
}
}
}
@@ -4141,12 +4223,18 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
ExprResult Result = CheckPlaceholderExpr(LowerBound);
if (Result.isInvalid())
return ExprError();
+ Result = DefaultLvalueConversion(Result.get());
+ if (Result.isInvalid())
+ return ExprError();
LowerBound = Result.get();
}
if (Length && Length->getType()->isNonOverloadPlaceholderType()) {
ExprResult Result = CheckPlaceholderExpr(Length);
if (Result.isInvalid())
return ExprError();
+ Result = DefaultLvalueConversion(Result.get());
+ if (Result.isInvalid())
+ return ExprError();
Length = Result.get();
}
@@ -4253,6 +4341,13 @@ ExprResult Sema::ActOnOMPArraySectionExpr(Expr *Base, SourceLocation LBLoc,
return ExprError();
}
+ if (!Base->getType()->isSpecificPlaceholderType(
+ BuiltinType::OMPArraySection)) {
+ ExprResult Result = DefaultFunctionArrayLvalueConversion(Base);
+ if (Result.isInvalid())
+ return ExprError();
+ Base = Result.get();
+ }
return new (Context)
OMPArraySectionExpr(Base, LowerBound, Length, Context.OMPArraySectionTy,
VK_LValue, OK_Ordinary, ColonLoc, RBLoc);
@@ -4466,6 +4561,13 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
}
}
+ // If the default argument expression is not set yet, we are building it now.
+ if (!Param->hasInit()) {
+ Diag(Param->getLocStart(), diag::err_recursive_default_argument) << FD;
+ Param->setInvalidDecl();
+ return ExprError();
+ }
+
// If the default expression creates temporaries, we need to
// push them to the current stack of expression temporaries so they'll
// be properly destroyed.
@@ -4473,15 +4575,15 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// bound temporaries; see the comment in PR5810.
// We don't need to do that with block decls, though, because
// blocks in default argument expression can never capture anything.
- if (isa<ExprWithCleanups>(Param->getInit())) {
+ if (auto Init = dyn_cast<ExprWithCleanups>(Param->getInit())) {
// Set the "needs cleanups" bit regardless of whether there are
// any explicit objects.
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(Init->cleanupsHaveSideEffects());
// Append all the objects to the cleanup list. Right now, this
// should always be a no-op, because blocks in default argument
// expressions should never be able to capture anything.
- assert(!cast<ExprWithCleanups>(Param->getInit())->getNumObjects() &&
+ assert(!Init->getNumObjects() &&
"default argument expression has capturing blocks?");
}
@@ -4866,6 +4968,9 @@ static bool isPlaceholderToRemoveAsArg(QualType type) {
switch (placeholder->getKind()) {
// Ignore all the non-placeholder types.
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
#define PLACEHOLDER_TYPE(ID, SINGLETON_ID)
#define BUILTIN_TYPE(ID, SINGLETON_ID) case BuiltinType::ID:
#include "clang/AST/BuiltinTypes.def"
@@ -4995,6 +5100,14 @@ static FunctionDecl *rewriteBuiltinFunctionDecl(Sema *Sema, ASTContext &Context,
return OverloadDecl;
}
+static bool isNumberOfArgsValidForCall(Sema &S, const FunctionDecl *Callee,
+ std::size_t NumArgs) {
+ if (S.TooManyArguments(Callee->getNumParams(), NumArgs,
+ /*PartialOverloading=*/false))
+ return Callee->isVariadic();
+ return Callee->getMinRequiredArguments() <= NumArgs;
+}
+
/// ActOnCallExpr - Handle a call to Fn with the specified array of arguments.
/// This provides the location of the left/right parens and a list of comma
/// locations.
@@ -5032,8 +5145,6 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
// Determine whether this is a dependent call inside a C++ template,
// in which case we won't do any semantic analysis now.
- // FIXME: Will need to cache the results of name lookup (including ADL) in
- // Fn.
bool Dependent = false;
if (Fn->isTypeDependent())
Dependent = true;
@@ -5126,7 +5237,14 @@ Sema::ActOnCallExpr(Scope *S, Expr *Fn, SourceLocation LParenLoc,
Fn->getLocStart()))
return ExprError();
- if (FD->hasAttr<EnableIfAttr>()) {
+ // CheckEnableIf assumes that the we're passing in a sane number of args for
+ // FD, but that doesn't always hold true here. This is because, in some
+ // cases, we'll emit a diag about an ill-formed function call, but then
+ // we'll continue on as if the function call wasn't ill-formed. So, if the
+ // number of args looks incorrect, don't do enable_if checks; we should've
+ // already emitted an error about the bad call.
+ if (FD->hasAttr<EnableIfAttr>() &&
+ isNumberOfArgsValidForCall(*this, FD, ArgExprs.size())) {
if (const EnableIfAttr *Attr = CheckEnableIf(FD, ArgExprs, true)) {
Diag(Fn->getLocStart(),
isa<CXXMethodDecl>(FD) ?
@@ -5192,6 +5310,12 @@ Sema::BuildResolvedCallExpr(Expr *Fn, NamedDecl *NDecl,
FunctionDecl *FDecl = dyn_cast_or_null<FunctionDecl>(NDecl);
unsigned BuiltinID = (FDecl ? FDecl->getBuiltinID() : 0);
+ // Functions with 'interrupt' attribute cannot be called directly.
+ if (FDecl && FDecl->hasAttr<AnyX86InterruptAttr>()) {
+ Diag(Fn->getExprLoc(), diag::err_anyx86_interrupt_called);
+ return ExprError();
+ }
+
// Promote the function operand.
// We special-case function promotion here because we only allow promoting
// builtin functions to function pointers in the callee of a call.
@@ -5474,7 +5598,7 @@ void Sema::maybeExtendBlockObject(ExprResult &E) {
E = ImplicitCastExpr::Create(Context, E.get()->getType(),
CK_ARCExtendBlockObject, E.get(),
/*base path*/ nullptr, VK_RValue);
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
}
/// Prepare a conversion of the given expression to an ObjC object
@@ -6122,30 +6246,87 @@ static QualType checkConditionalPointerCompatibility(Sema &S, ExprResult &LHS,
lhptee = S.Context.getQualifiedType(lhptee.getUnqualifiedType(), lhQual);
rhptee = S.Context.getQualifiedType(rhptee.getUnqualifiedType(), rhQual);
+ // For OpenCL:
+ // 1. If LHS and RHS types match exactly and:
+ // (a) AS match => use standard C rules, no bitcast or addrspacecast
+ // (b) AS overlap => generate addrspacecast
+ // (c) AS don't overlap => give an error
+ // 2. if LHS and RHS types don't match:
+ // (a) AS match => use standard C rules, generate bitcast
+ // (b) AS overlap => generate addrspacecast instead of bitcast
+ // (c) AS don't overlap => give an error
+
+ // For OpenCL, non-null composite type is returned only for cases 1a and 1b.
QualType CompositeTy = S.Context.mergeTypes(lhptee, rhptee);
+ // OpenCL cases 1c, 2a, 2b, and 2c.
if (CompositeTy.isNull()) {
- S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
- << LHSTy << RHSTy << LHS.get()->getSourceRange()
- << RHS.get()->getSourceRange();
// In this situation, we assume void* type. No especially good
// reason, but this is what gcc does, and we do have to pick
// to get a consistent AST.
- QualType incompatTy = S.Context.getPointerType(S.Context.VoidTy);
- LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
+ QualType incompatTy;
+ if (S.getLangOpts().OpenCL) {
+ // OpenCL v1.1 s6.5 - Conversion between pointers to distinct address
+ // spaces is disallowed.
+ unsigned ResultAddrSpace;
+ if (lhQual.isAddressSpaceSupersetOf(rhQual)) {
+ // Cases 2a and 2b.
+ ResultAddrSpace = lhQual.getAddressSpace();
+ } else if (rhQual.isAddressSpaceSupersetOf(lhQual)) {
+ // Cases 2a and 2b.
+ ResultAddrSpace = rhQual.getAddressSpace();
+ } else {
+ // Cases 1c and 2c.
+ S.Diag(Loc,
+ diag::err_typecheck_op_on_nonoverlapping_address_space_pointers)
+ << LHSTy << RHSTy << 2 << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ // Continue handling cases 2a and 2b.
+ incompatTy = S.Context.getPointerType(
+ S.Context.getAddrSpaceQualType(S.Context.VoidTy, ResultAddrSpace));
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy,
+ (lhQual.getAddressSpace() != ResultAddrSpace)
+ ? CK_AddressSpaceConversion /* 2b */
+ : CK_BitCast /* 2a */);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy,
+ (rhQual.getAddressSpace() != ResultAddrSpace)
+ ? CK_AddressSpaceConversion /* 2b */
+ : CK_BitCast /* 2a */);
+ } else {
+ S.Diag(Loc, diag::ext_typecheck_cond_incompatible_pointers)
+ << LHSTy << RHSTy << LHS.get()->getSourceRange()
+ << RHS.get()->getSourceRange();
+ incompatTy = S.Context.getPointerType(S.Context.VoidTy);
+ LHS = S.ImpCastExprToType(LHS.get(), incompatTy, CK_BitCast);
+ RHS = S.ImpCastExprToType(RHS.get(), incompatTy, CK_BitCast);
+ }
return incompatTy;
}
// The pointer types are compatible.
QualType ResultTy = CompositeTy.withCVRQualifiers(MergedCVRQual);
+ auto LHSCastKind = CK_BitCast, RHSCastKind = CK_BitCast;
if (IsBlockPointer)
ResultTy = S.Context.getBlockPointerType(ResultTy);
- else
+ else {
+ // Cases 1a and 1b for OpenCL.
+ auto ResultAddrSpace = ResultTy.getQualifiers().getAddressSpace();
+ LHSCastKind = lhQual.getAddressSpace() == ResultAddrSpace
+ ? CK_BitCast /* 1a */
+ : CK_AddressSpaceConversion /* 1b */;
+ RHSCastKind = rhQual.getAddressSpace() == ResultAddrSpace
+ ? CK_BitCast /* 1a */
+ : CK_AddressSpaceConversion /* 1b */;
ResultTy = S.Context.getPointerType(ResultTy);
+ }
- LHS = S.ImpCastExprToType(LHS.get(), ResultTy, CK_BitCast);
- RHS = S.ImpCastExprToType(RHS.get(), ResultTy, CK_BitCast);
+ // For case 1a of OpenCL, S.ImpCastExprToType will not insert bitcast
+ // if the target type does not change.
+ LHS = S.ImpCastExprToType(LHS.get(), ResultTy, LHSCastKind);
+ RHS = S.ImpCastExprToType(RHS.get(), ResultTy, RHSCastKind);
return ResultTy;
}
@@ -6413,6 +6594,18 @@ OpenCLCheckVectorConditional(Sema &S, ExprResult &Cond,
return OpenCLConvertScalarsToVectors(S, LHS, RHS, CondTy, QuestionLoc);
}
+/// \brief Return true if the Expr is block type
+static bool checkBlockType(Sema &S, const Expr *E) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(E)) {
+ QualType Ty = CE->getCallee()->getType();
+ if (Ty->isBlockPointerType()) {
+ S.Diag(E->getExprLoc(), diag::err_opencl_ternary_with_block);
+ return true;
+ }
+ }
+ return false;
+}
+
/// Note that LHS is not null here, even if this is the gnu "x ?: y" extension.
/// In that case, LHS = cond.
/// C99 6.5.15
@@ -6462,6 +6655,22 @@ QualType Sema::CheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
QualType LHSTy = LHS.get()->getType();
QualType RHSTy = RHS.get()->getType();
+ // Diagnose attempts to convert between __float128 and long double where
+ // such conversions currently can't be handled.
+ if (unsupportedTypeConversion(*this, LHSTy, RHSTy)) {
+ Diag(QuestionLoc,
+ diag::err_typecheck_cond_incompatible_operands) << LHSTy << RHSTy
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ return QualType();
+ }
+
+ // OpenCL v2.0 s6.12.5 - Blocks cannot be used as expressions of the ternary
+ // selection operator (?:).
+ if (getLangOpts().OpenCL &&
+ (checkBlockType(*this, LHS.get()) | checkBlockType(*this, RHS.get()))) {
+ return QualType();
+ }
+
// If both operands have arithmetic type, do the usual arithmetic conversions
// to find a common type: C99 6.5.15p3,5.
if (LHSTy->isArithmeticType() && RHSTy->isArithmeticType()) {
@@ -6804,8 +7013,23 @@ ExprResult Sema::ActOnConditionalOp(SourceLocation QuestionLoc,
// doesn't handle dependent types properly, so make sure any TypoExprs have
// been dealt with before checking the operands.
ExprResult CondResult = CorrectDelayedTyposInExpr(CondExpr);
- if (!CondResult.isUsable()) return ExprError();
+ ExprResult LHSResult = CorrectDelayedTyposInExpr(LHSExpr);
+ ExprResult RHSResult = CorrectDelayedTyposInExpr(RHSExpr);
+
+ if (!CondResult.isUsable())
+ return ExprError();
+
+ if (LHSExpr) {
+ if (!LHSResult.isUsable())
+ return ExprError();
+ }
+
+ if (!RHSResult.isUsable())
+ return ExprError();
+
CondExpr = CondResult.get();
+ LHSExpr = LHSResult.get();
+ RHSExpr = RHSResult.get();
}
// If this is the gnu "x ?: y" extension, analyze the types as though the LHS
@@ -6918,7 +7142,7 @@ checkPointerTypesForAssignment(Sema &S, QualType LHSType, QualType RHSType) {
else if (lhq.getObjCLifetime() != rhq.getObjCLifetime())
ConvTy = Sema::IncompatiblePointerDiscardsQualifiers;
- // For GCC compatibility, other qualifier mismatches are treated
+ // For GCC/MS compatibility, other qualifier mismatches are treated
// as still compatible in C.
else ConvTy = Sema::CompatiblePointerDiscardsQualifiers;
}
@@ -7170,9 +7394,30 @@ Sema::CheckAssignmentConstraints(QualType LHSType, ExprResult &RHS,
return IncompatibleVectors;
}
}
+
+ // When the RHS comes from another lax conversion (e.g. binops between
+ // scalars and vectors) the result is canonicalized as a vector. When the
+ // LHS is also a vector, the lax is allowed by the condition above. Handle
+ // the case where LHS is a scalar.
+ if (LHSType->isScalarType()) {
+ const VectorType *VecType = RHSType->getAs<VectorType>();
+ if (VecType && VecType->getNumElements() == 1 &&
+ isLaxVectorConversion(RHSType, LHSType)) {
+ ExprResult *VecExpr = &RHS;
+ *VecExpr = ImpCastExprToType(VecExpr->get(), LHSType, CK_BitCast);
+ Kind = CK_BitCast;
+ return Compatible;
+ }
+ }
+
return Incompatible;
}
+ // Diagnose attempts to convert between __float128 and long double where
+ // such conversions currently can't be handled.
+ if (unsupportedTypeConversion(*this, LHSType, RHSType))
+ return Incompatible;
+
// Arithmetic conversions.
if (LHSType->isArithmeticType() && RHSType->isArithmeticType() &&
!(getLangOpts().CPlusPlus && LHSType->isEnumeralType())) {
@@ -7539,13 +7784,24 @@ Sema::CheckSingleAssignmentConstraints(QualType LHSType, ExprResult &CallerRHS,
if (result != Incompatible && RHS.get()->getType() != LHSType) {
QualType Ty = LHSType.getNonLValueExprType(Context);
Expr *E = RHS.get();
- if (getLangOpts().ObjCAutoRefCount)
- CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
- Diagnose, DiagnoseCFAudited);
+
+ // Check for various Objective-C errors. If we are not reporting
+ // diagnostics and just checking for errors, e.g., during overload
+ // resolution, return Incompatible to indicate the failure.
+ if (getLangOpts().ObjCAutoRefCount &&
+ CheckObjCARCConversion(SourceRange(), Ty, E, CCK_ImplicitConversion,
+ Diagnose, DiagnoseCFAudited) != ACR_okay) {
+ if (!Diagnose)
+ return Incompatible;
+ }
if (getLangOpts().ObjC1 &&
(CheckObjCBridgeRelatedConversions(E->getLocStart(), LHSType,
E->getType(), E, Diagnose) ||
ConversionToObjCStringLiteralCheck(LHSType, E, Diagnose))) {
+ if (!Diagnose)
+ return Incompatible;
+ // Replace the expression with a corrected version and continue so we
+ // can find further errors.
RHS = E;
return Compatible;
}
@@ -7693,14 +7949,16 @@ QualType Sema::CheckVectorOperands(ExprResult &LHS, ExprResult &RHS,
return RHSType;
}
- // If we're allowing lax vector conversions, only the total (data) size
- // needs to be the same.
- // FIXME: Should we really be allowing this?
- // FIXME: We really just pick the LHS type arbitrarily?
- if (isLaxVectorConversion(RHSType, LHSType)) {
- QualType resultType = LHSType;
- RHS = ImpCastExprToType(RHS.get(), resultType, CK_BitCast);
- return resultType;
+ // If we're allowing lax vector conversions, only the total (data) size needs
+ // to be the same. If one of the types is scalar, the result is always the
+ // vector type. Don't allow this if the scalar operand is an lvalue.
+ QualType VecType = LHSVecType ? LHSType : RHSType;
+ QualType ScalarType = LHSVecType ? RHSType : LHSType;
+ ExprResult *ScalarExpr = LHSVecType ? &RHS : &LHS;
+ if (isLaxVectorConversion(ScalarType, VecType) &&
+ !ScalarExpr->get()->isLValue()) {
+ *ScalarExpr = ImpCastExprToType(ScalarExpr->get(), VecType, CK_BitCast);
+ return VecType;
}
// Okay, the expression is invalid.
@@ -9244,7 +9502,7 @@ QualType Sema::CheckVectorCompareOperands(ExprResult &LHS, ExprResult &RHS,
}
// Return a signed type for the vector.
- return GetSignedVectorType(LHSType);
+ return GetSignedVectorType(vType);
}
QualType Sema::CheckVectorLogicalOperands(ExprResult &LHS, ExprResult &RHS,
@@ -9411,7 +9669,16 @@ static NonConstCaptureKind isReferenceToNonConstCapture(Sema &S, Expr *E) {
// Decide whether the first capture was for a block or a lambda.
DeclContext *DC = S.CurContext, *Prev = nullptr;
- while (DC != var->getDeclContext()) {
+ // Decide whether the first capture was for a block or a lambda.
+ while (DC) {
+ // For init-capture, it is possible that the variable belongs to the
+ // template pattern of the current context.
+ if (auto *FD = dyn_cast<FunctionDecl>(DC))
+ if (var->isInitCapture() &&
+ FD->getTemplateInstantiationPattern() == var->getDeclContext())
+ break;
+ if (DC == var->getDeclContext())
+ break;
Prev = DC;
DC = DC->getParent();
}
@@ -9558,6 +9825,9 @@ static void DiagnoseConstAssignment(Sema &S, const Expr *E,
/// emit an error and return true. If so, return false.
static bool CheckForModifiableLvalue(Expr *E, SourceLocation Loc, Sema &S) {
assert(!E->hasPlaceholderType(BuiltinType::PseudoObject));
+
+ S.CheckShadowingDeclModification(E, Loc);
+
SourceLocation OrigLoc = Loc;
Expr::isModifiableLvalueResult IsLV = E->isModifiableLvalue(S.Context,
&Loc);
@@ -9798,6 +10068,67 @@ QualType Sema::CheckAssignmentOperands(Expr *LHSExpr, ExprResult &RHS,
? LHSType : LHSType.getUnqualifiedType());
}
+// Only ignore explicit casts to void.
+static bool IgnoreCommaOperand(const Expr *E) {
+ E = E->IgnoreParens();
+
+ if (const CastExpr *CE = dyn_cast<CastExpr>(E)) {
+ if (CE->getCastKind() == CK_ToVoid) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+// Look for instances where it is likely the comma operator is confused with
+// another operator. There is a whitelist of acceptable expressions for the
+// left hand side of the comma operator, otherwise emit a warning.
+void Sema::DiagnoseCommaOperator(const Expr *LHS, SourceLocation Loc) {
+ // No warnings in macros
+ if (Loc.isMacroID())
+ return;
+
+ // Don't warn in template instantiations.
+ if (!ActiveTemplateInstantiations.empty())
+ return;
+
+ // Scope isn't fine-grained enough to whitelist the specific cases, so
+ // instead, skip more than needed, then call back into here with the
+ // CommaVisitor in SemaStmt.cpp.
+ // The whitelisted locations are the initialization and increment portions
+ // of a for loop. The additional checks are on the condition of
+ // if statements, do/while loops, and for loops.
+ const unsigned ForIncrementFlags =
+ Scope::ControlScope | Scope::ContinueScope | Scope::BreakScope;
+ const unsigned ForInitFlags = Scope::ControlScope | Scope::DeclScope;
+ const unsigned ScopeFlags = getCurScope()->getFlags();
+ if ((ScopeFlags & ForIncrementFlags) == ForIncrementFlags ||
+ (ScopeFlags & ForInitFlags) == ForInitFlags)
+ return;
+
+ // If there are multiple comma operators used together, get the RHS of the
+ // of the comma operator as the LHS.
+ while (const BinaryOperator *BO = dyn_cast<BinaryOperator>(LHS)) {
+ if (BO->getOpcode() != BO_Comma)
+ break;
+ LHS = BO->getRHS();
+ }
+
+ // Only allow some expressions on LHS to not warn.
+ if (IgnoreCommaOperand(LHS))
+ return;
+
+ Diag(Loc, diag::warn_comma_operator);
+ Diag(LHS->getLocStart(), diag::note_cast_to_void)
+ << LHS->getSourceRange()
+ << FixItHint::CreateInsertion(LHS->getLocStart(),
+ LangOpts.CPlusPlus ? "static_cast<void>("
+ : "(void)(")
+ << FixItHint::CreateInsertion(PP.getLocForEndOfToken(LHS->getLocEnd()),
+ ")");
+}
+
// C99 6.5.17
static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
SourceLocation Loc) {
@@ -9827,6 +10158,9 @@ static QualType CheckCommaOperands(Sema &S, ExprResult &LHS, ExprResult &RHS,
diag::err_incomplete_type);
}
+ if (!S.getDiagnostics().isIgnored(diag::warn_comma_operator, Loc))
+ S.DiagnoseCommaOperator(LHS.get(), Loc);
+
return RHS.get()->getType();
}
@@ -10075,8 +10409,8 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
if (sfinae)
return QualType();
// Materialize the temporary as an lvalue so that we can take its address.
- OrigOp = op = new (Context)
- MaterializeTemporaryExpr(op->getType(), OrigOp.get(), true);
+ OrigOp = op =
+ CreateMaterializeTemporaryExpr(op->getType(), OrigOp.get(), true);
} else if (isa<ObjCSelectorExpr>(op)) {
return Context.getPointerType(op->getType());
} else if (lval == Expr::LV_MemberFunction) {
@@ -10199,6 +10533,7 @@ QualType Sema::CheckAddressOfOperand(ExprResult &OrigOp, SourceLocation OpLoc) {
// If the operand has type "type", the result has type "pointer to type".
if (op->getType()->isObjCObjectType())
return Context.getObjCObjectPointerType(op->getType());
+
return Context.getPointerType(op->getType());
}
@@ -10240,7 +10575,9 @@ static QualType CheckIndirectionOperand(Sema &S, Expr *Op, ExprValueKind &VK,
}
if (const PointerType *PT = OpTy->getAs<PointerType>())
+ {
Result = PT->getPointeeType();
+ }
else if (const ObjCObjectPointerType *OPT =
OpTy->getAs<ObjCObjectPointerType>())
Result = OPT->getPointeeType();
@@ -10478,10 +10815,11 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
}
if (getLangOpts().OpenCL) {
+ QualType LHSTy = LHSExpr->getType();
+ QualType RHSTy = RHSExpr->getType();
// OpenCLC v2.0 s6.13.11.1 allows atomic variables to be initialized by
// the ATOMIC_VAR_INIT macro.
- if (LHSExpr->getType()->isAtomicType() ||
- RHSExpr->getType()->isAtomicType()) {
+ if (LHSTy->isAtomicType() || RHSTy->isAtomicType()) {
SourceRange SR(LHSExpr->getLocStart(), RHSExpr->getLocEnd());
if (BO_Assign == Opc)
Diag(OpLoc, diag::err_atomic_init_constant) << SR;
@@ -10489,6 +10827,16 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc,
ResultTy = InvalidOperands(OpLoc, LHS, RHS);
return ExprError();
}
+
+ // OpenCL special types - image, sampler, pipe, and blocks are to be used
+ // only with a builtin functions and therefore should be disallowed here.
+ if (LHSTy->isImageType() || RHSTy->isImageType() ||
+ LHSTy->isSamplerT() || RHSTy->isSamplerT() ||
+ LHSTy->isPipeType() || RHSTy->isPipeType() ||
+ LHSTy->isBlockPointerType() || RHSTy->isBlockPointerType()) {
+ ResultTy = InvalidOperands(OpLoc, LHS, RHS);
+ return ExprError();
+ }
}
switch (Opc) {
@@ -10959,8 +11307,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc,
ExprObjectKind OK = OK_Ordinary;
QualType resultType;
if (getLangOpts().OpenCL) {
+ QualType Ty = InputExpr->getType();
// The only legal unary operation for atomics is '&'.
- if (Opc != UO_AddrOf && InputExpr->getType()->isAtomicType()) {
+ if ((Opc != UO_AddrOf && Ty->isAtomicType()) ||
+ // OpenCL special types - image, sampler, pipe, and blocks are to be used
+ // only with a builtin functions and therefore should be disallowed here.
+ (Ty->isImageType() || Ty->isSamplerT() || Ty->isPipeType()
+ || Ty->isBlockPointerType())) {
return ExprError(Diag(OpLoc, diag::err_typecheck_unary_expr)
<< InputExpr->getType()
<< Input.get()->getSourceRange());
@@ -11273,7 +11626,8 @@ Sema::ActOnStmtExpr(SourceLocation LPLoc, Stmt *SubStmt,
if (hasAnyUnrecoverableErrorsInThisFunction())
DiscardCleanupsInEvaluationContext();
- assert(!ExprNeedsCleanups && "cleanups within StmtExpr not correctly bound!");
+ assert(!Cleanup.exprNeedsCleanups() &&
+ "cleanups within StmtExpr not correctly bound!");
PopExpressionEvaluationContext();
// FIXME: there are a variety of strange constraints to enforce here, for
@@ -11697,8 +12051,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
// Set the parameters on the block decl.
if (!Params.empty()) {
CurBlock->TheDecl->setParams(Params);
- CheckParmsForFunctionDef(CurBlock->TheDecl->param_begin(),
- CurBlock->TheDecl->param_end(),
+ CheckParmsForFunctionDef(CurBlock->TheDecl->parameters(),
/*CheckParameterNames=*/false);
}
@@ -11706,7 +12059,7 @@ void Sema::ActOnBlockArguments(SourceLocation CaretLoc, Declarator &ParamInfo,
ProcessDeclAttributes(CurScope, CurBlock->TheDecl, ParamInfo);
// Put the parameter variables in scope.
- for (auto AI : CurBlock->TheDecl->params()) {
+ for (auto AI : CurBlock->TheDecl->parameters()) {
AI->setOwningFunction(CurBlock->TheDecl);
// If this has an identifier, add it to the scope stack.
@@ -11736,12 +12089,13 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
Stmt *Body, Scope *CurScope) {
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
- Diag(CaretLoc, diag::err_blocks_disable);
+ Diag(CaretLoc, diag::err_blocks_disable) << LangOpts.OpenCL;
// Leave the expression-evaluation context.
if (hasAnyUnrecoverableErrorsInThisFunction())
DiscardCleanupsInEvaluationContext();
- assert(!ExprNeedsCleanups && "cleanups within block not correctly bound!");
+ assert(!Cleanup.exprNeedsCleanups() &&
+ "cleanups within block not correctly bound!");
PopExpressionEvaluationContext();
BlockScopeInfo *BSI = cast<BlockScopeInfo>(FunctionScopes.back());
@@ -11805,8 +12159,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
BlockTy = Context.getFunctionType(RetTy, None, EPI);
}
- DiagnoseUnusedParameters(BSI->TheDecl->param_begin(),
- BSI->TheDecl->param_end());
+ DiagnoseUnusedParameters(BSI->TheDecl->parameters());
BlockTy = Context.getBlockPointerType(BlockTy);
// If needed, diagnose invalid gotos and switches in the block.
@@ -11832,7 +12185,7 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
if (Result->getBlockDecl()->hasCaptures()) {
// First, this expression has a new cleanup object.
ExprCleanupObjects.push_back(Result->getBlockDecl());
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
// It also gets a branch-protected scope if any of the captured
// variables needs destruction.
@@ -11848,9 +12201,8 @@ ExprResult Sema::ActOnBlockStmtExpr(SourceLocation CaretLoc,
return Result;
}
-ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc,
- Expr *E, ParsedType Ty,
- SourceLocation RPLoc) {
+ExprResult Sema::ActOnVAArg(SourceLocation BuiltinLoc, Expr *E, ParsedType Ty,
+ SourceLocation RPLoc) {
TypeSourceInfo *TInfo;
GetTypeFromParser(Ty, &TInfo);
return BuildVAArgExpr(BuiltinLoc, E, TInfo, RPLoc);
@@ -11862,6 +12214,15 @@ ExprResult Sema::BuildVAArgExpr(SourceLocation BuiltinLoc,
Expr *OrigExpr = E;
bool IsMS = false;
+ // CUDA device code does not support varargs.
+ if (getLangOpts().CUDA && getLangOpts().CUDAIsDevice) {
+ if (const FunctionDecl *F = dyn_cast<FunctionDecl>(CurContext)) {
+ CUDAFunctionTarget T = IdentifyCUDATarget(F);
+ if (T == CFT_Global || T == CFT_Device || T == CFT_HostDevice)
+ return ExprError(Diag(E->getLocStart(), diag::err_va_arg_in_device));
+ }
+ }
+
// It might be a __builtin_ms_va_list. (But don't ever mark a va_arg()
// as Microsoft ABI on an actual Microsoft platform, where
// __builtin_ms_va_list and __builtin_va_list are the same.)
@@ -12000,10 +12361,11 @@ bool Sema::ConversionToObjCStringLiteralCheck(QualType DstType, Expr *&Exp,
StringLiteral *SL = dyn_cast<StringLiteral>(SrcExpr);
if (!SL || !SL->isAscii())
return false;
- if (Diagnose)
+ if (Diagnose) {
Diag(SL->getLocStart(), diag::err_missing_atsign_prefix)
<< FixItHint::CreateInsertion(SL->getLocStart(), "@");
- Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get();
+ Exp = BuildObjCStringLiteral(SL->getLocStart(), SL).get();
+ }
return true;
}
@@ -12460,10 +12822,9 @@ void
Sema::PushExpressionEvaluationContext(ExpressionEvaluationContext NewContext,
Decl *LambdaContextDecl,
bool IsDecltype) {
- ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(),
- ExprNeedsCleanups, LambdaContextDecl,
- IsDecltype);
- ExprNeedsCleanups = false;
+ ExprEvalContexts.emplace_back(NewContext, ExprCleanupObjects.size(), Cleanup,
+ LambdaContextDecl, IsDecltype);
+ Cleanup.reset();
if (!MaybeODRUseExprs.empty())
std::swap(MaybeODRUseExprs, ExprEvalContexts.back().SavedMaybeODRUseExprs);
}
@@ -12514,12 +12875,12 @@ void Sema::PopExpressionEvaluationContext() {
if (Rec.isUnevaluated() || Rec.Context == ConstantEvaluated) {
ExprCleanupObjects.erase(ExprCleanupObjects.begin() + Rec.NumCleanupObjects,
ExprCleanupObjects.end());
- ExprNeedsCleanups = Rec.ParentNeedsCleanups;
+ Cleanup = Rec.ParentCleanup;
CleanupVarDeclMarking();
std::swap(MaybeODRUseExprs, Rec.SavedMaybeODRUseExprs);
// Otherwise, merge the contexts together.
} else {
- ExprNeedsCleanups |= Rec.ParentNeedsCleanups;
+ Cleanup.mergeFrom(Rec.ParentCleanup);
MaybeODRUseExprs.insert(Rec.SavedMaybeODRUseExprs.begin(),
Rec.SavedMaybeODRUseExprs.end());
}
@@ -12538,7 +12899,7 @@ void Sema::DiscardCleanupsInEvaluationContext() {
ExprCleanupObjects.erase(
ExprCleanupObjects.begin() + ExprEvalContexts.back().NumCleanupObjects,
ExprCleanupObjects.end());
- ExprNeedsCleanups = false;
+ Cleanup.reset();
MaybeODRUseExprs.clear();
}
@@ -12563,6 +12924,11 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
// definition of a null pointer constant is completely crazy.)
return false;
+ case Sema::DiscardedStatement:
+ // These are technically a potentially evaluated but they have the effect
+ // of suppressing use marking.
+ return false;
+
case Sema::ConstantEvaluated:
case Sema::PotentiallyEvaluated:
// We are in a potentially evaluated expression (or a constant-expression
@@ -12581,7 +12947,7 @@ static bool IsPotentiallyEvaluatedContext(Sema &SemaRef) {
/// \brief Mark a function referenced, and check whether it is odr-used
/// (C++ [basic.def.odr]p2, C99 6.9p3)
void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
- bool OdrUse) {
+ bool MightBeOdrUse) {
assert(Func && "No function?");
Func->setReferenced();
@@ -12592,39 +12958,53 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// set of overloaded functions [...].
//
// We (incorrectly) mark overload resolution as an unevaluated context, so we
- // can just check that here. Skip the rest of this function if we've already
- // marked the function as used.
- if (Func->isUsed(/*CheckUsedAttr=*/false) ||
- !IsPotentiallyEvaluatedContext(*this)) {
- // C++11 [temp.inst]p3:
- // Unless a function template specialization has been explicitly
- // instantiated or explicitly specialized, the function template
- // specialization is implicitly instantiated when the specialization is
- // referenced in a context that requires a function definition to exist.
- //
- // We consider constexpr function templates to be referenced in a context
- // that requires a definition to exist whenever they are referenced.
- //
- // FIXME: This instantiates constexpr functions too frequently. If this is
- // really an unevaluated context (and we're not just in the definition of a
- // function template or overload resolution or other cases which we
- // incorrectly consider to be unevaluated contexts), and we're not in a
- // subexpression which we actually need to evaluate (for instance, a
- // template argument, array bound or an expression in a braced-init-list),
- // we are not permitted to instantiate this constexpr function definition.
- //
- // FIXME: This also implicitly defines special members too frequently. They
- // are only supposed to be implicitly defined if they are odr-used, but they
- // are not odr-used from constant expressions in unevaluated contexts.
- // However, they cannot be referenced if they are deleted, and they are
- // deleted whenever the implicit definition of the special member would
- // fail.
- if (!Func->isConstexpr() || Func->getBody())
- return;
- CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
- if (!Func->isImplicitlyInstantiable() && (!MD || MD->isUserProvided()))
- return;
- }
+ // can just check that here.
+ bool OdrUse = MightBeOdrUse && IsPotentiallyEvaluatedContext(*this);
+
+ // Determine whether we require a function definition to exist, per
+ // C++11 [temp.inst]p3:
+ // Unless a function template specialization has been explicitly
+ // instantiated or explicitly specialized, the function template
+ // specialization is implicitly instantiated when the specialization is
+ // referenced in a context that requires a function definition to exist.
+ //
+ // We consider constexpr function templates to be referenced in a context
+ // that requires a definition to exist whenever they are referenced.
+ //
+ // FIXME: This instantiates constexpr functions too frequently. If this is
+ // really an unevaluated context (and we're not just in the definition of a
+ // function template or overload resolution or other cases which we
+ // incorrectly consider to be unevaluated contexts), and we're not in a
+ // subexpression which we actually need to evaluate (for instance, a
+ // template argument, array bound or an expression in a braced-init-list),
+ // we are not permitted to instantiate this constexpr function definition.
+ //
+ // FIXME: This also implicitly defines special members too frequently. They
+ // are only supposed to be implicitly defined if they are odr-used, but they
+ // are not odr-used from constant expressions in unevaluated contexts.
+ // However, they cannot be referenced if they are deleted, and they are
+ // deleted whenever the implicit definition of the special member would
+ // fail (with very few exceptions).
+ CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(Func);
+ bool NeedDefinition =
+ OdrUse || (Func->isConstexpr() && (Func->isImplicitlyInstantiable() ||
+ (MD && !MD->isUserProvided())));
+
+ // C++14 [temp.expl.spec]p6:
+ // If a template [...] is explicitly specialized then that specialization
+ // shall be declared before the first use of that specialization that would
+ // cause an implicit instantiation to take place, in every translation unit
+ // in which such a use occurs
+ if (NeedDefinition &&
+ (Func->getTemplateSpecializationKind() != TSK_Undeclared ||
+ Func->getMemberSpecializationInfo()))
+ checkSpecializationVisibility(Loc, Func);
+
+ // If we don't need to mark the function as used, and we don't need to
+ // try to provide a definition, there's nothing more to do.
+ if ((Func->isUsed(/*CheckUsedAttr=*/false) || !OdrUse) &&
+ (!NeedDefinition || Func->getBody()))
+ return;
// Note that this declaration has been used.
if (CXXConstructorDecl *Constructor = dyn_cast<CXXConstructorDecl>(Func)) {
@@ -12659,7 +13039,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (MethodDecl->isDefaulted() && !MethodDecl->isDeleted()) {
if (MethodDecl->isCopyAssignmentOperator())
DefineImplicitCopyAssignment(Loc, MethodDecl);
- else
+ else if (MethodDecl->isMoveAssignmentOperator())
DefineImplicitMoveAssignment(Loc, MethodDecl);
}
} else if (isa<CXXConversionDecl>(MethodDecl) &&
@@ -12684,8 +13064,6 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
if (FPT && isUnresolvedExceptionSpec(FPT->getExceptionSpecType()))
ResolveExceptionSpec(Loc, FPT);
- if (!OdrUse) return;
-
// Implicit instantiation of function templates and member functions of
// class templates.
if (Func->isImplicitlyInstantiable()) {
@@ -12733,10 +13111,12 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
// Walk redefinitions, as some of them may be instantiable.
for (auto i : Func->redecls()) {
if (!i->isUsed(false) && i->isImplicitlyInstantiable())
- MarkFunctionReferenced(Loc, i);
+ MarkFunctionReferenced(Loc, i, OdrUse);
}
}
+ if (!OdrUse) return;
+
// Keep track of used but undefined functions.
if (!Func->isDefined()) {
if (mightHaveNonExternalLinkage(Func))
@@ -12747,17 +13127,7 @@ void Sema::MarkFunctionReferenced(SourceLocation Loc, FunctionDecl *Func,
UndefinedButUsed.insert(std::make_pair(Func->getCanonicalDecl(), Loc));
}
- // Normally the most current decl is marked used while processing the use and
- // any subsequent decls are marked used by decl merging. This fails with
- // template instantiation since marking can happen at the end of the file
- // and, because of the two phase lookup, this function is called with at
- // decl in the middle of a decl chain. We loop to maintain the invariant
- // that once a decl is used, all decls after it are also used.
- for (FunctionDecl *F = Func->getMostRecentDecl();; F = F->getPreviousDecl()) {
- F->markUsed(Context);
- if (F == Func)
- break;
- }
+ Func->markUsed(Context);
}
static void
@@ -12945,7 +13315,8 @@ static bool captureInBlock(BlockScopeInfo *BSI, VarDecl *Var,
return false;
}
const bool HasBlocksAttr = Var->hasAttr<BlocksAttr>();
- if (HasBlocksAttr || CaptureType->isReferenceType()) {
+ if (HasBlocksAttr || CaptureType->isReferenceType() ||
+ (S.getLangOpts().OpenMP && S.IsOpenMPCapturedDecl(Var))) {
// Block capture by reference does not change the capture or
// declaration reference types.
ByRef = true;
@@ -13013,14 +13384,13 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
QualType &DeclRefType,
const bool RefersToCapturedVariable,
Sema &S) {
-
// By default, capture variables by reference.
bool ByRef = true;
// Using an LValue reference type is consistent with Lambdas (see below).
- if (S.getLangOpts().OpenMP) {
- ByRef = S.IsOpenMPCapturedByRef(Var, RSI);
- if (S.IsOpenMPCapturedVar(Var))
+ if (S.getLangOpts().OpenMP && RSI->CapRegionKind == CR_OpenMP) {
+ if (S.IsOpenMPCapturedDecl(Var))
DeclRefType = DeclRefType.getUnqualifiedType();
+ ByRef = S.IsOpenMPCapturedByRef(Var, RSI->OpenMPLevel);
}
if (ByRef)
@@ -13060,7 +13430,7 @@ static bool captureInCapturedRegion(CapturedRegionScopeInfo *RSI,
/// \brief Create a field within the lambda class for the variable
/// being captured.
-static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI, VarDecl *Var,
+static void addAsFieldToClosureType(Sema &S, LambdaScopeInfo *LSI,
QualType FieldType, QualType DeclRefType,
SourceLocation Loc,
bool RefersToCapturedVariable) {
@@ -13154,7 +13524,7 @@ static bool captureInLambda(LambdaScopeInfo *LSI,
// Capture this variable in the lambda.
if (BuildAndDiagnose)
- addAsFieldToClosureType(S, LSI, Var, CaptureType, DeclRefType, Loc,
+ addAsFieldToClosureType(S, LSI, CaptureType, DeclRefType, Loc,
RefersToCapturedVariable);
// Compute the type of a reference to this captured variable.
@@ -13210,7 +13580,7 @@ bool Sema::tryCaptureVariable(
// Capture global variables if it is required to use private copy of this
// variable.
bool IsGlobal = !Var->hasLocalStorage();
- if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedVar(Var)))
+ if (IsGlobal && !(LangOpts.OpenMP && IsOpenMPCapturedDecl(Var)))
return true;
// Walk up the stack to determine whether we can capture the variable,
@@ -13226,7 +13596,6 @@ bool Sema::tryCaptureVariable(
bool Nested = false;
bool Explicit = (Kind != TryCapture_Implicit);
unsigned FunctionScopesIndex = MaxFunctionScopesIndex;
- unsigned OpenMPLevel = 0;
do {
// Only block literals, captured statements, and lambda expressions can
// capture; other scopes don't work.
@@ -13292,20 +13661,19 @@ bool Sema::tryCaptureVariable(
// just break here. Similarly, global variables that are captured in a
// target region should not be captured outside the scope of the region.
if (RSI->CapRegionKind == CR_OpenMP) {
- auto isTargetCap = isOpenMPTargetCapturedVar(Var, OpenMPLevel);
+ auto IsTargetCap = isOpenMPTargetCapturedDecl(Var, RSI->OpenMPLevel);
// When we detect target captures we are looking from inside the
// target region, therefore we need to propagate the capture from the
// enclosing region. Therefore, the capture is not initially nested.
- if (isTargetCap)
+ if (IsTargetCap)
FunctionScopesIndex--;
- if (isTargetCap || isOpenMPPrivateVar(Var, OpenMPLevel)) {
- Nested = !isTargetCap;
+ if (IsTargetCap || isOpenMPPrivateDecl(Var, RSI->OpenMPLevel)) {
+ Nested = !IsTargetCap;
DeclRefType = DeclRefType.getUnqualifiedType();
CaptureType = Context.getLValueReferenceType(DeclRefType);
break;
}
- ++OpenMPLevel;
}
}
}
@@ -13316,8 +13684,9 @@ bool Sema::tryCaptureVariable(
Diag(ExprLoc, diag::err_lambda_impcap) << Var->getDeclName();
Diag(Var->getLocation(), diag::note_previous_decl)
<< Var->getDeclName();
- Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
- diag::note_lambda_decl);
+ if (cast<LambdaScopeInfo>(CSI)->Lambda)
+ Diag(cast<LambdaScopeInfo>(CSI)->Lambda->getLocStart(),
+ diag::note_lambda_decl);
// FIXME: If we error out because an outer lambda can not implicitly
// capture a variable that an inner lambda explicitly captures, we
// should have the inner lambda do the explicit capture - because
@@ -13539,6 +13908,12 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
"Can't instantiate a partial template specialization.");
+ // If this might be a member specialization of a static data member, check
+ // the specialization is visible. We already did the checks for variable
+ // template specializations when we created them.
+ if (TSK != TSK_Undeclared && !isa<VarTemplateSpecializationDecl>(Var))
+ SemaRef.checkSpecializationVisibility(Loc, Var);
+
// Perform implicit instantiation of static data members, static data member
// templates of class templates, and variable template specializations. Delay
// instantiations of variable templates, except for those that could be used
@@ -13582,7 +13957,8 @@ static void DoMarkVarDeclReferenced(Sema &SemaRef, SourceLocation Loc,
}
}
- if(!MarkODRUsed) return;
+ if (!MarkODRUsed)
+ return;
// Per C++11 [basic.def.odr], a variable is odr-used "unless it satisfies
// the requirements for appearing in a constant expression (5.19) and, if
@@ -13610,13 +13986,16 @@ void Sema::MarkVariableReferenced(SourceLocation Loc, VarDecl *Var) {
}
static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
- Decl *D, Expr *E, bool OdrUse) {
+ Decl *D, Expr *E, bool MightBeOdrUse) {
+ if (SemaRef.isInOpenMPDeclareTargetContext())
+ SemaRef.checkDeclIsAllowedInOpenMPTarget(E, D);
+
if (VarDecl *Var = dyn_cast<VarDecl>(D)) {
DoMarkVarDeclReferenced(SemaRef, Loc, Var, E);
return;
}
- SemaRef.MarkAnyDeclReferenced(Loc, D, OdrUse);
+ SemaRef.MarkAnyDeclReferenced(Loc, D, MightBeOdrUse);
// If this is a call to a method via a cast, also mark the method in the
// derived class used in case codegen can devirtualize the call.
@@ -13638,7 +14017,7 @@ static void MarkExprReferenced(Sema &SemaRef, SourceLocation Loc,
CXXMethodDecl *DM = MD->getCorrespondingMethodInClass(MostDerivedClassDecl);
if (!DM || DM->isPure())
return;
- SemaRef.MarkAnyDeclReferenced(Loc, DM, OdrUse);
+ SemaRef.MarkAnyDeclReferenced(Loc, DM, MightBeOdrUse);
}
/// \brief Perform reference-marking and odr-use handling for a DeclRefExpr.
@@ -13661,30 +14040,31 @@ void Sema::MarkMemberReferenced(MemberExpr *E) {
// overload resolution when referred to from a potentially-evaluated
// expression, is odr-used, unless it is a pure virtual function and its
// name is not explicitly qualified.
- bool OdrUse = true;
+ bool MightBeOdrUse = true;
if (E->performsVirtualDispatch(getLangOpts())) {
if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(E->getMemberDecl()))
if (Method->isPure())
- OdrUse = false;
+ MightBeOdrUse = false;
}
SourceLocation Loc = E->getMemberLoc().isValid() ?
E->getMemberLoc() : E->getLocStart();
- MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, OdrUse);
+ MarkExprReferenced(*this, Loc, E->getMemberDecl(), E, MightBeOdrUse);
}
/// \brief Perform marking for a reference to an arbitrary declaration. It
/// marks the declaration referenced, and performs odr-use checking for
/// functions and variables. This method should not be used when building a
/// normal expression which refers to a variable.
-void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D, bool OdrUse) {
- if (OdrUse) {
+void Sema::MarkAnyDeclReferenced(SourceLocation Loc, Decl *D,
+ bool MightBeOdrUse) {
+ if (MightBeOdrUse) {
if (auto *VD = dyn_cast<VarDecl>(D)) {
MarkVariableReferenced(Loc, VD);
return;
}
}
if (auto *FD = dyn_cast<FunctionDecl>(D)) {
- MarkFunctionReferenced(Loc, FD, OdrUse);
+ MarkFunctionReferenced(Loc, FD, MightBeOdrUse);
return;
}
D->setReferenced();
@@ -13838,6 +14218,7 @@ bool Sema::DiagRuntimeBehavior(SourceLocation Loc, const Stmt *Statement,
switch (ExprEvalContexts.back().Context) {
case Unevaluated:
case UnevaluatedAbstract:
+ case DiscardedStatement:
// The argument will never be evaluated, so don't complain.
break;
@@ -13987,7 +14368,8 @@ void Sema::DiagnoseEqualityWithExtraParens(ParenExpr *ParenE) {
}
}
-ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
+ExprResult Sema::CheckBooleanCondition(SourceLocation Loc, Expr *E,
+ bool IsConstexpr) {
DiagnoseAssignmentAsCondition(E);
if (ParenExpr *parenE = dyn_cast<ParenExpr>(E))
DiagnoseEqualityWithExtraParens(parenE);
@@ -13998,7 +14380,7 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
if (!E->isTypeDependent()) {
if (getLangOpts().CPlusPlus)
- return CheckCXXBooleanCondition(E); // C++ 6.4p4
+ return CheckCXXBooleanCondition(E, IsConstexpr); // C++ 6.4p4
ExprResult ERes = DefaultFunctionArrayLvalueConversion(E);
if (ERes.isInvalid())
@@ -14017,12 +14399,36 @@ ExprResult Sema::CheckBooleanCondition(Expr *E, SourceLocation Loc) {
return E;
}
-ExprResult Sema::ActOnBooleanCondition(Scope *S, SourceLocation Loc,
- Expr *SubExpr) {
+Sema::ConditionResult Sema::ActOnCondition(Scope *S, SourceLocation Loc,
+ Expr *SubExpr, ConditionKind CK) {
+ // Empty conditions are valid in for-statements.
if (!SubExpr)
- return ExprError();
+ return ConditionResult();
- return CheckBooleanCondition(SubExpr, Loc);
+ ExprResult Cond;
+ switch (CK) {
+ case ConditionKind::Boolean:
+ Cond = CheckBooleanCondition(Loc, SubExpr);
+ break;
+
+ case ConditionKind::ConstexprIf:
+ Cond = CheckBooleanCondition(Loc, SubExpr, true);
+ break;
+
+ case ConditionKind::Switch:
+ Cond = CheckSwitchCondition(Loc, SubExpr);
+ break;
+ }
+ if (Cond.isInvalid())
+ return ConditionError();
+
+ // FIXME: FullExprArg doesn't have an invalid bit, so check nullness instead.
+ FullExprArg FullExpr = MakeFullExpr(Cond.get(), Loc);
+ if (!FullExpr.get())
+ return ConditionError();
+
+ return ConditionResult(*this, nullptr, FullExpr,
+ CK == ConditionKind::ConstexprIf);
}
namespace {
@@ -14457,6 +14863,12 @@ ExprResult RebuildUnknownAnyExpr::resolveDecl(Expr *E, ValueDecl *VD) {
ExprResult Sema::checkUnknownAnyCast(SourceRange TypeRange, QualType CastType,
Expr *CastExpr, CastKind &CastKind,
ExprValueKind &VK, CXXCastPath &Path) {
+ // The type we're casting to must be either void or complete.
+ if (!CastType->isVoidType() &&
+ RequireCompleteType(TypeRange.getBegin(), CastType,
+ diag::err_typecheck_cast_to_incomplete))
+ return ExprError();
+
// Rewrite the casted expression from scratch.
ExprResult result = RebuildUnknownAnyExpr(*this, CastType).Visit(CastExpr);
if (!result.isUsable()) return ExprError();
@@ -14559,16 +14971,20 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
case BuiltinType::Overload: {
// Try to resolve a single function template specialization.
// This is obligatory.
- ExprResult result = E;
- if (ResolveAndFixSingleFunctionTemplateSpecialization(result, false)) {
- return result;
+ ExprResult Result = E;
+ if (ResolveAndFixSingleFunctionTemplateSpecialization(Result, false))
+ return Result;
+
+ // No guarantees that ResolveAndFixSingleFunctionTemplateSpecialization
+ // leaves Result unchanged on failure.
+ Result = E;
+ if (resolveAndFixAddressOfOnlyViableOverloadCandidate(Result))
+ return Result;
// If that failed, try to recover with a call.
- } else {
- tryToRecoverWithCall(result, PDiag(diag::err_ovl_unresolvable),
- /*complain*/ true);
- return result;
- }
+ tryToRecoverWithCall(Result, PDiag(diag::err_ovl_unresolvable),
+ /*complain*/ true);
+ return Result;
}
// Bound member functions.
@@ -14627,8 +15043,10 @@ ExprResult Sema::CheckPlaceholderExpr(Expr *E) {
return ExprError();
// Everything else should be impossible.
-#define BUILTIN_TYPE(Id, SingletonId) \
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
+#define BUILTIN_TYPE(Id, SingletonId) case BuiltinType::Id:
#define PLACEHOLDER_TYPE(Id, SingletonId)
#include "clang/AST/BuiltinTypes.def"
break;
@@ -14665,3 +15083,27 @@ Sema::ActOnObjCBoolLiteral(SourceLocation OpLoc, tok::TokenKind Kind) {
return new (Context)
ObjCBoolLiteralExpr(Kind == tok::kw___objc_yes, BoolT, OpLoc);
}
+
+ExprResult Sema::ActOnObjCAvailabilityCheckExpr(
+ llvm::ArrayRef<AvailabilitySpec> AvailSpecs, SourceLocation AtLoc,
+ SourceLocation RParen) {
+
+ StringRef Platform = getASTContext().getTargetInfo().getPlatformName();
+
+ auto Spec = std::find_if(AvailSpecs.begin(), AvailSpecs.end(),
+ [&](const AvailabilitySpec &Spec) {
+ return Spec.getPlatform() == Platform;
+ });
+
+ VersionTuple Version;
+ if (Spec != AvailSpecs.end())
+ Version = Spec->getVersion();
+ else
+ // This is the '*' case in @available. We should diagnose this; the
+ // programmer should explicitly account for this case if they target this
+ // platform.
+ Diag(AtLoc, diag::warn_available_using_star_case) << RParen << Platform;
+
+ return new (Context)
+ ObjCAvailabilityCheckExpr(Version, AtLoc, RParen, Context.BoolTy);
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
index 38fbea18d790..2cd00f8218a6 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprCXX.cpp
@@ -113,7 +113,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
bool LookInScope = false;
if (SS.isInvalid())
- return ParsedType();
+ return nullptr;
// If we have an object type, it's because we are in a
// pseudo-destructor-expression or a member access expression, and
@@ -198,7 +198,7 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
// FIXME: Should we be suppressing ambiguities here?
if (Found.isAmbiguous())
- return ParsedType();
+ return nullptr;
if (TypeDecl *Type = Found.getAsSingle<TypeDecl>()) {
QualType T = Context.getTypeDeclType(Type);
@@ -320,12 +320,12 @@ ParsedType Sema::getDestructorName(SourceLocation TildeLoc,
}
}
- return ParsedType();
+ return nullptr;
}
ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
if (DS.getTypeSpecType() == DeclSpec::TST_error || !ObjectType)
- return ParsedType();
+ return nullptr;
assert(DS.getTypeSpecType() == DeclSpec::TST_decltype
&& "only get destructor types from declspecs");
QualType T = BuildDecltypeType(DS.getRepAsExpr(), DS.getTypeSpecTypeLoc());
@@ -336,7 +336,7 @@ ParsedType Sema::getDestructorType(const DeclSpec& DS, ParsedType ObjectType) {
Diag(DS.getTypeSpecTypeLoc(), diag::err_destructor_expr_type_mismatch)
<< T << SearchType;
- return ParsedType();
+ return nullptr;
}
bool Sema::checkLiteralOperatorId(const CXXScopeSpec &SS,
@@ -508,23 +508,60 @@ Sema::ActOnCXXTypeid(SourceLocation OpLoc, SourceLocation LParenLoc,
return BuildCXXTypeId(TypeInfoType, OpLoc, (Expr*)TyOrExpr, RParenLoc);
}
+/// Grabs __declspec(uuid()) off a type, or returns 0 if we cannot resolve to
+/// a single GUID.
+static void
+getUuidAttrOfType(Sema &SemaRef, QualType QT,
+ llvm::SmallSetVector<const UuidAttr *, 1> &UuidAttrs) {
+ // Optionally remove one level of pointer, reference or array indirection.
+ const Type *Ty = QT.getTypePtr();
+ if (QT->isPointerType() || QT->isReferenceType())
+ Ty = QT->getPointeeType().getTypePtr();
+ else if (QT->isArrayType())
+ Ty = Ty->getBaseElementTypeUnsafe();
+
+ const auto *RD = Ty->getAsCXXRecordDecl();
+ if (!RD)
+ return;
+
+ if (const auto *Uuid = RD->getMostRecentDecl()->getAttr<UuidAttr>()) {
+ UuidAttrs.insert(Uuid);
+ return;
+ }
+
+ // __uuidof can grab UUIDs from template arguments.
+ if (const auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD)) {
+ const TemplateArgumentList &TAL = CTSD->getTemplateArgs();
+ for (const TemplateArgument &TA : TAL.asArray()) {
+ const UuidAttr *UuidForTA = nullptr;
+ if (TA.getKind() == TemplateArgument::Type)
+ getUuidAttrOfType(SemaRef, TA.getAsType(), UuidAttrs);
+ else if (TA.getKind() == TemplateArgument::Declaration)
+ getUuidAttrOfType(SemaRef, TA.getAsDecl()->getType(), UuidAttrs);
+
+ if (UuidForTA)
+ UuidAttrs.insert(UuidForTA);
+ }
+ }
+}
+
/// \brief Build a Microsoft __uuidof expression with a type operand.
ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
SourceLocation TypeidLoc,
TypeSourceInfo *Operand,
SourceLocation RParenLoc) {
+ StringRef UuidStr;
if (!Operand->getType()->isDependentType()) {
- bool HasMultipleGUIDs = false;
- if (!CXXUuidofExpr::GetUuidAttrOfType(Operand->getType(),
- &HasMultipleGUIDs)) {
- if (HasMultipleGUIDs)
- return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
- else
- return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
- }
+ llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs;
+ getUuidAttrOfType(*this, Operand->getType(), UuidAttrs);
+ if (UuidAttrs.empty())
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ if (UuidAttrs.size() > 1)
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+ UuidStr = UuidAttrs.back()->getGuid();
}
- return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand,
+ return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), Operand, UuidStr,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -533,18 +570,22 @@ ExprResult Sema::BuildCXXUuidof(QualType TypeInfoType,
SourceLocation TypeidLoc,
Expr *E,
SourceLocation RParenLoc) {
+ StringRef UuidStr;
if (!E->getType()->isDependentType()) {
- bool HasMultipleGUIDs = false;
- if (!CXXUuidofExpr::GetUuidAttrOfType(E->getType(), &HasMultipleGUIDs) &&
- !E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
- if (HasMultipleGUIDs)
- return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
- else
+ if (E->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) {
+ UuidStr = "00000000-0000-0000-0000-000000000000";
+ } else {
+ llvm::SmallSetVector<const UuidAttr *, 1> UuidAttrs;
+ getUuidAttrOfType(*this, E->getType(), UuidAttrs);
+ if (UuidAttrs.empty())
return ExprError(Diag(TypeidLoc, diag::err_uuidof_without_guid));
+ if (UuidAttrs.size() > 1)
+ return ExprError(Diag(TypeidLoc, diag::err_uuidof_with_multiple_guids));
+ UuidStr = UuidAttrs.back()->getGuid();
}
}
- return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E,
+ return new (Context) CXXUuidofExpr(TypeInfoType.withConst(), E, UuidStr,
SourceRange(TypeidLoc, RParenLoc));
}
@@ -831,6 +872,92 @@ bool Sema::CheckCXXThrowOperand(SourceLocation ThrowLoc,
return false;
}
+static QualType adjustCVQualifiersForCXXThisWithinLambda(
+ ArrayRef<FunctionScopeInfo *> FunctionScopes, QualType ThisTy,
+ DeclContext *CurSemaContext, ASTContext &ASTCtx) {
+
+ QualType ClassType = ThisTy->getPointeeType();
+ LambdaScopeInfo *CurLSI = nullptr;
+ DeclContext *CurDC = CurSemaContext;
+
+ // Iterate through the stack of lambdas starting from the innermost lambda to
+ // the outermost lambda, checking if '*this' is ever captured by copy - since
+ // that could change the cv-qualifiers of the '*this' object.
+ // The object referred to by '*this' starts out with the cv-qualifiers of its
+ // member function. We then start with the innermost lambda and iterate
+ // outward checking to see if any lambda performs a by-copy capture of '*this'
+ // - and if so, any nested lambda must respect the 'constness' of that
+ // capturing lamdbda's call operator.
+ //
+
+ // The issue is that we cannot rely entirely on the FunctionScopeInfo stack
+ // since ScopeInfos are pushed on during parsing and treetransforming. But
+ // since a generic lambda's call operator can be instantiated anywhere (even
+ // end of the TU) we need to be able to examine its enclosing lambdas and so
+ // we use the DeclContext to get a hold of the closure-class and query it for
+ // capture information. The reason we don't just resort to always using the
+ // DeclContext chain is that it is only mature for lambda expressions
+ // enclosing generic lambda's call operators that are being instantiated.
+
+ for (int I = FunctionScopes.size();
+ I-- && isa<LambdaScopeInfo>(FunctionScopes[I]);
+ CurDC = getLambdaAwareParentOfDeclContext(CurDC)) {
+ CurLSI = cast<LambdaScopeInfo>(FunctionScopes[I]);
+
+ if (!CurLSI->isCXXThisCaptured())
+ continue;
+
+ auto C = CurLSI->getCXXThisCapture();
+
+ if (C.isCopyCapture()) {
+ ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
+ if (CurLSI->CallOperator->isConst())
+ ClassType.addConst();
+ return ASTCtx.getPointerType(ClassType);
+ }
+ }
+ // We've run out of ScopeInfos but check if CurDC is a lambda (which can
+ // happen during instantiation of generic lambdas)
+ if (isLambdaCallOperator(CurDC)) {
+ assert(CurLSI);
+ assert(isGenericLambdaCallOperatorSpecialization(CurLSI->CallOperator));
+ assert(CurDC == getLambdaAwareParentOfDeclContext(CurLSI->CallOperator));
+
+ auto IsThisCaptured =
+ [](CXXRecordDecl *Closure, bool &IsByCopy, bool &IsConst) {
+ IsConst = false;
+ IsByCopy = false;
+ for (auto &&C : Closure->captures()) {
+ if (C.capturesThis()) {
+ if (C.getCaptureKind() == LCK_StarThis)
+ IsByCopy = true;
+ if (Closure->getLambdaCallOperator()->isConst())
+ IsConst = true;
+ return true;
+ }
+ }
+ return false;
+ };
+
+ bool IsByCopyCapture = false;
+ bool IsConstCapture = false;
+ CXXRecordDecl *Closure = cast<CXXRecordDecl>(CurDC->getParent());
+ while (Closure &&
+ IsThisCaptured(Closure, IsByCopyCapture, IsConstCapture)) {
+ if (IsByCopyCapture) {
+ ClassType.removeLocalCVRQualifiers(Qualifiers::CVRMask);
+ if (IsConstCapture)
+ ClassType.addConst();
+ return ASTCtx.getPointerType(ClassType);
+ }
+ Closure = isLambdaCallOperator(Closure->getParent())
+ ? cast<CXXRecordDecl>(Closure->getParent()->getParent())
+ : nullptr;
+ }
+ }
+ return ASTCtx.getPointerType(ClassType);
+}
+
QualType Sema::getCurrentThisType() {
DeclContext *DC = getFunctionLevelDeclContext();
QualType ThisTy = CXXThisTypeOverride;
@@ -845,13 +972,29 @@ QualType Sema::getCurrentThisType() {
// within a default initializer - so use the enclosing class as 'this'.
// There is no enclosing member function to retrieve the 'this' pointer
// from.
+
+ // FIXME: This looks wrong. If we're in a lambda within a lambda within a
+ // default member initializer, we need to recurse up more parents to find
+ // the right context. Looks like we should be walking up to the parent of
+ // the closure type, checking whether that is itself a lambda, and if so,
+ // recursing, until we reach a class or a function that isn't a lambda
+ // call operator. And we should accumulate the constness of *this on the
+ // way.
+
QualType ClassTy = Context.getTypeDeclType(
cast<CXXRecordDecl>(CurContext->getParent()->getParent()));
// There are no cv-qualifiers for 'this' within default initializers,
// per [expr.prim.general]p4.
- return Context.getPointerType(ClassTy);
+ ThisTy = Context.getPointerType(ClassTy);
}
}
+
+ // If we are within a lambda's call operator, the cv-qualifiers of 'this'
+ // might need to be adjusted if the lambda or any of its enclosing lambda's
+ // captures '*this' by copy.
+ if (!ThisTy.isNull() && isLambdaCallOperator(CurContext))
+ return adjustCVQualifiersForCXXThisWithinLambda(FunctionScopes, ThisTy,
+ CurContext, Context);
return ThisTy;
}
@@ -870,6 +1013,8 @@ Sema::CXXThisScopeRAII::CXXThisScopeRAII(Sema &S,
else
Record = cast<CXXRecordDecl>(ContextDecl);
+ // We care only for CVR qualifiers here, so cut everything else.
+ CXXThisTypeQuals &= Qualifiers::FastMask;
S.CXXThisTypeOverride
= S.Context.getPointerType(
S.Context.getRecordType(Record).withCVRQualifiers(CXXThisTypeQuals));
@@ -884,28 +1029,84 @@ Sema::CXXThisScopeRAII::~CXXThisScopeRAII() {
}
}
-static Expr *captureThis(ASTContext &Context, RecordDecl *RD,
- QualType ThisTy, SourceLocation Loc) {
- FieldDecl *Field
- = FieldDecl::Create(Context, RD, Loc, Loc, nullptr, ThisTy,
- Context.getTrivialTypeSourceInfo(ThisTy, Loc),
- nullptr, false, ICIS_NoInit);
+static Expr *captureThis(Sema &S, ASTContext &Context, RecordDecl *RD,
+ QualType ThisTy, SourceLocation Loc,
+ const bool ByCopy) {
+
+ QualType AdjustedThisTy = ThisTy;
+ // The type of the corresponding data member (not a 'this' pointer if 'by
+ // copy').
+ QualType CaptureThisFieldTy = ThisTy;
+ if (ByCopy) {
+ // If we are capturing the object referred to by '*this' by copy, ignore any
+ // cv qualifiers inherited from the type of the member function for the type
+ // of the closure-type's corresponding data member and any use of 'this'.
+ CaptureThisFieldTy = ThisTy->getPointeeType();
+ CaptureThisFieldTy.removeLocalCVRQualifiers(Qualifiers::CVRMask);
+ AdjustedThisTy = Context.getPointerType(CaptureThisFieldTy);
+ }
+
+ FieldDecl *Field = FieldDecl::Create(
+ Context, RD, Loc, Loc, nullptr, CaptureThisFieldTy,
+ Context.getTrivialTypeSourceInfo(CaptureThisFieldTy, Loc), nullptr, false,
+ ICIS_NoInit);
+
Field->setImplicit(true);
Field->setAccess(AS_private);
RD->addDecl(Field);
- return new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/true);
+ Expr *This =
+ new (Context) CXXThisExpr(Loc, ThisTy, /*isImplicit*/ true);
+ if (ByCopy) {
+ Expr *StarThis = S.CreateBuiltinUnaryOp(Loc,
+ UO_Deref,
+ This).get();
+ InitializedEntity Entity = InitializedEntity::InitializeLambdaCapture(
+ nullptr, CaptureThisFieldTy, Loc);
+ InitializationKind InitKind = InitializationKind::CreateDirect(Loc, Loc, Loc);
+ InitializationSequence Init(S, Entity, InitKind, StarThis);
+ ExprResult ER = Init.Perform(S, Entity, InitKind, StarThis);
+ if (ER.isInvalid()) return nullptr;
+ return ER.get();
+ }
+ return This;
}
-bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit,
- bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt) {
+bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
+ bool BuildAndDiagnose, const unsigned *const FunctionScopeIndexToStopAt,
+ const bool ByCopy) {
// We don't need to capture this in an unevaluated context.
if (isUnevaluatedContext() && !Explicit)
return true;
+
+ assert((!ByCopy || Explicit) && "cannot implicitly capture *this by value");
const unsigned MaxFunctionScopesIndex = FunctionScopeIndexToStopAt ?
- *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
- // Otherwise, check that we can capture 'this'.
- unsigned NumClosures = 0;
+ *FunctionScopeIndexToStopAt : FunctionScopes.size() - 1;
+
+ // Check that we can capture the *enclosing object* (referred to by '*this')
+ // by the capturing-entity/closure (lambda/block/etc) at
+ // MaxFunctionScopesIndex-deep on the FunctionScopes stack.
+
+ // Note: The *enclosing object* can only be captured by-value by a
+ // closure that is a lambda, using the explicit notation:
+ // [*this] { ... }.
+ // Every other capture of the *enclosing object* results in its by-reference
+ // capture.
+
+ // For a closure 'L' (at MaxFunctionScopesIndex in the FunctionScopes
+ // stack), we can capture the *enclosing object* only if:
+ // - 'L' has an explicit byref or byval capture of the *enclosing object*
+ // - or, 'L' has an implicit capture.
+ // AND
+ // -- there is no enclosing closure
+ // -- or, there is some enclosing closure 'E' that has already captured the
+ // *enclosing object*, and every intervening closure (if any) between 'E'
+ // and 'L' can implicitly capture the *enclosing object*.
+ // -- or, every enclosing closure can implicitly capture the
+ // *enclosing object*
+
+
+ unsigned NumCapturingClosures = 0;
for (unsigned idx = MaxFunctionScopesIndex; idx != 0; idx--) {
if (CapturingScopeInfo *CSI =
dyn_cast<CapturingScopeInfo>(FunctionScopes[idx])) {
@@ -917,44 +1118,69 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, bool Explicit,
if (LSI && isGenericLambdaCallOperatorSpecialization(LSI->CallOperator)) {
// This context can't implicitly capture 'this'; fail out.
if (BuildAndDiagnose)
- Diag(Loc, diag::err_this_capture) << Explicit;
+ Diag(Loc, diag::err_this_capture)
+ << (Explicit && idx == MaxFunctionScopesIndex);
return true;
}
if (CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByref ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_LambdaByval ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_Block ||
CSI->ImpCaptureStyle == CapturingScopeInfo::ImpCap_CapturedRegion ||
- Explicit) {
+ (Explicit && idx == MaxFunctionScopesIndex)) {
+ // Regarding (Explicit && idx == MaxFunctionScopesIndex): only the first
+ // iteration through can be an explicit capture, all enclosing closures,
+ // if any, must perform implicit captures.
+
// This closure can capture 'this'; continue looking upwards.
- NumClosures++;
- Explicit = false;
+ NumCapturingClosures++;
continue;
}
// This context can't implicitly capture 'this'; fail out.
if (BuildAndDiagnose)
- Diag(Loc, diag::err_this_capture) << Explicit;
+ Diag(Loc, diag::err_this_capture)
+ << (Explicit && idx == MaxFunctionScopesIndex);
return true;
}
break;
}
if (!BuildAndDiagnose) return false;
- // Mark that we're implicitly capturing 'this' in all the scopes we skipped.
+
+ // If we got here, then the closure at MaxFunctionScopesIndex on the
+ // FunctionScopes stack, can capture the *enclosing object*, so capture it
+ // (including implicit by-reference captures in any enclosing closures).
+
+ // In the loop below, respect the ByCopy flag only for the closure requesting
+ // the capture (i.e. first iteration through the loop below). Ignore it for
+ // all enclosing closure's upto NumCapturingClosures (since they must be
+ // implicitly capturing the *enclosing object* by reference (see loop
+ // above)).
+ assert((!ByCopy ||
+ dyn_cast<LambdaScopeInfo>(FunctionScopes[MaxFunctionScopesIndex])) &&
+ "Only a lambda can capture the enclosing object (referred to by "
+ "*this) by copy");
// FIXME: We need to delay this marking in PotentiallyPotentiallyEvaluated
// contexts.
- for (unsigned idx = MaxFunctionScopesIndex; NumClosures;
- --idx, --NumClosures) {
+ QualType ThisTy = getCurrentThisType();
+ for (unsigned idx = MaxFunctionScopesIndex; NumCapturingClosures;
+ --idx, --NumCapturingClosures) {
CapturingScopeInfo *CSI = cast<CapturingScopeInfo>(FunctionScopes[idx]);
Expr *ThisExpr = nullptr;
- QualType ThisTy = getCurrentThisType();
- if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI))
- // For lambda expressions, build a field and an initializing expression.
- ThisExpr = captureThis(Context, LSI->Lambda, ThisTy, Loc);
- else if (CapturedRegionScopeInfo *RSI
+
+ if (LambdaScopeInfo *LSI = dyn_cast<LambdaScopeInfo>(CSI)) {
+ // For lambda expressions, build a field and an initializing expression,
+ // and capture the *enclosing object* by copy only if this is the first
+ // iteration.
+ ThisExpr = captureThis(*this, Context, LSI->Lambda, ThisTy, Loc,
+ ByCopy && idx == MaxFunctionScopesIndex);
+
+ } else if (CapturedRegionScopeInfo *RSI
= dyn_cast<CapturedRegionScopeInfo>(FunctionScopes[idx]))
- ThisExpr = captureThis(Context, RSI->TheRecordDecl, ThisTy, Loc);
+ ThisExpr =
+ captureThis(*this, Context, RSI->TheRecordDecl, ThisTy, Loc,
+ false/*ByCopy*/);
- bool isNested = NumClosures > 1;
- CSI->addThisCapture(isNested, Loc, ThisTy, ThisExpr);
+ bool isNested = NumCapturingClosures > 1;
+ CSI->addThisCapture(isNested, Loc, ThisExpr, ByCopy);
}
return false;
}
@@ -996,7 +1222,14 @@ Sema::ActOnCXXTypeConstructExpr(ParsedType TypeRep,
if (!TInfo)
TInfo = Context.getTrivialTypeSourceInfo(Ty, SourceLocation());
- return BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
+ auto Result = BuildCXXTypeConstructExpr(TInfo, LParenLoc, exprs, RParenLoc);
+ // Avoid creating a non-type-dependent expression that contains typos.
+ // Non-type-dependent expressions are liable to be discarded without
+ // checking for embedded typos.
+ if (!Result.isInvalid() && Result.get()->isInstantiationDependent() &&
+ !Result.get()->isTypeDependent())
+ Result = CorrectDelayedTyposInExpr(Result.get());
+ return Result;
}
/// ActOnCXXTypeConstructExpr - Parse construction of a specified type.
@@ -1551,7 +1784,8 @@ Sema::BuildCXXNew(SourceRange Range, bool UseGlobal,
// new.
if (PlacementArgs.empty() && OperatorNew &&
(OperatorNew->isImplicit() ||
- getSourceManager().isInSystemHeader(OperatorNew->getLocStart()))) {
+ (OperatorNew->getLocStart().isValid() &&
+ getSourceManager().isInSystemHeader(OperatorNew->getLocStart())))) {
if (unsigned Align = Context.getPreferredTypeAlign(AllocType.getTypePtr())){
unsigned SuitableAlign = Context.getTargetInfo().getSuitableAlign();
if (Align > SuitableAlign)
@@ -2113,14 +2347,13 @@ void Sema::DeclareGlobalNewDelete() {
QualType VoidPtr = Context.getPointerType(Context.VoidTy);
QualType SizeT = Context.getSizeType();
- bool AssumeSaneOperatorNew = getLangOpts().AssumeSaneOperatorNew;
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_New),
- VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
+ VoidPtr, SizeT, QualType());
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Array_New),
- VoidPtr, SizeT, QualType(), AssumeSaneOperatorNew);
+ VoidPtr, SizeT, QualType());
DeclareGlobalAllocationFunction(
Context.DeclarationNames.getCXXOperatorName(OO_Delete),
Context.VoidTy, VoidPtr);
@@ -2141,8 +2374,7 @@ void Sema::DeclareGlobalNewDelete() {
/// allocation function if it doesn't already exist.
void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
QualType Return,
- QualType Param1, QualType Param2,
- bool AddRestrictAttr) {
+ QualType Param1, QualType Param2) {
DeclContext *GlobalCtx = Context.getTranslationUnitDecl();
unsigned NumParams = Param2.isNull() ? 1 : 2;
@@ -2165,9 +2397,6 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
// FIXME: Do we need to check for default arguments here?
if (InitialParam1Type == Param1 &&
(NumParams == 1 || InitialParam2Type == Param2)) {
- if (AddRestrictAttr && !Func->hasAttr<RestrictAttr>())
- Func->addAttr(RestrictAttr::CreateImplicit(
- Context, RestrictAttr::GNU_malloc));
// Make the function visible to name lookup, even if we found it in
// an unimported module. It either is an implicitly-declared global
// allocation function, or is suppressing that function.
@@ -2210,10 +2439,6 @@ void Sema::DeclareGlobalAllocationFunction(DeclarationName Name,
Alloc->addAttr(VisibilityAttr::CreateImplicit(Context,
VisibilityAttr::Default));
- if (AddRestrictAttr)
- Alloc->addAttr(
- RestrictAttr::CreateImplicit(Context, RestrictAttr::GNU_malloc));
-
ParmVarDecl *ParamDecls[2];
for (unsigned I = 0; I != NumParams; ++I) {
ParamDecls[I] = ParmVarDecl::Create(Context, Alloc, SourceLocation(),
@@ -2265,7 +2490,7 @@ FunctionDecl *Sema::FindUsualDeallocationFunction(SourceLocation StartLoc,
"found an unexpected usual deallocation function");
}
- if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads)
+ if (getLangOpts().CUDA)
EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
assert(Matches.size() == 1 &&
@@ -2299,7 +2524,7 @@ bool Sema::FindDeallocationFunction(SourceLocation StartLoc, CXXRecordDecl *RD,
Matches.push_back(F.getPair());
}
- if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads)
+ if (getLangOpts().CUDA)
EraseUnwantedCUDAMatches(dyn_cast<FunctionDecl>(CurContext), Matches);
// There's exactly one suitable operator; pick it.
@@ -2765,30 +2990,10 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return ExprError();
}
- // C++ [expr.delete]p3:
- // In the first alternative (delete object), if the static type of the
- // object to be deleted is different from its dynamic type, the static
- // type shall be a base class of the dynamic type of the object to be
- // deleted and the static type shall have a virtual destructor or the
- // behavior is undefined.
- //
- // Note: a final class cannot be derived from, no issue there
- if (PointeeRD->isPolymorphic() && !PointeeRD->hasAttr<FinalAttr>()) {
- CXXDestructorDecl *dtor = PointeeRD->getDestructor();
- if (dtor && !dtor->isVirtual()) {
- if (PointeeRD->isAbstract()) {
- // If the class is abstract, we warn by default, because we're
- // sure the code has undefined behavior.
- Diag(StartLoc, diag::warn_delete_abstract_non_virtual_dtor)
- << PointeeElem;
- } else if (!ArrayForm) {
- // Otherwise, if this is not an array delete, it's a bit suspect,
- // but not necessarily wrong.
- Diag(StartLoc, diag::warn_delete_non_virtual_dtor) << PointeeElem;
- }
- }
- }
-
+ CheckVirtualDtorCall(PointeeRD->getDestructor(), StartLoc,
+ /*IsDelete=*/true, /*CallCanBeVirtual=*/true,
+ /*WarnOnNonAbstractTypes=*/!ArrayForm,
+ SourceLocation());
}
if (!OperatorDelete)
@@ -2817,11 +3022,61 @@ Sema::ActOnCXXDelete(SourceLocation StartLoc, bool UseGlobal,
return Result;
}
+void Sema::CheckVirtualDtorCall(CXXDestructorDecl *dtor, SourceLocation Loc,
+ bool IsDelete, bool CallCanBeVirtual,
+ bool WarnOnNonAbstractTypes,
+ SourceLocation DtorLoc) {
+ if (!dtor || dtor->isVirtual() || !CallCanBeVirtual)
+ return;
+
+ // C++ [expr.delete]p3:
+ // In the first alternative (delete object), if the static type of the
+ // object to be deleted is different from its dynamic type, the static
+ // type shall be a base class of the dynamic type of the object to be
+ // deleted and the static type shall have a virtual destructor or the
+ // behavior is undefined.
+ //
+ const CXXRecordDecl *PointeeRD = dtor->getParent();
+ // Note: a final class cannot be derived from, no issue there
+ if (!PointeeRD->isPolymorphic() || PointeeRD->hasAttr<FinalAttr>())
+ return;
+
+ QualType ClassType = dtor->getThisType(Context)->getPointeeType();
+ if (PointeeRD->isAbstract()) {
+ // If the class is abstract, we warn by default, because we're
+ // sure the code has undefined behavior.
+ Diag(Loc, diag::warn_delete_abstract_non_virtual_dtor) << (IsDelete ? 0 : 1)
+ << ClassType;
+ } else if (WarnOnNonAbstractTypes) {
+ // Otherwise, if this is not an array delete, it's a bit suspect,
+ // but not necessarily wrong.
+ Diag(Loc, diag::warn_delete_non_virtual_dtor) << (IsDelete ? 0 : 1)
+ << ClassType;
+ }
+ if (!IsDelete) {
+ std::string TypeStr;
+ ClassType.getAsStringInternal(TypeStr, getPrintingPolicy());
+ Diag(DtorLoc, diag::note_delete_non_virtual)
+ << FixItHint::CreateInsertion(DtorLoc, TypeStr + "::");
+ }
+}
+
+Sema::ConditionResult Sema::ActOnConditionVariable(Decl *ConditionVar,
+ SourceLocation StmtLoc,
+ ConditionKind CK) {
+ ExprResult E =
+ CheckConditionVariable(cast<VarDecl>(ConditionVar), StmtLoc, CK);
+ if (E.isInvalid())
+ return ConditionError();
+ return ConditionResult(*this, ConditionVar, MakeFullExpr(E.get(), StmtLoc),
+ CK == ConditionKind::ConstexprIf);
+}
+
/// \brief Check the use of the given variable as a C++ condition in an if,
/// while, do-while, or switch statement.
ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
SourceLocation StmtLoc,
- bool ConvertToBoolean) {
+ ConditionKind CK) {
if (ConditionVar->isInvalidDecl())
return ExprError();
@@ -2845,17 +3100,22 @@ ExprResult Sema::CheckConditionVariable(VarDecl *ConditionVar,
MarkDeclRefReferenced(cast<DeclRefExpr>(Condition.get()));
- if (ConvertToBoolean) {
- Condition = CheckBooleanCondition(Condition.get(), StmtLoc);
- if (Condition.isInvalid())
- return ExprError();
+ switch (CK) {
+ case ConditionKind::Boolean:
+ return CheckBooleanCondition(StmtLoc, Condition.get());
+
+ case ConditionKind::ConstexprIf:
+ return CheckBooleanCondition(StmtLoc, Condition.get(), true);
+
+ case ConditionKind::Switch:
+ return CheckSwitchCondition(StmtLoc, Condition.get());
}
- return Condition;
+ llvm_unreachable("unexpected condition kind");
}
/// CheckCXXBooleanCondition - Returns true if a conversion to bool is invalid.
-ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) {
+ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr, bool IsConstexpr) {
// C++ 6.4p4:
// The value of a condition that is an initialized declaration in a statement
// other than a switch statement is the value of the declared variable
@@ -2864,7 +3124,12 @@ ExprResult Sema::CheckCXXBooleanCondition(Expr *CondExpr) {
// The value of a condition that is an expression is the value of the
// expression, implicitly converted to bool.
//
- return PerformContextuallyConvertToBool(CondExpr);
+ // FIXME: Return this value to the caller so they don't need to recompute it.
+ llvm::APSInt Value(/*BitWidth*/1);
+ return (IsConstexpr && !CondExpr->isValueDependent())
+ ? CheckConvertedConstantExpression(CondExpr, Context.BoolTy, Value,
+ CCEK_ConstexprIf)
+ : PerformContextuallyConvertToBool(CondExpr);
}
/// Helper function to determine whether this is the (deprecated) C++
@@ -2898,7 +3163,8 @@ Sema::IsStringLiteralToNonConstPointerConversion(Expr *From, QualType ToType) {
return (ToPointeeType->getKind() == BuiltinType::Char_U ||
ToPointeeType->getKind() == BuiltinType::Char_S);
case StringLiteral::Wide:
- return ToPointeeType->isWideCharType();
+ return Context.typesAreCompatible(Context.getWideCharType(),
+ QualType(ToPointeeType, 0));
}
}
}
@@ -2927,14 +3193,13 @@ static ExprResult BuildCXXCastArgument(Sema &S,
if (S.CompleteConstructorCall(Constructor, From, CastLoc, ConstructorArgs))
return ExprError();
- S.CheckConstructorAccess(CastLoc, Constructor,
- InitializedEntity::InitializeTemporary(Ty),
- Constructor->getAccess());
+ S.CheckConstructorAccess(CastLoc, Constructor, FoundDecl,
+ InitializedEntity::InitializeTemporary(Ty));
if (S.DiagnoseUseOfDecl(Method, CastLoc))
return ExprError();
ExprResult Result = S.BuildCXXConstructExpr(
- CastLoc, Ty, cast<CXXConstructorDecl>(Method),
+ CastLoc, Ty, FoundDecl, cast<CXXConstructorDecl>(Method),
ConstructorArgs, HadMultipleCandidates,
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
@@ -3085,13 +3350,15 @@ Sema::PerformImplicitConversion(Expr *From, QualType ToType,
ConstructorArgs))
return ExprError();
return BuildCXXConstructExpr(
- /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
+ /*FIXME:ConstructLoc*/ SourceLocation(), ToType,
+ SCS.FoundCopyConstructor, SCS.CopyConstructor,
ConstructorArgs, /*HadMultipleCandidates*/ false,
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
}
return BuildCXXConstructExpr(
- /*FIXME:ConstructLoc*/ SourceLocation(), ToType, SCS.CopyConstructor,
+ /*FIXME:ConstructLoc*/ SourceLocation(), ToType,
+ SCS.FoundCopyConstructor, SCS.CopyConstructor,
From, /*HadMultipleCandidates*/ false,
/*ListInit*/ false, /*StdInitListInit*/ false, /*ZeroInit*/ false,
CXXConstructExpr::CK_Complete, SourceRange());
@@ -4314,6 +4581,7 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
return !Result.isInvalid() && !SFINAE.hasErrorOccurred();
}
+ case BTT_IsAssignable:
case BTT_IsNothrowAssignable:
case BTT_IsTriviallyAssignable: {
// C++11 [meta.unary.prop]p3:
@@ -4361,6 +4629,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, QualType LhsT,
if (Result.isInvalid() || SFINAE.hasErrorOccurred())
return false;
+ if (BTT == BTT_IsAssignable)
+ return true;
+
if (BTT == BTT_IsNothrowAssignable)
return Self.canThrow(Result.get()) == CT_Cannot;
@@ -4652,7 +4923,7 @@ QualType Sema::CheckPointerToMemberOperands(ExprResult &LHS, ExprResult &RHS,
return Result;
}
-/// \brief Try to convert a type to another according to C++0x 5.16p3.
+/// \brief Try to convert a type to another according to C++11 5.16p3.
///
/// This is part of the parameter validation for the ? operator. If either
/// value operand is a class type, the two operands are attempted to be
@@ -4668,17 +4939,21 @@ static bool TryClassUnification(Sema &Self, Expr *From, Expr *To,
InitializationKind Kind = InitializationKind::CreateCopy(To->getLocStart(),
SourceLocation());
- // C++0x 5.16p3
+ // C++11 5.16p3
// The process for determining whether an operand expression E1 of type T1
// can be converted to match an operand expression E2 of type T2 is defined
// as follows:
- // -- If E2 is an lvalue:
- bool ToIsLvalue = To->isLValue();
- if (ToIsLvalue) {
- // E1 can be converted to match E2 if E1 can be implicitly converted to
- // type "lvalue reference to T2", subject to the constraint that in the
- // conversion the reference must bind directly to E1.
- QualType T = Self.Context.getLValueReferenceType(ToType);
+ // -- If E2 is an lvalue: E1 can be converted to match E2 if E1 can be
+ // implicitly converted to type "lvalue reference to T2", subject to the
+ // constraint that in the conversion the reference must bind directly to
+ // an lvalue.
+ // -- If E2 is an xvalue: E1 can be converted to match E2 if E1 can be
+ // implicitly conveted to the type "rvalue reference to R2", subject to
+ // the constraint that the reference must bind directly.
+ if (To->isLValue() || To->isXValue()) {
+ QualType T = To->isLValue() ? Self.Context.getLValueReferenceType(ToType)
+ : Self.Context.getRValueReferenceType(ToType);
+
InitializedEntity Entity = InitializedEntity::InitializeTemporary(T);
InitializationSequence InitSeq(Self, Entity, Kind, From);
@@ -5029,6 +5304,12 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS,
QualType ResTy = UsualArithmeticConversions(LHS, RHS);
if (LHS.isInvalid() || RHS.isInvalid())
return QualType();
+ if (ResTy.isNull()) {
+ Diag(QuestionLoc,
+ diag::err_typecheck_cond_incompatible_operands) << LTy << RTy
+ << LHS.get()->getSourceRange() << RHS.get()->getSourceRange();
+ return QualType();
+ }
LHS = ImpCastExprToType(LHS.get(), ResTy, PrepareScalarCast(LHS, ResTy));
RHS = ImpCastExprToType(RHS.get(), ResTy, PrepareScalarCast(RHS, ResTy));
@@ -5390,7 +5671,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
if (!ReturnsRetained && E->getType()->isObjCARCImplicitlyUnretainedType())
return E;
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
CastKind ck = (ReturnsRetained ? CK_ARCConsumeObject
: CK_ARCReclaimReturnedObject);
@@ -5443,7 +5724,7 @@ ExprResult Sema::MaybeBindToTemporary(Expr *E) {
return E;
// We need a cleanup, but we don't need to remember the temporary.
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
}
CXXTemporary *Temp = CXXTemporary::Create(Context, Destructor);
@@ -5470,14 +5751,16 @@ Expr *Sema::MaybeCreateExprWithCleanups(Expr *SubExpr) {
unsigned FirstCleanup = ExprEvalContexts.back().NumCleanupObjects;
assert(ExprCleanupObjects.size() >= FirstCleanup);
- assert(ExprNeedsCleanups || ExprCleanupObjects.size() == FirstCleanup);
- if (!ExprNeedsCleanups)
+ assert(Cleanup.exprNeedsCleanups() ||
+ ExprCleanupObjects.size() == FirstCleanup);
+ if (!Cleanup.exprNeedsCleanups())
return SubExpr;
auto Cleanups = llvm::makeArrayRef(ExprCleanupObjects.begin() + FirstCleanup,
ExprCleanupObjects.size() - FirstCleanup);
- Expr *E = ExprWithCleanups::Create(Context, SubExpr, Cleanups);
+ auto *E = ExprWithCleanups::Create(
+ Context, SubExpr, Cleanup.cleanupsHaveSideEffects(), Cleanups);
DiscardCleanupsInEvaluationContext();
return E;
@@ -5488,7 +5771,7 @@ Stmt *Sema::MaybeCreateStmtWithCleanups(Stmt *SubStmt) {
CleanupVarDeclMarking();
- if (!ExprNeedsCleanups)
+ if (!Cleanup.exprNeedsCleanups())
return SubStmt;
// FIXME: In order to attach the temporaries, wrap the statement into
@@ -5594,7 +5877,7 @@ ExprResult Sema::ActOnDecltypeExpression(Expr *E) {
return ExprError();
// We need a cleanup, but we don't need to remember the temporary.
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
}
// Possibly strip off the top CXXBindTemporaryExpr.
@@ -5746,7 +6029,7 @@ ExprResult Sema::ActOnStartCXXMemberReference(Scope *S, Expr *Base,
MayBePseudoDestructor = true;
return Base;
} else if (!BaseType->isRecordType()) {
- ObjectType = ParsedType();
+ ObjectType = nullptr;
MayBePseudoDestructor = true;
return Base;
}
@@ -5789,7 +6072,7 @@ static bool CheckArrow(Sema& S, QualType& ObjectType, Expr *&Base,
if (const PointerType *Ptr = ObjectType->getAs<PointerType>()) {
ObjectType = Ptr->getPointeeType();
} else if (!Base->isTypeDependent()) {
- // The user wrote "p->" when she probably meant "p."; fix it.
+ // The user wrote "p->" when they probably meant "p."; fix it.
S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
<< ObjectType << true
<< FixItHint::CreateReplacement(OpLoc, ".");
@@ -6082,9 +6365,12 @@ ExprResult Sema::BuildCXXMemberCallExpr(Expr *E, NamedDecl *FoundDecl,
// follows the normal lifetime rules for block literals instead of being
// autoreleased.
DiagnosticErrorTrap Trap(Diags);
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
ExprResult Exp = BuildBlockForLambdaConversion(E->getExprLoc(),
E->getExprLoc(),
Method, E);
+ PopExpressionEvaluationContext();
+
if (Exp.isInvalid())
Diag(E->getExprLoc(), diag::note_lambda_to_block_conv);
return Exp;
@@ -6390,7 +6676,7 @@ static void CheckIfAnyEnclosingLambdasMustCaptureAnyPotentialCaptures(
static ExprResult attemptRecovery(Sema &SemaRef,
const TypoCorrectionConsumer &Consumer,
- TypoCorrection TC) {
+ const TypoCorrection &TC) {
LookupResult R(SemaRef, Consumer.getLookupResult().getLookupNameInfo(),
Consumer.getLookupResult().getLookupKind());
const CXXScopeSpec *SS = Consumer.getSS();
@@ -6567,6 +6853,14 @@ public:
ExprResult TransformBlockExpr(BlockExpr *E) { return Owned(E); }
+ ExprResult TransformObjCPropertyRefExpr(ObjCPropertyRefExpr *E) {
+ return Owned(E);
+ }
+
+ ExprResult TransformObjCIvarRefExpr(ObjCIvarRefExpr *E) {
+ return Owned(E);
+ }
+
ExprResult Transform(Expr *E) {
ExprResult Res;
while (true) {
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
index 9c345f8a69a3..283621889f80 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprMember.cpp
@@ -142,6 +142,7 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
AbstractInstanceResult = IMA_Abstract;
break;
+ case Sema::DiscardedStatement:
case Sema::ConstantEvaluated:
case Sema::PotentiallyEvaluated:
case Sema::PotentiallyEvaluatedIfUsed:
@@ -380,7 +381,8 @@ static Decl *FindGetterSetterNameDeclFromProtocolList(const ObjCProtocolDecl*PDe
const Selector &Sel,
ASTContext &Context) {
if (Member)
- if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(Member))
+ if (ObjCPropertyDecl *PD = PDecl->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance))
return PD;
if (ObjCMethodDecl *OMD = PDecl->getInstanceMethod(Sel))
return OMD;
@@ -401,7 +403,8 @@ static Decl *FindGetterSetterNameDecl(const ObjCObjectPointerType *QIdTy,
Decl *GDecl = nullptr;
for (const auto *I : QIdTy->quals()) {
if (Member)
- if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
GDecl = PD;
break;
}
@@ -900,6 +903,32 @@ static bool IsInFnTryBlockHandler(const Scope *S) {
return false;
}
+static VarDecl *
+getVarTemplateSpecialization(Sema &S, VarTemplateDecl *VarTempl,
+ const TemplateArgumentListInfo *TemplateArgs,
+ const DeclarationNameInfo &MemberNameInfo,
+ SourceLocation TemplateKWLoc) {
+
+ if (!TemplateArgs) {
+ S.Diag(MemberNameInfo.getBeginLoc(), diag::err_template_decl_ref)
+ << /*Variable template*/ 1 << MemberNameInfo.getName()
+ << MemberNameInfo.getSourceRange();
+
+ S.Diag(VarTempl->getLocation(), diag::note_template_decl_here);
+
+ return nullptr;
+ }
+ DeclResult VDecl = S.CheckVarTemplateId(
+ VarTempl, TemplateKWLoc, MemberNameInfo.getLoc(), *TemplateArgs);
+ if (VDecl.isInvalid())
+ return nullptr;
+ VarDecl *Var = cast<VarDecl>(VDecl.get());
+ if (!Var->getTemplateSpecializationKind())
+ Var->setTemplateSpecializationKind(TSK_ImplicitInstantiation,
+ MemberNameInfo.getLoc());
+ return Var;
+}
+
ExprResult
Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
SourceLocation OpLoc, bool IsArrow,
@@ -1067,9 +1096,23 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
// Handle the implicit-member-access case.
if (!BaseExpr) {
// If this is not an instance member, convert to a non-member access.
- if (!MemberDecl->isCXXInstanceMember())
- return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl);
-
+ if (!MemberDecl->isCXXInstanceMember()) {
+ // If this is a variable template, get the instantiated variable
+ // declaration corresponding to the supplied template arguments
+ // (while emitting diagnostics as necessary) that will be referenced
+ // by this expression.
+ assert((!TemplateArgs || isa<VarTemplateDecl>(MemberDecl)) &&
+ "How did we get template arguments here sans a variable template");
+ if (isa<VarTemplateDecl>(MemberDecl)) {
+ MemberDecl = getVarTemplateSpecialization(
+ *this, cast<VarTemplateDecl>(MemberDecl), TemplateArgs,
+ R.getLookupNameInfo(), TemplateKWLoc);
+ if (!MemberDecl)
+ return ExprError();
+ }
+ return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), MemberDecl,
+ FoundDecl, TemplateArgs);
+ }
SourceLocation Loc = R.getNameLoc();
if (SS.getRange().isValid())
Loc = SS.getRange().getBegin();
@@ -1125,6 +1168,15 @@ Sema::BuildMemberReferenceExpr(Expr *BaseExpr, QualType BaseExprType,
TemplateKWLoc, Enum, FoundDecl, MemberNameInfo,
Enum->getType(), VK_RValue, OK_Ordinary);
}
+ if (VarTemplateDecl *VarTempl = dyn_cast<VarTemplateDecl>(MemberDecl)) {
+ if (VarDecl *Var = getVarTemplateSpecialization(
+ *this, VarTempl, TemplateArgs, MemberNameInfo, TemplateKWLoc))
+ return BuildMemberExpr(*this, Context, BaseExpr, IsArrow, OpLoc, SS,
+ TemplateKWLoc, Var, FoundDecl, MemberNameInfo,
+ Var->getType().getNonReferenceType(), VK_LValue,
+ OK_Ordinary);
+ return ExprError();
+ }
// We found something that we didn't expect. Complain.
if (isa<TypeDecl>(MemberDecl))
@@ -1324,7 +1376,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R,
D = CAT->getClassInterface();
ClassDeclared = cast<ObjCInterfaceDecl>(D);
} else {
- if (IsArrow && IDecl->FindPropertyDeclaration(Member)) {
+ if (IsArrow &&
+ IDecl->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
S.Diag(MemberLoc, diag::err_property_found_suggest)
<< Member << BaseExpr.get()->getType()
<< FixItHint::CreateReplacement(OpLoc, ".");
@@ -1731,9 +1785,20 @@ BuildFieldReferenceExpr(Sema &S, Expr *BaseExpr, bool IsArrow,
FoundDecl, Field);
if (Base.isInvalid())
return ExprError();
- return BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
- /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
- MemberNameInfo, MemberType, VK, OK);
+ MemberExpr *ME =
+ BuildMemberExpr(S, S.Context, Base.get(), IsArrow, OpLoc, SS,
+ /*TemplateKWLoc=*/SourceLocation(), Field, FoundDecl,
+ MemberNameInfo, MemberType, VK, OK);
+
+ // Build a reference to a private copy for non-static data members in
+ // non-static member functions, privatized by OpenMP constructs.
+ if (S.getLangOpts().OpenMP && IsArrow &&
+ !S.CurContext->isDependentContext() &&
+ isa<CXXThisExpr>(Base.get()->IgnoreParenImpCasts())) {
+ if (auto *PrivateCopy = S.IsOpenMPCapturedDecl(Field))
+ return S.getOpenMPCapturedExpr(PrivateCopy, VK, OK, OpLoc);
+ }
+ return ME;
}
/// Builds an implicit member access expression. The current context
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
index c1fb906a5b19..8f0d4ff69576 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaExprObjC.cpp
@@ -1035,7 +1035,6 @@ ExprResult Sema::BuildObjCDictionaryLiteral(SourceRange SR,
HasPackExpansions = true;
}
-
QualType Ty
= Context.getObjCObjectPointerType(
@@ -1778,7 +1777,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
MemberName, BaseRange))
return ExprError();
- if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = IFace->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -1793,7 +1793,8 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
}
// Check protocols on qualified interfaces.
for (const auto *I : OPT->quals())
- if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(Member)) {
+ if (ObjCPropertyDecl *PD = I->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
// Check whether we can reference this property.
if (DiagnoseUseOfDecl(PD, MemberLoc))
return ExprError();
@@ -1816,7 +1817,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
Selector Sel = PP.getSelectorTable().getNullarySelector(Member);
ObjCMethodDecl *Getter = IFace->lookupInstanceMethod(Sel);
- // May be founf in property's qualified list.
+ // May be found in property's qualified list.
if (!Getter)
Getter = LookupMethodInQualifiedType(Sel, OPT, true);
@@ -1836,7 +1837,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
PP.getSelectorTable(), Member);
ObjCMethodDecl *Setter = IFace->lookupInstanceMethod(SetterSel);
- // May be founf in property's qualified list.
+ // May be found in property's qualified list.
if (!Setter)
Setter = LookupMethodInQualifiedType(SetterSel, OPT, true);
@@ -1852,8 +1853,9 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
// Special warning if member name used in a property-dot for a setter accessor
// does not use a property with same name; e.g. obj.X = ... for a property with
// name 'x'.
- if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor()
- && !IFace->FindPropertyDeclaration(Member)) {
+ if (Setter && Setter->isImplicit() && Setter->isPropertyAccessor() &&
+ !IFace->FindPropertyDeclaration(
+ Member, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
if (const ObjCPropertyDecl *PDecl = Setter->findPropertyDecl()) {
// Do not warn if user is using property-dot syntax to make call to
// user named setter.
@@ -1883,12 +1885,29 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
LookupOrdinaryName, nullptr, nullptr,
llvm::make_unique<DeclFilterCCC<ObjCPropertyDecl>>(),
CTK_ErrorRecovery, IFace, false, OPT)) {
- diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
- << MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
- return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
- TypoResult, MemberLoc,
- SuperLoc, SuperType, Super);
+ if (TypoResult.isIdentifier() &&
+ TypoResult.getAsIdentifierInfo() == Member) {
+ // There is no need to try the correction if it is the same.
+ NamedDecl *ChosenDecl =
+ Corrected.isKeyword() ? nullptr : Corrected.getFoundDecl();
+ if (ChosenDecl && isa<ObjCPropertyDecl>(ChosenDecl))
+ if (cast<ObjCPropertyDecl>(ChosenDecl)->isClassProperty()) {
+ // This is a class property, we should not use the instance to
+ // access it.
+ Diag(MemberLoc, diag::err_class_property_found) << MemberName
+ << OPT->getInterfaceDecl()->getName()
+ << FixItHint::CreateReplacement(BaseExpr->getSourceRange(),
+ OPT->getInterfaceDecl()->getName());
+ return ExprError();
+ }
+ } else {
+ diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
+ << MemberName << QualType(OPT, 0));
+ return HandleExprPropertyRefExpr(OPT, BaseExpr, OpLoc,
+ TypoResult, MemberLoc,
+ SuperLoc, SuperType, Super);
+ }
}
ObjCInterfaceDecl *ClassDeclared;
if (ObjCIvarDecl *Ivar =
@@ -1916,8 +1935,6 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
return ExprError();
}
-
-
ExprResult Sema::
ActOnClassPropertyRefExpr(IdentifierInfo &receiverName,
IdentifierInfo &propertyName,
@@ -2032,7 +2049,7 @@ class ObjCInterfaceOrSuperCCC : public CorrectionCandidateCallback {
}
};
-}
+} // end anonymous namespace
Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
IdentifierInfo *Name,
@@ -2040,7 +2057,7 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
bool IsSuper,
bool HasTrailingDot,
ParsedType &ReceiverType) {
- ReceiverType = ParsedType();
+ ReceiverType = nullptr;
// If the identifier is "super" and there is no trailing dot, we're
// messaging super. If the identifier is "super" and there is a
@@ -2183,7 +2200,6 @@ ExprResult Sema::ActOnSuperMessage(Scope *S,
LBracLoc, SelectorLocs, RBracLoc, Args);
}
-
ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
bool isSuperReceiver,
SourceLocation Loc,
@@ -2198,7 +2214,6 @@ ExprResult Sema::BuildClassMessageImplicit(QualType ReceiverType,
/*SuperLoc=*/isSuperReceiver ? Loc : SourceLocation(),
Sel, Method, Loc, Loc, Loc, Args,
/*isImplicit=*/true);
-
}
static void applyCocoaAPICheck(Sema &S, const ObjCMessageExpr *Msg,
@@ -2465,7 +2480,6 @@ ExprResult Sema::ActOnClassMessage(Scope *S,
if (ReceiverType.isNull())
return ExprError();
-
if (!ReceiverTypeInfo)
ReceiverTypeInfo = Context.getTrivialTypeSourceInfo(ReceiverType, LBracLoc);
@@ -2621,29 +2635,28 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method) {
// Handle messages to id and __kindof types (where we use the
// global method pool).
- // FIXME: The type bound is currently ignored by lookup in the
- // global pool.
const ObjCObjectType *typeBound = nullptr;
bool receiverIsIdLike = ReceiverType->isObjCIdOrObjectKindOfType(Context,
typeBound);
if (receiverIsIdLike || ReceiverType->isBlockPointerType() ||
(Receiver && Context.isObjCNSObjectType(Receiver->getType()))) {
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc),
- receiverIsIdLike);
- if (!Method)
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc,RBracLoc),
- receiverIsIdLike);
- if (Method) {
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ // If we have a type bound, further filter the methods.
+ CollectMultipleMethodsInGlobalPool(Sel, Methods, true/*InstanceFirst*/,
+ true/*CheckTheOther*/, typeBound);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try to
+ // select a better one.
+ Method = Methods[0];
+
if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(), Methods))
Method = BestMethod;
+
if (!AreMultipleMethodsInGlobalPool(Sel, Method,
SourceRange(LBracLoc, RBracLoc),
- receiverIsIdLike)) {
- DiagnoseUseOfDecl(Method, SelLoc);
- }
+ receiverIsIdLike, Methods))
+ DiagnoseUseOfDecl(Method, SelLoc);
}
} else if (ReceiverType->isObjCClassOrClassKindOfType() ||
ReceiverType->isObjCQualifiedClassType()) {
@@ -2681,25 +2694,32 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
if (!Method) {
// If not messaging 'self', look for any factory method named 'Sel'.
if (!Receiver || !isSelfExpr(Receiver)) {
- Method = LookupFactoryMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (!Method) {
- // If no class (factory) method was found, check if an _instance_
- // method of the same name exists in the root class only.
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (Method)
- if (const ObjCInterfaceDecl *ID =
- dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
- if (ID->getSuperClass())
- Diag(SelLoc, diag::warn_root_inst_method_not_found)
- << Sel << SourceRange(LBracLoc, RBracLoc);
- }
+ // If no class (factory) method was found, check if an _instance_
+ // method of the same name exists in the root class only.
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ CollectMultipleMethodsInGlobalPool(Sel, Methods,
+ false/*InstanceFirst*/,
+ true/*CheckTheOther*/);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try
+ // to select a better one.
+ Method = Methods[0];
+
+ // If we find an instance method, emit waring.
+ if (Method->isInstanceMethod()) {
+ if (const ObjCInterfaceDecl *ID =
+ dyn_cast<ObjCInterfaceDecl>(Method->getDeclContext())) {
+ if (ID->getSuperClass())
+ Diag(SelLoc, diag::warn_root_inst_method_not_found)
+ << Sel << SourceRange(LBracLoc, RBracLoc);
+ }
+ }
+
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
+ Methods))
+ Method = BestMethod;
}
- if (Method)
- if (ObjCMethodDecl *BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
- Method = BestMethod;
}
}
}
@@ -2764,15 +2784,24 @@ ExprResult Sema::BuildInstanceMessage(Expr *Receiver,
// behavior isn't very desirable, however we need it for GCC
// compatibility. FIXME: should we deviate??
if (OCIType->qual_empty()) {
- Method = LookupInstanceMethodInGlobalPool(Sel,
- SourceRange(LBracLoc, RBracLoc));
- if (Method) {
- if (auto BestMethod =
- SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod()))
+ SmallVector<ObjCMethodDecl*, 4> Methods;
+ CollectMultipleMethodsInGlobalPool(Sel, Methods,
+ true/*InstanceFirst*/,
+ false/*CheckTheOther*/);
+ if (!Methods.empty()) {
+ // We chose the first method as the initial condidate, then try
+ // to select a better one.
+ Method = Methods[0];
+
+ if (ObjCMethodDecl *BestMethod =
+ SelectBestMethod(Sel, ArgsIn, Method->isInstanceMethod(),
+ Methods))
Method = BestMethod;
+
AreMultipleMethodsInGlobalPool(Sel, Method,
SourceRange(LBracLoc, RBracLoc),
- true);
+ true/*receiverIdOrClass*/,
+ Methods);
}
if (Method && !forwardClass)
Diag(SelLoc, diag::warn_maynot_respond)
@@ -3052,11 +3081,13 @@ enum ARCConversionTypeClass {
/// struct A*
ACTC_coreFoundation
};
+
static bool isAnyRetainable(ARCConversionTypeClass ACTC) {
return (ACTC == ACTC_retainable ||
ACTC == ACTC_coreFoundation ||
ACTC == ACTC_voidPtr);
}
+
static bool isAnyCLike(ARCConversionTypeClass ACTC) {
return ACTC == ACTC_none ||
ACTC == ACTC_voidPtr ||
@@ -3328,7 +3359,7 @@ namespace {
}
}
};
-}
+} // end anonymous namespace
bool Sema::isKnownName(StringRef name) {
if (name.empty())
@@ -3475,6 +3506,8 @@ diagnoseObjCARCConversion(Sema &S, SourceRange castRange,
return;
QualType castExprType = castExpr->getType();
+ // Defer emitting a diagnostic for bridge-related casts; that will be
+ // handled by CheckObjCBridgeRelatedConversions.
TypedefNameDecl *TDNDecl = nullptr;
if ((castACTC == ACTC_coreFoundation && exprACTC == ACTC_retainable &&
ObjCBridgeRelatedAttrFromType(castType, TDNDecl)) ||
@@ -3780,7 +3813,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) {
else if (PRE->isImplicitProperty()) {
if (ObjCMethodDecl *Getter = PRE->getImplicitPropertyGetter())
SrcType = Getter->getReturnType();
-
}
}
@@ -3790,7 +3822,6 @@ void Sema::CheckObjCBridgeRelatedCast(QualType castType, Expr *castExpr) {
return;
CheckObjCBridgeRelatedConversions(castExpr->getLocStart(),
castType, SrcType, castExpr);
- return;
}
bool Sema::CheckTollFreeBridgeStaticCast(QualType castType, Expr *castExpr,
@@ -3919,16 +3950,16 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
<< FixItHint::CreateInsertion(SrcExprEndLoc, "]");
Diag(RelatedClass->getLocStart(), diag::note_declared_at);
Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- }
- QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
- // Argument.
- Expr *args[] = { SrcExpr };
- ExprResult msg = BuildClassMessageImplicit(receiverType, false,
+ QualType receiverType = Context.getObjCInterfaceType(RelatedClass);
+ // Argument.
+ Expr *args[] = { SrcExpr };
+ ExprResult msg = BuildClassMessageImplicit(receiverType, false,
ClassMethod->getLocation(),
ClassMethod->getSelector(), ClassMethod,
MultiExprArg(args, 1));
- SrcExpr = msg.get();
+ SrcExpr = msg.get();
+ }
return true;
}
}
@@ -3962,14 +3993,14 @@ Sema::CheckObjCBridgeRelatedConversions(SourceLocation Loc,
}
Diag(RelatedClass->getLocStart(), diag::note_declared_at);
Diag(TDNDecl->getLocStart(), diag::note_declared_at);
- }
- ExprResult msg =
- BuildInstanceMessageImplicit(SrcExpr, SrcType,
- InstanceMethod->getLocation(),
- InstanceMethod->getSelector(),
- InstanceMethod, None);
- SrcExpr = msg.get();
+ ExprResult msg =
+ BuildInstanceMessageImplicit(SrcExpr, SrcType,
+ InstanceMethod->getLocation(),
+ InstanceMethod->getSelector(),
+ InstanceMethod, None);
+ SrcExpr = msg.get();
+ }
return true;
}
}
@@ -3993,9 +4024,9 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
ARCConversionTypeClass exprACTC = classifyTypeForARCConversion(castExprType);
ARCConversionTypeClass castACTC = classifyTypeForARCConversion(effCastType);
if (exprACTC == castACTC) {
- // check for viablity and report error if casting an rvalue to a
+ // Check for viability and report error if casting an rvalue to a
// life-time qualifier.
- if (Diagnose && castACTC == ACTC_retainable &&
+ if (castACTC == ACTC_retainable &&
(CCK == CCK_CStyleCast || CCK == CCK_OtherCast) &&
castType != castExprType) {
const Type *DT = castType.getTypePtr();
@@ -4011,10 +4042,12 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
QDT = AT->desugar();
if (QDT != castType &&
QDT.getObjCLifetime() != Qualifiers::OCL_None) {
- SourceLocation loc =
- (castRange.isValid() ? castRange.getBegin()
- : castExpr->getExprLoc());
- Diag(loc, diag::err_arc_nolifetime_behavior);
+ if (Diagnose) {
+ SourceLocation loc = (castRange.isValid() ? castRange.getBegin()
+ : castExpr->getExprLoc());
+ Diag(loc, diag::err_arc_nolifetime_behavior);
+ }
+ return ACR_error;
}
}
return ACR_okay;
@@ -4051,7 +4084,7 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
castExpr = ImplicitCastExpr::Create(Context, castExpr->getType(),
CK_ARCConsumeObject, castExpr,
nullptr, VK_RValue);
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
return ACR_okay;
}
@@ -4062,24 +4095,26 @@ Sema::CheckObjCARCConversion(SourceRange castRange, QualType castType,
CCK != CCK_ImplicitConversion)
return ACR_unbridged;
- // Do not issue bridge cast" diagnostic when implicit casting a cstring
- // to 'NSString *'. Let caller issue a normal mismatched diagnostic with
- // suitable fix-it.
+ // Issue a diagnostic about a missing @-sign when implicit casting a cstring
+ // to 'NSString *', instead of falling through to report a "bridge cast"
+ // diagnostic.
if (castACTC == ACTC_retainable && exprACTC == ACTC_none &&
ConversionToObjCStringLiteralCheck(castType, castExpr, Diagnose))
- return ACR_okay;
+ return ACR_error;
// Do not issue "bridge cast" diagnostic when implicit casting
// a retainable object to a CF type parameter belonging to an audited
// CF API function. Let caller issue a normal type mismatched diagnostic
// instead.
- if (Diagnose &&
- (!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
- castACTC != ACTC_coreFoundation))
- if (!(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
- (Opc == BO_NE || Opc == BO_EQ)))
+ if ((!DiagnoseCFAudited || exprACTC != ACTC_retainable ||
+ castACTC != ACTC_coreFoundation) &&
+ !(exprACTC == ACTC_voidPtr && castACTC == ACTC_retainable &&
+ (Opc == BO_NE || Opc == BO_EQ))) {
+ if (Diagnose)
diagnoseObjCARCConversion(*this, castRange, castType, castACTC, castExpr,
castExpr, exprACTC, CCK);
+ return ACR_error;
+ }
return ACR_okay;
}
@@ -4292,7 +4327,7 @@ ExprResult Sema::BuildObjCBridgedCast(SourceLocation LParenLoc,
TSInfo, SubExpr);
if (MustConsume) {
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
Result = ImplicitCastExpr::Create(Context, T, CK_ARCConsumeObject, Result,
nullptr, VK_RValue);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
index c3a89463dc69..060ee3eef212 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaInit.cpp
@@ -26,6 +26,7 @@
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
#include <map>
+
using namespace clang;
//===----------------------------------------------------------------------===//
@@ -204,6 +205,8 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
// Semantic checking for initializer lists.
//===----------------------------------------------------------------------===//
+namespace {
+
/// @brief Semantic checking for initializer lists.
///
/// The InitListChecker class contains a set of routines that each
@@ -231,11 +234,11 @@ static void CheckStringInit(Expr *Str, QualType &DeclT, const ArrayType *AT,
/// point. CheckDesignatedInitializer() recursively steps into the
/// designated subobject and manages backing out the recursion to
/// initialize the subobjects after the one designated.
-namespace {
class InitListChecker {
Sema &SemaRef;
bool hadError;
bool VerifyOnly; // no diagnostics, no structure building
+ bool TreatUnavailableAsInvalid; // Used only in VerifyOnly mode.
llvm::DenseMap<InitListExpr *, InitListExpr *> SyntacticToSemantic;
InitListExpr *FullyStructuredList;
@@ -280,6 +283,7 @@ class InitListChecker {
unsigned &StructuredIndex);
void CheckStructUnionTypes(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
+ CXXRecordDecl::base_class_range Bases,
RecordDecl::field_iterator Field,
bool SubobjectIsDesignatorContext, unsigned &Index,
InitListExpr *StructuredList,
@@ -317,7 +321,8 @@ class InitListChecker {
static ExprResult PerformEmptyInit(Sema &SemaRef,
SourceLocation Loc,
const InitializedEntity &Entity,
- bool VerifyOnly);
+ bool VerifyOnly,
+ bool TreatUnavailableAsInvalid);
// Explanation on the "FillWithNoInit" mode:
//
@@ -338,6 +343,10 @@ class InitListChecker {
// in the InitListExpr, the "holes" in Case#1 are filled not with empty
// initializers but with special "NoInitExpr" place holders, which tells the
// CodeGen not to generate any initializers for these parts.
+ void FillInEmptyInitForBase(unsigned Init, const CXXBaseSpecifier &Base,
+ const InitializedEntity &ParentEntity,
+ InitListExpr *ILE, bool &RequiresSecondPass,
+ bool FillWithNoInit);
void FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE, bool &RequiresSecondPass,
@@ -353,19 +362,22 @@ class InitListChecker {
public:
InitListChecker(Sema &S, const InitializedEntity &Entity,
- InitListExpr *IL, QualType &T, bool VerifyOnly);
+ InitListExpr *IL, QualType &T, bool VerifyOnly,
+ bool TreatUnavailableAsInvalid);
bool HadError() { return hadError; }
// @brief Retrieves the fully-structured initializer list used for
// semantic analysis and code generation.
InitListExpr *getFullyStructuredList() const { return FullyStructuredList; }
};
+
} // end anonymous namespace
ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
SourceLocation Loc,
const InitializedEntity &Entity,
- bool VerifyOnly) {
+ bool VerifyOnly,
+ bool TreatUnavailableAsInvalid) {
InitializationKind Kind = InitializationKind::CreateValue(Loc, Loc, Loc,
true);
MultiExprArg SubInit;
@@ -419,8 +431,6 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
if (CtorDecl->getMinRequiredArguments() == 0 &&
CtorDecl->isExplicit() && R->getDeclName() &&
SemaRef.SourceMgr.isInSystemHeader(CtorDecl->getLocation())) {
-
-
bool IsInStd = false;
for (NamespaceDecl *ND = dyn_cast<NamespaceDecl>(R->getDeclContext());
ND && !IsInStd; ND = dyn_cast<NamespaceDecl>(ND->getParent())) {
@@ -437,7 +447,8 @@ ExprResult InitListChecker::PerformEmptyInit(Sema &SemaRef,
InitSeq.InitializeFrom(
SemaRef, Entity,
InitializationKind::CreateValue(Loc, Loc, Loc, true),
- MultiExprArg(), /*TopLevelOfInitList=*/false);
+ MultiExprArg(), /*TopLevelOfInitList=*/false,
+ TreatUnavailableAsInvalid);
// Emit a warning for this. System header warnings aren't shown
// by default, but people working on system headers should see it.
if (!VerifyOnly) {
@@ -474,10 +485,43 @@ void InitListChecker::CheckEmptyInitializable(const InitializedEntity &Entity,
SourceLocation Loc) {
assert(VerifyOnly &&
"CheckEmptyInitializable is only inteded for verification mode.");
- if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true).isInvalid())
+ if (PerformEmptyInit(SemaRef, Loc, Entity, /*VerifyOnly*/true,
+ TreatUnavailableAsInvalid).isInvalid())
hadError = true;
}
+void InitListChecker::FillInEmptyInitForBase(
+ unsigned Init, const CXXBaseSpecifier &Base,
+ const InitializedEntity &ParentEntity, InitListExpr *ILE,
+ bool &RequiresSecondPass, bool FillWithNoInit) {
+ assert(Init < ILE->getNumInits() && "should have been expanded");
+
+ InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
+ SemaRef.Context, &Base, false, &ParentEntity);
+
+ if (!ILE->getInit(Init)) {
+ ExprResult BaseInit =
+ FillWithNoInit ? new (SemaRef.Context) NoInitExpr(Base.getType())
+ : PerformEmptyInit(SemaRef, ILE->getLocEnd(), BaseEntity,
+ /*VerifyOnly*/ false,
+ TreatUnavailableAsInvalid);
+ if (BaseInit.isInvalid()) {
+ hadError = true;
+ return;
+ }
+
+ ILE->setInit(Init, BaseInit.getAs<Expr>());
+ } else if (InitListExpr *InnerILE =
+ dyn_cast<InitListExpr>(ILE->getInit(Init))) {
+ FillInEmptyInitializations(BaseEntity, InnerILE,
+ RequiresSecondPass, FillWithNoInit);
+ } else if (DesignatedInitUpdateExpr *InnerDIUE =
+ dyn_cast<DesignatedInitUpdateExpr>(ILE->getInit(Init))) {
+ FillInEmptyInitializations(BaseEntity, InnerDIUE->getUpdater(),
+ RequiresSecondPass, /*FillWithNoInit =*/true);
+ }
+}
+
void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
const InitializedEntity &ParentEntity,
InitListExpr *ILE,
@@ -535,7 +579,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
}
ExprResult MemberInit = PerformEmptyInit(SemaRef, Loc, MemberEntity,
- /*VerifyOnly*/false);
+ /*VerifyOnly*/false,
+ TreatUnavailableAsInvalid);
if (MemberInit.isInvalid()) {
hadError = true;
return;
@@ -592,14 +637,25 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
// The fields beyond ILE->getNumInits() are default initialized, so in
// order to leave them uninitialized, the ILE is expanded and the extra
// fields are then filled with NoInitExpr.
- unsigned NumFields = 0;
- for (auto *Field : RDecl->fields())
- if (!Field->isUnnamedBitfield())
- ++NumFields;
- if (ILE->getNumInits() < NumFields)
- ILE->resizeInits(SemaRef.Context, NumFields);
+ unsigned NumElems = numStructUnionElements(ILE->getType());
+ if (RDecl->hasFlexibleArrayMember())
+ ++NumElems;
+ if (ILE->getNumInits() < NumElems)
+ ILE->resizeInits(SemaRef.Context, NumElems);
unsigned Init = 0;
+
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RDecl)) {
+ for (auto &Base : CXXRD->bases()) {
+ if (hadError)
+ return;
+
+ FillInEmptyInitForBase(Init, Base, Entity, ILE, RequiresSecondPass,
+ FillWithNoInit);
+ ++Init;
+ }
+ }
+
for (auto *Field : RDecl->fields()) {
if (Field->isUnnamedBitfield())
continue;
@@ -661,7 +717,8 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
else {
ExprResult ElementInit = PerformEmptyInit(SemaRef, ILE->getLocEnd(),
ElementEntity,
- /*VerifyOnly*/false);
+ /*VerifyOnly*/false,
+ TreatUnavailableAsInvalid);
if (ElementInit.isInvalid()) {
hadError = true;
return;
@@ -707,11 +764,12 @@ InitListChecker::FillInEmptyInitializations(const InitializedEntity &Entity,
}
}
-
InitListChecker::InitListChecker(Sema &S, const InitializedEntity &Entity,
InitListExpr *IL, QualType &T,
- bool VerifyOnly)
- : SemaRef(S), VerifyOnly(VerifyOnly) {
+ bool VerifyOnly,
+ bool TreatUnavailableAsInvalid)
+ : SemaRef(S), VerifyOnly(VerifyOnly),
+ TreatUnavailableAsInvalid(TreatUnavailableAsInvalid) {
// FIXME: Check that IL isn't already the semantic form of some other
// InitListExpr. If it is, we'd create a broken AST.
@@ -744,6 +802,8 @@ int InitListChecker::numArrayElements(QualType DeclType) {
int InitListChecker::numStructUnionElements(QualType DeclType) {
RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
int InitializableMembers = 0;
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(structDecl))
+ InitializableMembers += CXXRD->getNumBases();
for (const auto *Field : structDecl->fields())
if (!Field->isUnnamedBitfield())
++InitializableMembers;
@@ -888,7 +948,6 @@ static void warnBracedScalarInit(Sema &S, const InitializedEntity &Entity,
}
}
-
/// Check whether the initializer \p IList (that was written with explicit
/// braces) can be used to initialize an object of type \p T.
///
@@ -992,10 +1051,14 @@ void InitListChecker::CheckListElementTypes(const InitializedEntity &Entity,
assert(DeclType->isAggregateType() &&
"non-aggregate records should be handed in CheckSubElementType");
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
- CheckStructUnionTypes(Entity, IList, DeclType, RD->field_begin(),
- SubobjectIsDesignatorContext, Index,
- StructuredList, StructuredIndex,
- TopLevelObject);
+ auto Bases =
+ CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
+ CXXRecordDecl::base_class_iterator());
+ if (auto *CXXRD = dyn_cast<CXXRecordDecl>(RD))
+ Bases = CXXRD->bases();
+ CheckStructUnionTypes(Entity, IList, DeclType, Bases, RD->field_begin(),
+ SubobjectIsDesignatorContext, Index, StructuredList,
+ StructuredIndex, TopLevelObject);
} else if (DeclType->isArrayType()) {
llvm::APSInt Zero(
SemaRef.Context.getTypeSize(SemaRef.Context.getSizeType()),
@@ -1130,8 +1193,8 @@ void InitListChecker::CheckSubElementType(const InitializedEntity &Entity,
// Fall through for subaggregate initialization.
} else {
- assert((ElemType->isRecordType() || ElemType->isVectorType()) &&
- "Unexpected type");
+ assert((ElemType->isRecordType() || ElemType->isVectorType() ||
+ ElemType->isClkEventT()) && "Unexpected type");
// C99 6.7.8p13:
//
@@ -1220,7 +1283,6 @@ void InitListChecker::CheckComplexType(const InitializedEntity &Entity,
}
}
-
void InitListChecker::CheckScalarType(const InitializedEntity &Entity,
InitListExpr *IList, QualType DeclType,
unsigned &Index,
@@ -1672,16 +1734,13 @@ bool InitListChecker::CheckFlexibleArrayInit(const InitializedEntity &Entity,
return FlexArrayDiag != diag::ext_flexible_array_init;
}
-void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
- InitListExpr *IList,
- QualType DeclType,
- RecordDecl::field_iterator Field,
- bool SubobjectIsDesignatorContext,
- unsigned &Index,
- InitListExpr *StructuredList,
- unsigned &StructuredIndex,
- bool TopLevelObject) {
- RecordDecl* structDecl = DeclType->getAs<RecordType>()->getDecl();
+void InitListChecker::CheckStructUnionTypes(
+ const InitializedEntity &Entity, InitListExpr *IList, QualType DeclType,
+ CXXRecordDecl::base_class_range Bases, RecordDecl::field_iterator Field,
+ bool SubobjectIsDesignatorContext, unsigned &Index,
+ InitListExpr *StructuredList, unsigned &StructuredIndex,
+ bool TopLevelObject) {
+ RecordDecl *structDecl = DeclType->getAs<RecordType>()->getDecl();
// If the record is invalid, some of it's members are invalid. To avoid
// confusion, we forgo checking the intializer for the entire record.
@@ -1726,13 +1785,35 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
return;
}
+ bool InitializedSomething = false;
+
+ // If we have any base classes, they are initialized prior to the fields.
+ for (auto &Base : Bases) {
+ Expr *Init = Index < IList->getNumInits() ? IList->getInit(Index) : nullptr;
+ SourceLocation InitLoc = Init ? Init->getLocStart() : IList->getLocEnd();
+
+ // Designated inits always initialize fields, so if we see one, all
+ // remaining base classes have no explicit initializer.
+ if (Init && isa<DesignatedInitExpr>(Init))
+ Init = nullptr;
+
+ InitializedEntity BaseEntity = InitializedEntity::InitializeBase(
+ SemaRef.Context, &Base, false, &Entity);
+ if (Init) {
+ CheckSubElementType(BaseEntity, IList, Base.getType(), Index,
+ StructuredList, StructuredIndex);
+ InitializedSomething = true;
+ } else if (VerifyOnly) {
+ CheckEmptyInitializable(BaseEntity, InitLoc);
+ }
+ }
+
// If structDecl is a forward declaration, this loop won't do
// anything except look at designated initializers; That's okay,
// because an error should get printed out elsewhere. It might be
// worthwhile to skip over the rest of the initializer, though.
RecordDecl *RD = DeclType->getAs<RecordType>()->getDecl();
RecordDecl::field_iterator FieldEnd = RD->field_end();
- bool InitializedSomething = false;
bool CheckForMissingFields = true;
while (Index < IList->getNumInits()) {
Expr *Init = IList->getInit(Index);
@@ -1782,7 +1863,7 @@ void InitListChecker::CheckStructUnionTypes(const InitializedEntity &Entity,
// Make sure we can use this declaration.
bool InvalidUse;
if (VerifyOnly)
- InvalidUse = !SemaRef.CanUseDecl(*Field);
+ InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid);
else
InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field,
IList->getInit(Index)->getLocStart());
@@ -1895,8 +1976,8 @@ static DesignatedInitExpr *CloneDesignatedInitExpr(Sema &SemaRef,
SmallVector<Expr*, 4> IndexExprs(NumIndexExprs);
for (unsigned I = 0; I < NumIndexExprs; ++I)
IndexExprs[I] = DIE->getSubExpr(I + 1);
- return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators_begin(),
- DIE->size(), IndexExprs,
+ return DesignatedInitExpr::Create(SemaRef.Context, DIE->designators(),
+ IndexExprs,
DIE->getEqualOrColonLoc(),
DIE->usesGNUSyntax(), DIE->getInit());
}
@@ -1919,7 +2000,7 @@ class FieldInitializerValidatorCCC : public CorrectionCandidateCallback {
RecordDecl *Record;
};
-}
+} // end anonymous namespace
/// @brief Check the well-formedness of a C99 designated initializer.
///
@@ -2146,8 +2227,10 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
for (auto *FI : RT->getDecl()->fields()) {
if (FI->isUnnamedBitfield())
continue;
- if (KnownField == FI)
+ if (declaresSameEntity(KnownField, FI)) {
+ KnownField = FI;
break;
+ }
++FieldIndex;
}
@@ -2160,11 +2243,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
FieldIndex = 0;
if (!VerifyOnly) {
FieldDecl *CurrentField = StructuredList->getInitializedFieldInUnion();
- if (CurrentField && CurrentField != *Field) {
+ if (CurrentField && !declaresSameEntity(CurrentField, *Field)) {
assert(StructuredList->getNumInits() == 1
&& "A union should never have more than one initializer!");
- // we're about to throw away an initializer, emit warning
+ // We're about to throw away an initializer, emit warning.
SemaRef.Diag(D->getFieldLoc(),
diag::warn_initializer_overrides)
<< D->getSourceRange();
@@ -2186,7 +2269,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Make sure we can use this declaration.
bool InvalidUse;
if (VerifyOnly)
- InvalidUse = !SemaRef.CanUseDecl(*Field);
+ InvalidUse = !SemaRef.CanUseDecl(*Field, TreatUnavailableAsInvalid);
else
InvalidUse = SemaRef.DiagnoseUseOfDecl(*Field, D->getFieldLoc());
if (InvalidUse) {
@@ -2276,7 +2359,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (CheckDesignatedInitializer(MemberEntity, IList, DIE, DesigIdx + 1,
FieldType, nullptr, nullptr, Index,
StructuredList, newStructuredIndex,
- true, false))
+ FinishSubobjectInit, false))
return true;
}
@@ -2304,8 +2387,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
// Check the remaining fields within this class/struct/union subobject.
bool prevHadError = hadError;
- CheckStructUnionTypes(Entity, IList, CurrentObjectType, Field, false, Index,
- StructuredList, FieldIndex);
+ auto NoBases =
+ CXXRecordDecl::base_class_range(CXXRecordDecl::base_class_iterator(),
+ CXXRecordDecl::base_class_iterator());
+ CheckStructUnionTypes(Entity, IList, CurrentObjectType, NoBases, Field,
+ false, Index, StructuredList, FieldIndex);
return hadError && !prevHadError;
}
@@ -2467,11 +2553,11 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
Index = OldIndex;
ElementEntity.setElementIndex(ElementIndex);
- if (CheckDesignatedInitializer(ElementEntity, IList, DIE, DesigIdx + 1,
- ElementType, nullptr, nullptr, Index,
- StructuredList, ElementIndex,
- (DesignatedStartIndex == DesignatedEndIndex),
- false))
+ if (CheckDesignatedInitializer(
+ ElementEntity, IList, DIE, DesigIdx + 1, ElementType, nullptr,
+ nullptr, Index, StructuredList, ElementIndex,
+ FinishSubobjectInit && (DesignatedStartIndex == DesignatedEndIndex),
+ false))
return true;
// Move to the next index in the array that we'll be initializing.
@@ -2751,7 +2837,7 @@ ExprResult Sema::ActOnDesignatedInitializer(Designation &Desig,
DesignatedInitExpr *DIE
= DesignatedInitExpr::Create(Context,
- Designators.data(), Designators.size(),
+ Designators,
InitExpressions, Loc, GNUSyntax,
Init.getAs<Expr>());
@@ -2787,10 +2873,11 @@ InitializedEntity::InitializedEntity(ASTContext &Context, unsigned Index,
InitializedEntity
InitializedEntity::InitializeBase(ASTContext &Context,
const CXXBaseSpecifier *Base,
- bool IsInheritedVirtualBase) {
+ bool IsInheritedVirtualBase,
+ const InitializedEntity *Parent) {
InitializedEntity Result;
Result.Kind = EK_Base;
- Result.Parent = nullptr;
+ Result.Parent = Parent;
Result.Base = reinterpret_cast<uintptr_t>(Base);
if (IsInheritedVirtualBase)
Result.Base |= 0x01;
@@ -2928,7 +3015,7 @@ unsigned InitializedEntity::dumpImpl(raw_ostream &OS) const {
return Depth + 1;
}
-void InitializedEntity::dump() const {
+LLVM_DUMP_METHOD void InitializedEntity::dump() const {
dumpImpl(llvm::errs());
}
@@ -3137,13 +3224,9 @@ void InitializationSequence::AddListInitializationStep(QualType T) {
Steps.push_back(S);
}
-void
-InitializationSequence
-::AddConstructorInitializationStep(CXXConstructorDecl *Constructor,
- AccessSpecifier Access,
- QualType T,
- bool HadMultipleCandidates,
- bool FromInitList, bool AsInitList) {
+void InitializationSequence::AddConstructorInitializationStep(
+ DeclAccessPair FoundDecl, CXXConstructorDecl *Constructor, QualType T,
+ bool HadMultipleCandidates, bool FromInitList, bool AsInitList) {
Step S;
S.Kind = FromInitList ? AsInitList ? SK_StdInitializerListConstructorCall
: SK_ConstructorInitializationFromList
@@ -3151,7 +3234,7 @@ InitializationSequence
S.Type = T;
S.Function.HadMultipleCandidates = HadMultipleCandidates;
S.Function.Function = Constructor;
- S.Function.FoundDecl = DeclAccessPair::make(Constructor, Access);
+ S.Function.FoundDecl = FoundDecl;
Steps.push_back(S);
}
@@ -3313,7 +3396,8 @@ static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
- InitializationSequence &Sequence);
+ InitializationSequence &Sequence,
+ bool TreatUnavailableAsInvalid);
/// \brief When initializing from init list via constructor, handle
/// initialization of an object of type std::initializer_list<T>.
@@ -3323,7 +3407,8 @@ static void TryListInitialization(Sema &S,
static bool TryInitializerListConstruction(Sema &S,
InitListExpr *List,
QualType DestType,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TreatUnavailableAsInvalid) {
QualType E;
if (!S.isStdInitializerList(DestType, &E))
return false;
@@ -3342,7 +3427,8 @@ static bool TryInitializerListConstruction(Sema &S,
InitializedEntity::InitializeTemporary(ArrayType);
InitializationKind Kind =
InitializationKind::CreateDirectList(List->getExprLoc());
- TryListInitialization(S, HiddenArray, Kind, List, Sequence);
+ TryListInitialization(S, HiddenArray, Kind, List, Sequence,
+ TreatUnavailableAsInvalid);
if (Sequence)
Sequence.AddStdInitializerListConstructionStep(DestType);
return true;
@@ -3359,18 +3445,13 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
CandidateSet.clear();
for (NamedDecl *D : Ctors) {
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
- bool SuppressUserConversions = false;
+ auto Info = getConstructorInfo(D);
+ if (!Info.Constructor)
+ continue;
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = nullptr;
- FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else {
- Constructor = cast<CXXConstructorDecl>(D);
+ bool SuppressUserConversions = false;
+ if (!Info.ConstructorTmpl) {
// C++11 [over.best.ics]p4:
// ... and the constructor or user-defined conversion function is a
// candidate by
@@ -3387,15 +3468,15 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
// parameter of a constructor of X.
if ((CopyInitializing ||
(IsListInit && Args.size() == 1 && isa<InitListExpr>(Args[0]))) &&
- Constructor->isCopyOrMoveConstructor())
+ Info.Constructor->isCopyOrMoveConstructor())
SuppressUserConversions = true;
}
- if (!Constructor->isInvalidDecl() &&
- (AllowExplicit || !Constructor->isExplicit()) &&
- (!OnlyListConstructors || S.isInitListConstructor(Constructor))) {
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ if (!Info.Constructor->isInvalidDecl() &&
+ (AllowExplicit || !Info.Constructor->isExplicit()) &&
+ (!OnlyListConstructors || S.isInitListConstructor(Info.Constructor))) {
+ if (Info.ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr, Args,
CandidateSet, SuppressUserConversions);
else {
@@ -3407,9 +3488,9 @@ ResolveConstructorOverload(Sema &S, SourceLocation DeclLoc,
// are also considered.
bool AllowExplicitConv = AllowExplicit && !CopyInitializing &&
Args.size() == 1 &&
- Constructor->isCopyOrMoveConstructor();
- S.AddOverloadCandidate(Constructor, FoundDecl, Args, CandidateSet,
- SuppressUserConversions,
+ Info.Constructor->isCopyOrMoveConstructor();
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, Args,
+ CandidateSet, SuppressUserConversions,
/*PartialOverloading=*/false,
/*AllowExplicit=*/AllowExplicitConv);
}
@@ -3517,18 +3598,23 @@ static void TryConstructorInitialization(Sema &S,
// If a program calls for the default initialization of an object
// of a const-qualified type T, T shall be a class type with a
// user-provided default constructor.
+ // C++ core issue 253 proposal:
+ // If the implicit default constructor initializes all subobjects, no
+ // initializer should be required.
+ // The 253 proposal is for example needed to process libstdc++ headers in 5.x.
+ CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (Kind.getKind() == InitializationKind::IK_Default &&
- Entity.getType().isConstQualified() &&
- !cast<CXXConstructorDecl>(Best->Function)->isUserProvided()) {
- if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
- Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
- return;
+ Entity.getType().isConstQualified()) {
+ if (!CtorDecl->getParent()->allowConstDefaultInit()) {
+ if (!maybeRecoverWithZeroInitialization(S, Sequence, Entity))
+ Sequence.SetFailed(InitializationSequence::FK_DefaultInitOfConst);
+ return;
+ }
}
// C++11 [over.match.list]p1:
// In copy-list-initialization, if an explicit constructor is chosen, the
// initializer is ill-formed.
- CXXConstructorDecl *CtorDecl = cast<CXXConstructorDecl>(Best->Function);
if (IsListInit && !Kind.AllowExplicit() && CtorDecl->isExplicit()) {
Sequence.SetFailed(InitializationSequence::FK_ExplicitConstructor);
return;
@@ -3538,7 +3624,7 @@ static void TryConstructorInitialization(Sema &S,
// subsumed by the initialization.
bool HadMultipleCandidates = (CandidateSet.size() > 1);
Sequence.AddConstructorInitializationStep(
- CtorDecl, Best->FoundDecl.getAccess(), DestType, HadMultipleCandidates,
+ Best->FoundDecl, CtorDecl, DestType, HadMultipleCandidates,
IsListInit | IsInitListCopy, AsInitializerList);
}
@@ -3591,7 +3677,8 @@ static void TryReferenceListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TreatUnavailableAsInvalid) {
// First, catch C++03 where this isn't possible.
if (!S.getLangOpts().CPlusPlus11) {
Sequence.SetFailed(InitializationSequence::FK_ReferenceBindingToInitList);
@@ -3647,7 +3734,8 @@ static void TryReferenceListInitialization(Sema &S,
// Not reference-related. Create a temporary and bind to that.
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(cv1T1);
- TryListInitialization(S, TempEntity, Kind, InitList, Sequence);
+ TryListInitialization(S, TempEntity, Kind, InitList, Sequence,
+ TreatUnavailableAsInvalid);
if (Sequence) {
if (DestType->isRValueReferenceType() ||
(T1Quals.hasConst() && !T1Quals.hasVolatile()))
@@ -3663,7 +3751,8 @@ static void TryListInitialization(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
InitListExpr *InitList,
- InitializationSequence &Sequence) {
+ InitializationSequence &Sequence,
+ bool TreatUnavailableAsInvalid) {
QualType DestType = Entity.getType();
// C++ doesn't allow scalar initialization with more than one argument.
@@ -3674,7 +3763,8 @@ static void TryListInitialization(Sema &S,
return;
}
if (DestType->isReferenceType()) {
- TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence);
+ TryReferenceListInitialization(S, Entity, Kind, InitList, Sequence,
+ TreatUnavailableAsInvalid);
return;
}
@@ -3718,7 +3808,8 @@ static void TryListInitialization(Sema &S,
InitList->getRBraceLoc())
: Kind;
Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
- /*TopLevelOfInitList*/ true);
+ /*TopLevelOfInitList*/ true,
+ TreatUnavailableAsInvalid);
// TryStringLiteralInitialization() (in InitializeFrom()) will fail if
// the element is not an appropriately-typed string literal, in which
@@ -3750,7 +3841,8 @@ static void TryListInitialization(Sema &S,
// - Otherwise, if T is a specialization of std::initializer_list<E>,
// an initializer_list object constructed [...]
- if (TryInitializerListConstruction(S, InitList, DestType, Sequence))
+ if (TryInitializerListConstruction(S, InitList, DestType, Sequence,
+ TreatUnavailableAsInvalid))
return;
// - Otherwise, if T is a class type, constructors are considered.
@@ -3763,8 +3855,48 @@ static void TryListInitialization(Sema &S,
}
if (S.getLangOpts().CPlusPlus && !DestType->isAggregateType() &&
- InitList->getNumInits() == 1 &&
- InitList->getInit(0)->getType()->isRecordType()) {
+ InitList->getNumInits() == 1) {
+ Expr *E = InitList->getInit(0);
+
+ // - Otherwise, if T is an enumeration with a fixed underlying type,
+ // the initializer-list has a single element v, and the initialization
+ // is direct-list-initialization, the object is initialized with the
+ // value T(v); if a narrowing conversion is required to convert v to
+ // the underlying type of T, the program is ill-formed.
+ auto *ET = DestType->getAs<EnumType>();
+ if (S.getLangOpts().CPlusPlus1z &&
+ Kind.getKind() == InitializationKind::IK_DirectList &&
+ ET && ET->getDecl()->isFixed() &&
+ !S.Context.hasSameUnqualifiedType(E->getType(), DestType) &&
+ (E->getType()->isIntegralOrEnumerationType() ||
+ E->getType()->isFloatingType())) {
+ // There are two ways that T(v) can work when T is an enumeration type.
+ // If there is either an implicit conversion sequence from v to T or
+ // a conversion function that can convert from v to T, then we use that.
+ // Otherwise, if v is of integral, enumeration, or floating-point type,
+ // it is converted to the enumeration type via its underlying type.
+ // There is no overlap possible between these two cases (except when the
+ // source value is already of the destination type), and the first
+ // case is handled by the general case for single-element lists below.
+ ImplicitConversionSequence ICS;
+ ICS.setStandard();
+ ICS.Standard.setAsIdentityConversion();
+ // If E is of a floating-point type, then the conversion is ill-formed
+ // due to narrowing, but go through the motions in order to produce the
+ // right diagnostic.
+ ICS.Standard.Second = E->getType()->isFloatingType()
+ ? ICK_Floating_Integral
+ : ICK_Integral_Conversion;
+ ICS.Standard.setFromType(E->getType());
+ ICS.Standard.setToType(0, E->getType());
+ ICS.Standard.setToType(1, DestType);
+ ICS.Standard.setToType(2, DestType);
+ Sequence.AddConversionSequenceStep(ICS, ICS.Standard.getToType(2),
+ /*TopLevelOfInitList*/true);
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
+
// - Otherwise, if the initializer list has a single element of type E
// [...references are handled above...], the object or reference is
// initialized from that element (by copy-initialization for
@@ -3778,22 +3910,25 @@ static void TryListInitialization(Sema &S,
// copy-initialization. This only matters if we might use an 'explicit'
// conversion operator, so we only need to handle the cases where the source
// is of record type.
- InitializationKind SubKind =
- Kind.getKind() == InitializationKind::IK_DirectList
- ? InitializationKind::CreateDirect(Kind.getLocation(),
- InitList->getLBraceLoc(),
- InitList->getRBraceLoc())
- : Kind;
- Expr *SubInit[1] = { InitList->getInit(0) };
- Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
- /*TopLevelOfInitList*/true);
- if (Sequence)
- Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
- return;
+ if (InitList->getInit(0)->getType()->isRecordType()) {
+ InitializationKind SubKind =
+ Kind.getKind() == InitializationKind::IK_DirectList
+ ? InitializationKind::CreateDirect(Kind.getLocation(),
+ InitList->getLBraceLoc(),
+ InitList->getRBraceLoc())
+ : Kind;
+ Expr *SubInit[1] = { InitList->getInit(0) };
+ Sequence.InitializeFrom(S, Entity, SubKind, SubInit,
+ /*TopLevelOfInitList*/true,
+ TreatUnavailableAsInvalid);
+ if (Sequence)
+ Sequence.RewrapReferenceInitList(Entity.getType(), InitList);
+ return;
+ }
}
InitListChecker CheckInitList(S, Entity, InitList,
- DestType, /*VerifyOnly=*/true);
+ DestType, /*VerifyOnly=*/true, TreatUnavailableAsInvalid);
if (CheckInitList.HadError()) {
Sequence.SetFailed(InitializationSequence::FK_ListInitializationFailed);
return;
@@ -3847,26 +3982,19 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,
CXXRecordDecl *T1RecordDecl = cast<CXXRecordDecl>(T1RecordType->getDecl());
for (NamedDecl *D : S.LookupConstructors(T1RecordDecl)) {
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = nullptr;
- FunctionTemplateDecl *ConstructorTmpl = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
+ auto Info = getConstructorInfo(D);
+ if (!Info.Constructor)
+ continue;
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ if (!Info.Constructor->isInvalidDecl() &&
+ Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (Info.ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
- S.AddOverloadCandidate(Constructor, FoundDecl,
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
}
@@ -4068,7 +4196,6 @@ convertQualifiersAndValueKindIfNecessary(Sema &S,
return Initializer->getValueKind();
}
-
/// \brief Reference initialization without resolving overloaded functions.
static void TryReferenceInitializationCore(Sema &S,
const InitializedEntity &Entity,
@@ -4303,7 +4430,6 @@ static void TryReferenceInitializationCore(Sema &S,
}
Sequence.AddReferenceBindingStep(cv1T1, /*bindingTemporary=*/true);
- return;
}
/// \brief Attempt character array initialization from a string literal
@@ -4472,27 +4598,19 @@ static void TryUserDefinedConversion(Sema &S,
Con = CopyOfCon.begin(), ConEnd = CopyOfCon.end();
Con != ConEnd; ++Con) {
NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = nullptr;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
+ auto Info = getConstructorInfo(D);
+ if (!Info.Constructor)
+ continue;
- if (!Constructor->isInvalidDecl() &&
- Constructor->isConvertingConstructor(AllowExplicit)) {
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
+ if (!Info.Constructor->isInvalidDecl() &&
+ Info.Constructor->isConvertingConstructor(AllowExplicit)) {
+ if (Info.ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
/*ExplicitArgs*/ nullptr,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
else
- S.AddOverloadCandidate(Constructor, FoundDecl,
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
Initializer, CandidateSet,
/*SuppressUserConversions=*/true);
}
@@ -4689,8 +4807,8 @@ static void checkIndirectCopyRestoreSource(Sema &S, Expr *src) {
// If isWeakAccess to true, there will be an implicit
// load which requires a cleanup.
if (S.getLangOpts().ObjCAutoRefCount && isWeakAccess)
- S.ExprNeedsCleanups = true;
-
+ S.Cleanup.setExprNeedsCleanups(true);
+
if (iik == IIK_okay) return;
S.Diag(src->getExprLoc(), diag::err_arc_nonlocal_writeback)
@@ -4800,9 +4918,11 @@ InitializationSequence::InitializationSequence(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args,
- bool TopLevelOfInitList)
+ bool TopLevelOfInitList,
+ bool TreatUnavailableAsInvalid)
: FailedCandidateSet(Kind.getLocation(), OverloadCandidateSet::CSK_Normal) {
- InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList);
+ InitializeFrom(S, Entity, Kind, Args, TopLevelOfInitList,
+ TreatUnavailableAsInvalid);
}
/// Tries to get a FunctionDecl out of `E`. If it succeeds and we can take the
@@ -4820,7 +4940,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
const InitializedEntity &Entity,
const InitializationKind &Kind,
MultiExprArg Args,
- bool TopLevelOfInitList) {
+ bool TopLevelOfInitList,
+ bool TreatUnavailableAsInvalid) {
ASTContext &Context = S.Context;
// Eliminate non-overload placeholder types in the arguments. We
@@ -4874,7 +4995,8 @@ void InitializationSequence::InitializeFrom(Sema &S,
// object is list-initialized (8.5.4).
if (Kind.getKind() != InitializationKind::IK_Direct) {
if (InitListExpr *InitList = dyn_cast_or_null<InitListExpr>(Initializer)) {
- TryListInitialization(S, Entity, Kind, InitList, *this);
+ TryListInitialization(S, Entity, Kind, InitList, *this,
+ TreatUnavailableAsInvalid);
return;
}
}
@@ -4958,7 +5080,7 @@ void InitializationSequence::InitializeFrom(Sema &S,
Entity.getKind() == InitializedEntity::EK_Member &&
Initializer && isa<InitListExpr>(Initializer)) {
TryListInitialization(S, Entity, Kind, cast<InitListExpr>(Initializer),
- *this);
+ *this, TreatUnavailableAsInvalid);
AddParenthesizedArrayInitStep(DestType);
} else if (DestAT->getElementType()->isCharType())
SetFailed(FK_ArrayNeedsInitListOrStringLiteral);
@@ -5232,38 +5354,33 @@ static void LookupCopyAndMoveConstructors(Sema &S,
for (SmallVectorImpl<NamedDecl *>::iterator
CI = Ctors.begin(), CE = Ctors.end(); CI != CE; ++CI) {
NamedDecl *D = *CI;
- CXXConstructorDecl *Constructor = nullptr;
+ auto Info = getConstructorInfo(D);
+ if (!Info.Constructor)
+ continue;
- if ((Constructor = dyn_cast<CXXConstructorDecl>(D))) {
- // Handle copy/moveconstructors, only.
- if (!Constructor || Constructor->isInvalidDecl() ||
- !Constructor->isCopyOrMoveConstructor() ||
- !Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
+ if (!Info.ConstructorTmpl) {
+ // Handle copy/move constructors, only.
+ if (Info.Constructor->isInvalidDecl() ||
+ !Info.Constructor->isCopyOrMoveConstructor() ||
+ !Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
continue;
- DeclAccessPair FoundDecl
- = DeclAccessPair::make(Constructor, Constructor->getAccess());
- S.AddOverloadCandidate(Constructor, FoundDecl,
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
CurInitExpr, CandidateSet);
continue;
}
// Handle constructor templates.
- FunctionTemplateDecl *ConstructorTmpl = cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl->isInvalidDecl())
+ if (Info.ConstructorTmpl->isInvalidDecl())
continue;
- Constructor = cast<CXXConstructorDecl>(
- ConstructorTmpl->getTemplatedDecl());
- if (!Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
+ if (!Info.Constructor->isConvertingConstructor(/*AllowExplicit=*/true))
continue;
// FIXME: Do we need to limit this to copy-constructor-like
// candidates?
- DeclAccessPair FoundDecl
- = DeclAccessPair::make(ConstructorTmpl, ConstructorTmpl->getAccess());
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl, nullptr,
- CurInitExpr, CandidateSet, true);
+ S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
+ nullptr, CurInitExpr, CandidateSet, true);
}
}
@@ -5402,8 +5519,8 @@ static ExprResult CopyObject(Sema &S,
SmallVector<Expr*, 8> ConstructorArgs;
CurInit.get(); // Ownership transferred into MultiExprArg, below.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Best->FoundDecl.getAccess(), IsExtraneousCopy);
+ S.CheckConstructorAccess(Loc, Constructor, Best->FoundDecl, Entity,
+ IsExtraneousCopy);
if (IsExtraneousCopy) {
// If this is a totally extraneous copy for C++03 reference
@@ -5438,7 +5555,8 @@ static ExprResult CopyObject(Sema &S,
return ExprError();
// Actually perform the constructor call.
- CurInit = S.BuildCXXConstructExpr(Loc, T, Constructor, Elidable,
+ CurInit = S.BuildCXXConstructExpr(Loc, T, Best->FoundDecl, Constructor,
+ Elidable,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
@@ -5485,7 +5603,7 @@ static void CheckCXX98CompatAccessibleCopy(Sema &S,
switch (OR) {
case OR_Success:
S.CheckConstructorAccess(Loc, cast<CXXConstructorDecl>(Best->Function),
- Entity, Best->FoundDecl.getAccess(), Diag);
+ Best->FoundDecl, Entity, Diag);
// FIXME: Check default arguments as far as that's possible.
break;
@@ -5611,7 +5729,6 @@ PerformConstructorInitialization(Sema &S,
if (isExplicitTemporary(Entity, Kind, NumArgs)) {
// An explicitly-constructed temporary, e.g., X(1, 2).
- S.MarkFunctionReferenced(Loc, Constructor);
if (S.DiagnoseUseOfDecl(Constructor, Loc))
return ExprError();
@@ -5623,10 +5740,19 @@ PerformConstructorInitialization(Sema &S,
? SourceRange(LBraceLoc, RBraceLoc)
: Kind.getParenRange();
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(
+ Step.Function.FoundDecl.getDecl())) {
+ Constructor = S.findInheritingConstructor(Loc, Constructor, Shadow);
+ if (S.DiagnoseUseOfDecl(Constructor, Loc))
+ return ExprError();
+ }
+ S.MarkFunctionReferenced(Loc, Constructor);
+
CurInit = new (S.Context) CXXTemporaryObjectExpr(
- S.Context, Constructor, TSInfo, ConstructorArgs, ParenOrBraceRange,
- HadMultipleCandidates, IsListInitialization,
- IsStdInitListInitialization, ConstructorInitRequiresZeroInit);
+ S.Context, Constructor, TSInfo,
+ ConstructorArgs, ParenOrBraceRange, HadMultipleCandidates,
+ IsListInitialization, IsStdInitListInitialization,
+ ConstructorInitRequiresZeroInit);
} else {
CXXConstructExpr::ConstructionKind ConstructKind =
CXXConstructExpr::CK_Complete;
@@ -5651,6 +5777,7 @@ PerformConstructorInitialization(Sema &S,
// unconditionally.
if (Entity.allowsNRVO())
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Step.Function.FoundDecl,
Constructor, /*Elidable=*/true,
ConstructorArgs,
HadMultipleCandidates,
@@ -5661,6 +5788,7 @@ PerformConstructorInitialization(Sema &S,
ParenOrBraceRange);
else
CurInit = S.BuildCXXConstructExpr(Loc, Entity.getType(),
+ Step.Function.FoundDecl,
Constructor,
ConstructorArgs,
HadMultipleCandidates,
@@ -5674,8 +5802,7 @@ PerformConstructorInitialization(Sema &S,
return ExprError();
// Only check access if all of that succeeded.
- S.CheckConstructorAccess(Loc, Constructor, Entity,
- Step.Function.FoundDecl.getAccess());
+ S.CheckConstructorAccess(Loc, Constructor, Step.Function.FoundDecl, Entity);
if (S.DiagnoseUseOfDecl(Step.Function.FoundDecl, Loc))
return ExprError();
@@ -5777,6 +5904,11 @@ static const InitializedEntity *getEntityForTemporaryLifetimeExtension(
FallbackDecl);
case InitializedEntity::EK_Base:
+ // For subobjects, we look at the complete object.
+ if (Entity->getParent())
+ return getEntityForTemporaryLifetimeExtension(Entity->getParent(),
+ Entity);
+ // Fall through.
case InitializedEntity::EK_Delegating:
// We can reach this case for aggregate initialization in a constructor:
// struct A { int &&r; };
@@ -6042,6 +6174,36 @@ static void CheckMoveOnConstruction(Sema &S, const Expr *InitExpr,
<< FixItHint::CreateRemoval(SourceRange(RParen, RParen));
}
+static void CheckForNullPointerDereference(Sema &S, const Expr *E) {
+ // Check to see if we are dereferencing a null pointer. If so, this is
+ // undefined behavior, so warn about it. This only handles the pattern
+ // "*null", which is a very syntactic check.
+ if (const UnaryOperator *UO = dyn_cast<UnaryOperator>(E->IgnoreParenCasts()))
+ if (UO->getOpcode() == UO_Deref &&
+ UO->getSubExpr()->IgnoreParenCasts()->
+ isNullPointerConstant(S.Context, Expr::NPC_ValueDependentIsNotNull)) {
+ S.DiagRuntimeBehavior(UO->getOperatorLoc(), UO,
+ S.PDiag(diag::warn_binding_null_to_reference)
+ << UO->getSubExpr()->getSourceRange());
+ }
+}
+
+MaterializeTemporaryExpr *
+Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
+ bool BoundToLvalueReference) {
+ auto MTE = new (Context)
+ MaterializeTemporaryExpr(T, Temporary, BoundToLvalueReference);
+
+ // Order an ExprWithCleanups for lifetime marks.
+ //
+ // TODO: It'll be good to have a single place to check the access of the
+ // destructor and generate ExprWithCleanups for various uses. Currently these
+ // are done in both CreateMaterializeTemporaryExpr and MaybeBindToTemporary,
+ // but there may be a chance to merge them.
+ Cleanup.setExprNeedsCleanups(false);
+ return MTE;
+}
+
ExprResult
InitializationSequence::Perform(Sema &S,
const InitializedEntity &Entity,
@@ -6294,6 +6456,7 @@ InitializationSequence::Perform(Sema &S,
/*IsInitializerList=*/false,
ExtendingEntity->getDecl());
+ CheckForNullPointerDereference(S, CurInit.get());
break;
case SK_BindReferenceToTemporary: {
@@ -6305,7 +6468,7 @@ InitializationSequence::Perform(Sema &S,
return ExprError();
// Materialize the temporary into memory.
- MaterializeTemporaryExpr *MTE = new (S.Context) MaterializeTemporaryExpr(
+ MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
Entity.getType().getNonReferenceType(), CurInit.get(),
Entity.getType()->isLValueReferenceType());
@@ -6325,7 +6488,7 @@ InitializationSequence::Perform(Sema &S,
MTE->getType()->isObjCLifetimeType()) ||
(MTE->getStorageDuration() == SD_Automatic &&
MTE->getType().isDestructedType()))
- S.ExprNeedsCleanups = true;
+ S.Cleanup.setExprNeedsCleanups(true);
CurInit = MTE;
break;
@@ -6360,7 +6523,8 @@ InitializationSequence::Perform(Sema &S,
return ExprError();
// Build an expression that constructs a temporary.
- CurInit = S.BuildCXXConstructExpr(Loc, Step->Type, Constructor,
+ CurInit = S.BuildCXXConstructExpr(Loc, Step->Type,
+ FoundFn, Constructor,
ConstructorArgs,
HadMultipleCandidates,
/*ListInit*/ false,
@@ -6371,8 +6535,8 @@ InitializationSequence::Perform(Sema &S,
if (CurInit.isInvalid())
return ExprError();
- S.CheckConstructorAccess(Kind.getLocation(), Constructor, Entity,
- FoundFn.getAccess());
+ S.CheckConstructorAccess(Kind.getLocation(), Constructor, FoundFn,
+ Entity);
if (S.DiagnoseUseOfDecl(FoundFn, Kind.getLocation()))
return ExprError();
@@ -6499,7 +6663,8 @@ InitializationSequence::Perform(Sema &S,
InitializedEntity TempEntity = InitializedEntity::InitializeTemporary(Ty);
InitializedEntity InitEntity = IsTemporary ? TempEntity : Entity;
InitListChecker PerformInitList(S, InitEntity,
- InitList, Ty, /*VerifyOnly=*/false);
+ InitList, Ty, /*VerifyOnly=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
if (PerformInitList.HadError())
return ExprError();
@@ -6715,9 +6880,9 @@ InitializationSequence::Perform(Sema &S,
<< CurInit.get()->getSourceRange();
// Materialize the temporary into memory.
- MaterializeTemporaryExpr *MTE = new (S.Context)
- MaterializeTemporaryExpr(CurInit.get()->getType(), CurInit.get(),
- /*BoundToLvalueReference=*/false);
+ MaterializeTemporaryExpr *MTE = S.CreateMaterializeTemporaryExpr(
+ CurInit.get()->getType(), CurInit.get(),
+ /*BoundToLvalueReference=*/false);
// Maybe lifetime-extend the array temporary's subobjects to match the
// entity's lifetime.
@@ -6870,7 +7035,8 @@ static void diagnoseListInit(Sema &S, const InitializedEntity &Entity,
}
InitListChecker DiagnoseInitList(S, Entity, InitList, DestType,
- /*VerifyOnly=*/false);
+ /*VerifyOnly=*/false,
+ /*TreatUnavailableAsInvalid=*/false);
assert(DiagnoseInitList.HadError() &&
"Inconsistent init list check result.");
}
@@ -7132,17 +7298,20 @@ bool InitializationSequence::Diagnose(Sema &S,
isa<CXXConstructorDecl>(S.CurContext)) {
// This is implicit default initialization of a member or
// base within a constructor. If no viable function was
- // found, notify the user that she needs to explicitly
+ // found, notify the user that they need to explicitly
// initialize this base/member.
CXXConstructorDecl *Constructor
= cast<CXXConstructorDecl>(S.CurContext);
+ const CXXRecordDecl *InheritedFrom = nullptr;
+ if (auto Inherited = Constructor->getInheritedConstructor())
+ InheritedFrom = Inherited.getShadowDecl()->getNominatedBaseClass();
if (Entity.getKind() == InitializedEntity::EK_Base) {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << (Constructor->getInheritedConstructor() ? 2 :
- Constructor->isImplicit() ? 1 : 0)
+ << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*base=*/0
- << Entity.getType();
+ << Entity.getType()
+ << InheritedFrom;
RecordDecl *BaseDecl
= Entity.getBaseSpecifier()->getType()->getAs<RecordType>()
@@ -7151,11 +7320,11 @@ bool InitializationSequence::Diagnose(Sema &S,
<< S.Context.getTagDeclType(BaseDecl);
} else {
S.Diag(Kind.getLocation(), diag::err_missing_default_ctor)
- << (Constructor->getInheritedConstructor() ? 2 :
- Constructor->isImplicit() ? 1 : 0)
+ << (InheritedFrom ? 2 : Constructor->isImplicit() ? 1 : 0)
<< S.Context.getTypeDeclType(Constructor->getParent())
<< /*member=*/1
- << Entity.getName();
+ << Entity.getName()
+ << InheritedFrom;
S.Diag(Entity.getDecl()->getLocation(),
diag::note_member_declared_at);
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
index 884add26e43a..1b8410d7f4b9 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaLambda.cpp
@@ -355,7 +355,8 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
SourceRange IntroducerRange,
TypeSourceInfo *MethodTypeInfo,
SourceLocation EndLoc,
- ArrayRef<ParmVarDecl *> Params) {
+ ArrayRef<ParmVarDecl *> Params,
+ const bool IsConstexprSpecified) {
QualType MethodType = MethodTypeInfo->getType();
TemplateParameterList *TemplateParams =
getGenericLambdaTemplateParameterList(getCurLambda(), *this);
@@ -392,7 +393,7 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
MethodType, MethodTypeInfo,
SC_None,
/*isInline=*/true,
- /*isConstExpr=*/false,
+ IsConstexprSpecified,
EndLoc);
Method->setAccess(AS_public);
@@ -414,11 +415,10 @@ CXXMethodDecl *Sema::startLambdaDefinition(CXXRecordDecl *Class,
// Add parameters.
if (!Params.empty()) {
Method->setParams(Params);
- CheckParmsForFunctionDef(const_cast<ParmVarDecl **>(Params.begin()),
- const_cast<ParmVarDecl **>(Params.end()),
+ CheckParmsForFunctionDef(Params,
/*CheckParameterNames=*/false);
-
- for (auto P : Method->params())
+
+ for (auto P : Method->parameters())
P->setOwningFunction(Method);
}
@@ -617,6 +617,8 @@ void Sema::deduceClosureReturnType(CapturingScopeInfo &CSI) {
assert(CSI.HasImplicitReturnType);
// If it was ever a placeholder, it had to been deduced to DependentTy.
assert(CSI.ReturnType.isNull() || !CSI.ReturnType->isUndeducedType());
+ assert((!isa<LambdaScopeInfo>(CSI) || !getLangOpts().CPlusPlus14) &&
+ "lambda expressions use auto deduction in C++14 onwards");
// C++ core issue 975:
// If a lambda-expression does not include a trailing-return-type,
@@ -807,19 +809,13 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
bool KnownDependent = false;
LambdaScopeInfo *const LSI = getCurLambda();
assert(LSI && "LambdaScopeInfo should be on stack!");
- TemplateParameterList *TemplateParams =
- getGenericLambdaTemplateParameterList(LSI, *this);
-
- if (Scope *TmplScope = CurScope->getTemplateParamParent()) {
- // Since we have our own TemplateParams, so check if an outer scope
- // has template params, only then are we in a dependent scope.
- if (TemplateParams) {
- TmplScope = TmplScope->getParent();
- TmplScope = TmplScope ? TmplScope->getTemplateParamParent() : nullptr;
- }
- if (TmplScope && !TmplScope->decl_empty())
- KnownDependent = true;
- }
+
+ // The lambda-expression's closure type might be dependent even if its
+ // semantic context isn't, if it appears within a default argument of a
+ // function template.
+ if (CurScope->getTemplateParamParent())
+ KnownDependent = true;
+
// Determine the signature of the call operator.
TypeSourceInfo *MethodTyInfo;
bool ExplicitParams = true;
@@ -882,8 +878,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
CXXRecordDecl *Class = createLambdaClosureType(Intro.Range, MethodTyInfo,
KnownDependent, Intro.Default);
- CXXMethodDecl *Method = startLambdaDefinition(Class, Intro.Range,
- MethodTyInfo, EndLoc, Params);
+ CXXMethodDecl *Method =
+ startLambdaDefinition(Class, Intro.Range, MethodTyInfo, EndLoc, Params,
+ ParamInfo.getDeclSpec().isConstexprSpecified());
if (ExplicitParams)
CheckCXXDefaultArguments(Method);
@@ -922,7 +919,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
= Intro.Default == LCD_None? Intro.Range.getBegin() : Intro.DefaultLoc;
for (auto C = Intro.Captures.begin(), E = Intro.Captures.end(); C != E;
PrevCaptureLoc = C->Loc, ++C) {
- if (C->Kind == LCK_This) {
+ if (C->Kind == LCK_This || C->Kind == LCK_StarThis) {
+ if (C->Kind == LCK_StarThis)
+ Diag(C->Loc, !getLangOpts().CPlusPlus1z
+ ? diag::ext_star_this_lambda_capture_cxx1z
+ : diag::warn_cxx14_compat_star_this_lambda_capture);
+
// C++11 [expr.prim.lambda]p8:
// An identifier or this shall not appear more than once in a
// lambda-capture.
@@ -934,10 +936,12 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- // C++11 [expr.prim.lambda]p8:
- // If a lambda-capture includes a capture-default that is =, the
- // lambda-capture shall not contain this [...].
- if (Intro.Default == LCD_ByCopy) {
+ // C++1z [expr.prim.lambda]p8:
+ // If a lambda-capture includes a capture-default that is =, each
+ // simple-capture of that lambda-capture shall be of the form "&
+ // identifier" or "* this". [ Note: The form [&,this] is redundant but
+ // accepted for compatibility with ISO C++14. --end note ]
+ if (Intro.Default == LCD_ByCopy && C->Kind != LCK_StarThis) {
Diag(C->Loc, diag::err_this_capture_with_copy_default)
<< FixItHint::CreateRemoval(
SourceRange(getLocForEndOfToken(PrevCaptureLoc), C->Loc));
@@ -953,7 +957,9 @@ void Sema::ActOnStartOfLambdaDefinition(LambdaIntroducer &Intro,
continue;
}
- CheckCXXThisCapture(C->Loc, /*Explicit=*/true);
+ CheckCXXThisCapture(C->Loc, /*Explicit=*/true, /*BuildAndDiagnose*/ true,
+ /*FunctionScopeIndexToStopAtPtr*/ nullptr,
+ C->Kind == LCK_StarThis);
continue;
}
@@ -1144,8 +1150,8 @@ static void addFunctionPointerConversion(Sema &S,
CXXMethodDecl *CallOperator) {
// This conversion is explicitly disabled if the lambda's function has
// pass_object_size attributes on any of its parameters.
- if (std::any_of(CallOperator->param_begin(), CallOperator->param_end(),
- std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)))
+ if (llvm::any_of(CallOperator->parameters(),
+ std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>)))
return;
// Add the conversion to function pointer.
@@ -1493,7 +1499,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
SourceRange IntroducerRange;
bool ExplicitParams;
bool ExplicitResultType;
- bool LambdaExprNeedsCleanups;
+ CleanupInfo LambdaCleanup;
bool ContainsUnexpandedParameterPack;
SmallVector<VarDecl *, 4> ArrayIndexVars;
SmallVector<unsigned, 4> ArrayIndexStarts;
@@ -1503,7 +1509,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
IntroducerRange = LSI->IntroducerRange;
ExplicitParams = LSI->ExplicitParams;
ExplicitResultType = !LSI->HasImplicitReturnType;
- LambdaExprNeedsCleanups = LSI->ExprNeedsCleanups;
+ LambdaCleanup = LSI->Cleanup;
ContainsUnexpandedParameterPack = LSI->ContainsUnexpandedParameterPack;
CallOperator->setLexicalDeclContext(Class);
@@ -1527,10 +1533,9 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
// Handle 'this' capture.
if (From.isThisCapture()) {
Captures.push_back(
- LambdaCapture(From.getLocation(), IsImplicit, LCK_This));
- CaptureInits.push_back(new (Context) CXXThisExpr(From.getLocation(),
- getCurrentThisType(),
- /*isImplicit=*/true));
+ LambdaCapture(From.getLocation(), IsImplicit,
+ From.isCopyCapture() ? LCK_StarThis : LCK_This));
+ CaptureInits.push_back(From.getInitExpr());
ArrayIndexStarts.push_back(ArrayIndexVars.size());
continue;
}
@@ -1585,9 +1590,8 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
CheckCompletedCXXClass(Class);
}
- if (LambdaExprNeedsCleanups)
- ExprNeedsCleanups = true;
-
+ Cleanup.mergeFrom(LambdaCleanup);
+
LambdaExpr *Lambda = LambdaExpr::Create(Context, Class, IntroducerRange,
CaptureDefault, CaptureDefaultLoc,
Captures,
@@ -1595,6 +1599,17 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
CaptureInits, ArrayIndexVars,
ArrayIndexStarts, EndLoc,
ContainsUnexpandedParameterPack);
+ // If the lambda expression's call operator is not explicitly marked constexpr
+ // and we are not in a dependent context, analyze the call operator to infer
+ // its constexpr-ness, supressing diagnostics while doing so.
+ if (getLangOpts().CPlusPlus1z && !CallOperator->isInvalidDecl() &&
+ !CallOperator->isConstexpr() &&
+ !Class->getDeclContext()->isDependentContext()) {
+ TentativeAnalysisScope DiagnosticScopeGuard(*this);
+ CallOperator->setConstexpr(
+ CheckConstexprFunctionDecl(CallOperator) &&
+ CheckConstexprFunctionBody(CallOperator, CallOperator->getBody()));
+ }
if (!CurContext->isDependentContext()) {
switch (ExprEvalContexts.back().Context) {
@@ -1619,6 +1634,7 @@ ExprResult Sema::BuildLambdaExpr(SourceLocation StartLoc, SourceLocation EndLoc,
ExprEvalContexts.back().Lambdas.push_back(Lambda);
break;
+ case DiscardedStatement:
case PotentiallyEvaluated:
case PotentiallyEvaluatedIfUsed:
break;
@@ -1697,7 +1713,7 @@ ExprResult Sema::BuildBlockForLambdaConversion(SourceLocation CurrentLocation,
// Create the block literal expression.
Expr *BuildBlock = new (Context) BlockExpr(Block, Conv->getConversionType());
ExprCleanupObjects.push_back(Block);
- ExprNeedsCleanups = true;
+ Cleanup.setExprNeedsCleanups(true);
return BuildBlock;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
index 45dc2e33da93..e2550824fb69 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaLookup.cpp
@@ -29,7 +29,6 @@
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
-#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Overload.h"
#include "clang/Sema/Scope.h"
#include "clang/Sema/ScopeInfo.h"
@@ -280,6 +279,10 @@ static inline unsigned getIDNS(Sema::LookupNameKind NameKind,
IDNS = Decl::IDNS_ObjCProtocol;
break;
+ case Sema::LookupOMPReductionName:
+ IDNS = Decl::IDNS_OMPReduction;
+ break;
+
case Sema::LookupAnyName:
IDNS = Decl::IDNS_Ordinary | Decl::IDNS_Tag | Decl::IDNS_Member
| Decl::IDNS_Using | Decl::IDNS_Namespace | Decl::IDNS_ObjCProtocol
@@ -419,6 +422,18 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
}
}
+ // VarDecl can have incomplete array types, prefer the one with more complete
+ // array type.
+ if (VarDecl *DVD = dyn_cast<VarDecl>(DUnderlying)) {
+ VarDecl *EVD = cast<VarDecl>(EUnderlying);
+ if (EVD->getType()->isIncompleteType() &&
+ !DVD->getType()->isIncompleteType()) {
+ // Prefer the decl with a more complete type if visible.
+ return S.isVisible(DVD);
+ }
+ return false; // Avoid picking up a newer decl, just because it was newer.
+ }
+
// For most kinds of declaration, it doesn't really matter which one we pick.
if (!isa<FunctionDecl>(DUnderlying) && !isa<VarDecl>(DUnderlying)) {
// If the existing declaration is hidden, prefer the new one. Otherwise,
@@ -432,10 +447,6 @@ static bool isPreferredLookupResult(Sema &S, Sema::LookupNameKind Kind,
if (Prev == EUnderlying)
return true;
return false;
-
- // If the existing declaration is hidden, prefer the new one. Otherwise,
- // keep what we've got.
- return !S.isVisible(Existing);
}
/// Determine whether \p D can hide a tag declaration.
@@ -669,24 +680,21 @@ static bool LookupBuiltin(Sema &S, LookupResult &R) {
NameKind == Sema::LookupRedeclarationWithLinkage) {
IdentifierInfo *II = R.getLookupName().getAsIdentifierInfo();
if (II) {
- if (S.getLangOpts().CPlusPlus11 && S.getLangOpts().GNUMode &&
- II == S.getFloat128Identifier()) {
- // libstdc++4.7's type_traits expects type __float128 to exist, so
- // insert a dummy type to make that header build in gnu++11 mode.
- R.addDecl(S.getASTContext().getFloat128StubType());
- return true;
- }
- if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName &&
- II == S.getASTContext().getMakeIntegerSeqName()) {
- R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
- return true;
+ if (S.getLangOpts().CPlusPlus && NameKind == Sema::LookupOrdinaryName) {
+ if (II == S.getASTContext().getMakeIntegerSeqName()) {
+ R.addDecl(S.getASTContext().getMakeIntegerSeqDecl());
+ return true;
+ } else if (II == S.getASTContext().getTypePackElementName()) {
+ R.addDecl(S.getASTContext().getTypePackElementDecl());
+ return true;
+ }
}
// If this is a builtin on this (or all) targets, create the decl.
if (unsigned BuiltinID = II->getBuiltinID()) {
- // In C++, we don't have any predefined library functions like
- // 'malloc'. Instead, we'll just error.
- if (S.getLangOpts().CPlusPlus &&
+ // In C++ and OpenCL (spec v1.2 s6.9.f), we don't have any predefined
+ // library functions like 'malloc'. Instead, we'll just error.
+ if ((S.getLangOpts().CPlusPlus || S.getLangOpts().OpenCL) &&
S.Context.BuiltinInfo.isPredefinedLibFunction(BuiltinID))
return false;
@@ -734,11 +742,11 @@ void Sema::ForceDeclarationOfImplicitMembers(CXXRecordDecl *Class) {
if (getLangOpts().CPlusPlus11) {
// If the move constructor has not yet been declared, do so now.
if (Class->needsImplicitMoveConstructor())
- DeclareImplicitMoveConstructor(Class); // might not actually do it
+ DeclareImplicitMoveConstructor(Class);
// If the move assignment operator has not yet been declared, do so now.
if (Class->needsImplicitMoveAssignment())
- DeclareImplicitMoveAssignment(Class); // might not actually do it
+ DeclareImplicitMoveAssignment(Class);
}
// If the destructor has not yet been declared, do so now.
@@ -1074,32 +1082,35 @@ bool Sema::CppLookupName(LookupResult &R, Scope *S) {
for (; S && !isNamespaceOrTranslationUnitScope(S); S = S->getParent()) {
DeclContext *Ctx = S->getEntity();
-
+ bool SearchNamespaceScope = true;
// Check whether the IdResolver has anything in this scope.
- bool Found = false;
for (; I != IEnd && S->isDeclScope(*I); ++I) {
if (NamedDecl *ND = R.getAcceptableDecl(*I)) {
- if (NameKind == LookupRedeclarationWithLinkage) {
+ if (NameKind == LookupRedeclarationWithLinkage &&
+ !(*I)->isTemplateParameter()) {
+ // If it's a template parameter, we still find it, so we can diagnose
+ // the invalid redeclaration.
+
// Determine whether this (or a previous) declaration is
// out-of-scope.
if (!LeftStartingScope && !Initial->isDeclScope(*I))
LeftStartingScope = true;
// If we found something outside of our starting scope that
- // does not have linkage, skip it. If it's a template parameter,
- // we still find it, so we can diagnose the invalid redeclaration.
- if (LeftStartingScope && !((*I)->hasLinkage()) &&
- !(*I)->isTemplateParameter()) {
+ // does not have linkage, skip it.
+ if (LeftStartingScope && !((*I)->hasLinkage())) {
R.setShadowed();
continue;
}
+ } else {
+ // We found something in this scope, we should not look at the
+ // namespace scope
+ SearchNamespaceScope = false;
}
-
- Found = true;
R.addDecl(ND);
}
}
- if (Found) {
+ if (!SearchNamespaceScope) {
R.resolveKind();
if (S->isClassScope())
if (CXXRecordDecl *Record = dyn_cast_or_null<CXXRecordDecl>(Ctx))
@@ -1470,6 +1481,35 @@ bool Sema::hasVisibleDefaultArgument(const NamedDecl *D,
Modules);
}
+bool Sema::hasVisibleMemberSpecialization(
+ const NamedDecl *D, llvm::SmallVectorImpl<Module *> *Modules) {
+ assert(isa<CXXRecordDecl>(D->getDeclContext()) &&
+ "not a member specialization");
+ for (auto *Redecl : D->redecls()) {
+ // If the specialization is declared at namespace scope, then it's a member
+ // specialization declaration. If it's lexically inside the class
+ // definition then it was instantiated.
+ //
+ // FIXME: This is a hack. There should be a better way to determine this.
+ // FIXME: What about MS-style explicit specializations declared within a
+ // class definition?
+ if (Redecl->getLexicalDeclContext()->isFileContext()) {
+ auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
+
+ if (isVisible(NonConstR))
+ return true;
+
+ if (Modules) {
+ Modules->push_back(getOwningModule(NonConstR));
+ const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
+ Modules->insert(Modules->end(), Merged.begin(), Merged.end());
+ }
+ }
+ }
+
+ return false;
+}
+
/// \brief Determine whether a declaration is visible to name lookup.
///
/// This routine determines whether the declaration D is visible in the current
@@ -1570,19 +1610,58 @@ static NamedDecl *findAcceptableDecl(Sema &SemaRef, NamedDecl *D) {
assert(!LookupResult::isVisible(SemaRef, D) && "not in slow case");
for (auto RD : D->redecls()) {
- if (auto ND = dyn_cast<NamedDecl>(RD)) {
- // FIXME: This is wrong in the case where the previous declaration is not
- // visible in the same scope as D. This needs to be done much more
- // carefully.
- if (LookupResult::isVisible(SemaRef, ND))
- return ND;
- }
+ // Don't bother with extra checks if we already know this one isn't visible.
+ if (RD == D)
+ continue;
+
+ auto ND = cast<NamedDecl>(RD);
+ // FIXME: This is wrong in the case where the previous declaration is not
+ // visible in the same scope as D. This needs to be done much more
+ // carefully.
+ if (LookupResult::isVisible(SemaRef, ND))
+ return ND;
}
return nullptr;
}
+bool Sema::hasVisibleDeclarationSlow(const NamedDecl *D,
+ llvm::SmallVectorImpl<Module *> *Modules) {
+ assert(!isVisible(D) && "not in slow case");
+
+ for (auto *Redecl : D->redecls()) {
+ auto *NonConstR = const_cast<NamedDecl*>(cast<NamedDecl>(Redecl));
+ if (isVisible(NonConstR))
+ return true;
+
+ if (Modules) {
+ Modules->push_back(getOwningModule(NonConstR));
+ const auto &Merged = Context.getModulesWithMergedDefinition(NonConstR);
+ Modules->insert(Modules->end(), Merged.begin(), Merged.end());
+ }
+ }
+
+ return false;
+}
+
NamedDecl *LookupResult::getAcceptableDeclSlow(NamedDecl *D) const {
+ if (auto *ND = dyn_cast<NamespaceDecl>(D)) {
+ // Namespaces are a bit of a special case: we expect there to be a lot of
+ // redeclarations of some namespaces, all declarations of a namespace are
+ // essentially interchangeable, all declarations are found by name lookup
+ // if any is, and namespaces are never looked up during template
+ // instantiation. So we benefit from caching the check in this case, and
+ // it is correct to do so.
+ auto *Key = ND->getCanonicalDecl();
+ if (auto *Acceptable = getSema().VisibleNamespaceCache.lookup(Key))
+ return Acceptable;
+ auto *Acceptable =
+ isVisible(getSema(), Key) ? Key : findAcceptableDecl(getSema(), Key);
+ if (Acceptable)
+ getSema().VisibleNamespaceCache.insert(std::make_pair(Key, Acceptable));
+ return Acceptable;
+ }
+
return findAcceptableDecl(getSema(), D);
}
@@ -1986,6 +2065,10 @@ bool Sema::LookupQualifiedName(LookupResult &R, DeclContext *LookupCtx,
BaseCallback = &LookupAnyMember;
break;
+ case LookupOMPReductionName:
+ BaseCallback = &CXXRecordDecl::FindOMPReductionMember;
+ break;
+
case LookupUsingDeclName:
// This lookup is for redeclarations only.
@@ -2409,7 +2492,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
// FIXME: That's not correct, we may have added this class only because it
// was the enclosing class of another class, and in that case we won't have
// added its base classes yet.
- if (!Result.Classes.insert(Class).second)
+ if (!Result.Classes.insert(Class))
return;
// -- If T is a template-id, its associated namespaces and classes are
@@ -2459,7 +2542,7 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result,
if (!BaseType)
continue;
CXXRecordDecl *BaseDecl = cast<CXXRecordDecl>(BaseType->getDecl());
- if (Result.Classes.insert(BaseDecl).second) {
+ if (Result.Classes.insert(BaseDecl)) {
// Find the associated namespace for this base class.
DeclContext *BaseCtx = BaseDecl->getDeclContext();
CollectEnclosingNamespace(Result.Namespaces, BaseCtx);
@@ -2864,42 +2947,38 @@ Sema::SpecialMemberOverloadResult *Sema::LookupSpecialMember(CXXRecordDecl *RD,
// from an external source and invalidate lookup_result.
SmallVector<NamedDecl *, 8> Candidates(R.begin(), R.end());
- for (auto *Cand : Candidates) {
- if (Cand->isInvalidDecl())
+ for (NamedDecl *CandDecl : Candidates) {
+ if (CandDecl->isInvalidDecl())
continue;
- if (UsingShadowDecl *U = dyn_cast<UsingShadowDecl>(Cand)) {
- // FIXME: [namespace.udecl]p15 says that we should only consider a
- // using declaration here if it does not match a declaration in the
- // derived class. We do not implement this correctly in other cases
- // either.
- Cand = U->getTargetDecl();
-
- if (Cand->isInvalidDecl())
- continue;
- }
-
- if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand)) {
+ DeclAccessPair Cand = DeclAccessPair::make(CandDecl, AS_public);
+ auto CtorInfo = getConstructorInfo(Cand);
+ if (CXXMethodDecl *M = dyn_cast<CXXMethodDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodCandidate(M, DeclAccessPair::make(M, AS_public), RD, ThisTy,
- Classification, llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
- else
- AddOverloadCandidate(M, DeclAccessPair::make(M, AS_public),
+ AddMethodCandidate(M, Cand, RD, ThisTy, Classification,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else if (CtorInfo)
+ AddOverloadCandidate(CtorInfo.Constructor, CtorInfo.FoundDecl,
llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else
+ AddOverloadCandidate(M, Cand, llvm::makeArrayRef(&Arg, NumArgs), OCS,
+ true);
} else if (FunctionTemplateDecl *Tmpl =
- dyn_cast<FunctionTemplateDecl>(Cand)) {
+ dyn_cast<FunctionTemplateDecl>(Cand->getUnderlyingDecl())) {
if (SM == CXXCopyAssignment || SM == CXXMoveAssignment)
- AddMethodTemplateCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- RD, nullptr, ThisTy, Classification,
- llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
+ AddMethodTemplateCandidate(
+ Tmpl, Cand, RD, nullptr, ThisTy, Classification,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
+ else if (CtorInfo)
+ AddTemplateOverloadCandidate(
+ CtorInfo.ConstructorTmpl, CtorInfo.FoundDecl, nullptr,
+ llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
else
- AddTemplateOverloadCandidate(Tmpl, DeclAccessPair::make(Tmpl, AS_public),
- nullptr, llvm::makeArrayRef(&Arg, NumArgs),
- OCS, true);
+ AddTemplateOverloadCandidate(
+ Tmpl, Cand, nullptr, llvm::makeArrayRef(&Arg, NumArgs), OCS, true);
} else {
- assert(isa<UsingDecl>(Cand) && "illegal Kind of operator = Decl");
+ assert(isa<UsingDecl>(Cand.getDecl()) &&
+ "illegal Kind of operator = Decl");
}
}
@@ -3119,7 +3198,7 @@ Sema::LookupLiteralOperator(Scope *S, LookupResult &R,
if (FoundRaw && FoundTemplate) {
Diag(R.getNameLoc(), diag::err_ovl_ambiguous_call) << R.getLookupName();
for (LookupResult::iterator I = R.begin(), E = R.end(); I != E; ++I)
- NoteOverloadCandidate((*I)->getUnderlyingDecl()->getAsFunction());
+ NoteOverloadCandidate(*I, (*I)->getUnderlyingDecl()->getAsFunction());
return LOLR_Error;
}
@@ -3984,8 +4063,8 @@ retry_lookup:
void TypoCorrectionConsumer::performQualifiedLookups() {
unsigned TypoLen = Typo->getName().size();
- for (auto QR : QualifiedResults) {
- for (auto NSI : Namespaces) {
+ for (const TypoCorrection &QR : QualifiedResults) {
+ for (const auto &NSI : Namespaces) {
DeclContext *Ctx = NSI.DeclCtx;
const Type *NSType = NSI.NameSpecifier->getAsType();
@@ -4073,10 +4152,8 @@ TypoCorrectionConsumer::NamespaceSpecifierSet::NamespaceSpecifierSet(
// Build the list of identifiers that would be used for an absolute
// (from the global context) NestedNameSpecifier referring to the current
// context.
- for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
- CEnd = CurContextChain.rend();
- C != CEnd; ++C) {
- if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C))
+ for (DeclContext *C : llvm::reverse(CurContextChain)) {
+ if (auto *ND = dyn_cast_or_null<NamespaceDecl>(C))
CurContextIdentifiers.push_back(ND->getIdentifier());
}
@@ -4104,13 +4181,11 @@ unsigned
TypoCorrectionConsumer::NamespaceSpecifierSet::buildNestedNameSpecifier(
DeclContextList &DeclChain, NestedNameSpecifier *&NNS) {
unsigned NumSpecifiers = 0;
- for (DeclContextList::reverse_iterator C = DeclChain.rbegin(),
- CEnd = DeclChain.rend();
- C != CEnd; ++C) {
- if (NamespaceDecl *ND = dyn_cast_or_null<NamespaceDecl>(*C)) {
+ for (DeclContext *C : llvm::reverse(DeclChain)) {
+ if (auto *ND = dyn_cast_or_null<NamespaceDecl>(C)) {
NNS = NestedNameSpecifier::Create(Context, NNS, ND);
++NumSpecifiers;
- } else if (RecordDecl *RD = dyn_cast_or_null<RecordDecl>(*C)) {
+ } else if (auto *RD = dyn_cast_or_null<RecordDecl>(C)) {
NNS = NestedNameSpecifier::Create(Context, NNS, RD->isTemplateDecl(),
RD->getTypeForDecl());
++NumSpecifiers;
@@ -4127,10 +4202,9 @@ void TypoCorrectionConsumer::NamespaceSpecifierSet::addNameSpecifier(
DeclContextList FullNamespaceDeclChain(NamespaceDeclChain);
// Eliminate common elements from the two DeclContext chains.
- for (DeclContextList::reverse_iterator C = CurContextChain.rbegin(),
- CEnd = CurContextChain.rend();
- C != CEnd && !NamespaceDeclChain.empty() &&
- NamespaceDeclChain.back() == *C; ++C) {
+ for (DeclContext *C : llvm::reverse(CurContextChain)) {
+ if (NamespaceDeclChain.empty() || NamespaceDeclChain.back() != C)
+ break;
NamespaceDeclChain.pop_back();
}
@@ -4207,7 +4281,8 @@ static void LookupPotentialTypoResult(Sema &SemaRef,
}
}
- if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(Name)) {
+ if (ObjCPropertyDecl *Prop = Class->FindPropertyDeclaration(
+ Name, ObjCPropertyQueryKind::OBJC_PR_query_instance)) {
Res.addDecl(Prop);
Res.resolveKind();
return;
@@ -4704,11 +4779,20 @@ TypoExpr *Sema::CorrectTypoDelayed(
const ObjCObjectPointerType *OPT) {
assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback");
- TypoCorrection Empty;
auto Consumer = makeTypoCorrectionConsumer(
TypoName, LookupKind, S, SS, std::move(CCC), MemberContext,
EnteringContext, OPT, Mode == CTK_ErrorRecovery);
+ // Give the external sema source a chance to correct the typo.
+ TypoCorrection ExternalTypo;
+ if (ExternalSource && Consumer) {
+ ExternalTypo = ExternalSource->CorrectTypo(
+ TypoName, LookupKind, S, SS, *Consumer->getCorrectionValidator(),
+ MemberContext, EnteringContext, OPT);
+ if (ExternalTypo)
+ Consumer->addCorrection(ExternalTypo);
+ }
+
if (!Consumer || Consumer->empty())
return nullptr;
@@ -4716,7 +4800,7 @@ TypoExpr *Sema::CorrectTypoDelayed(
// is not more that about a third of the length of the typo's identifier.
unsigned ED = Consumer->getBestEditDistance(true);
IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo();
- if (ED > 0 && Typo->getName().size() / ED < 3)
+ if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3)
return nullptr;
ExprEvalContexts.back().NumTypos++;
@@ -4852,8 +4936,8 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
static NamedDecl *getDefinitionToImport(NamedDecl *D) {
if (VarDecl *VD = dyn_cast<VarDecl>(D))
return VD->getDefinition();
- if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
- return FD->isDefined(FD) ? const_cast<FunctionDecl*>(FD) : nullptr;
+ if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D))
+ return FD->getDefinition();
if (TagDecl *TD = dyn_cast<TagDecl>(D))
return TD->getDefinition();
if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(D))
@@ -4866,7 +4950,7 @@ static NamedDecl *getDefinitionToImport(NamedDecl *D) {
}
void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
- bool NeedDefinition, bool Recover) {
+ MissingImportKind MIK, bool Recover) {
assert(!isVisible(Decl) && "missing import for non-hidden decl?");
// Suggest importing a module providing the definition of this entity, if
@@ -4875,8 +4959,6 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
if (!Def)
Def = Decl;
- // FIXME: Add a Fix-It that imports the corresponding module or includes
- // the header.
Module *Owner = getOwningModule(Decl);
assert(Owner && "definition of hidden declaration is not in a module");
@@ -4885,12 +4967,20 @@ void Sema::diagnoseMissingImport(SourceLocation Loc, NamedDecl *Decl,
auto Merged = Context.getModulesWithMergedDefinition(Decl);
OwningModules.insert(OwningModules.end(), Merged.begin(), Merged.end());
- diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules,
- NeedDefinition ? MissingImportKind::Definition
- : MissingImportKind::Declaration,
+ diagnoseMissingImport(Loc, Decl, Decl->getLocation(), OwningModules, MIK,
Recover);
}
+/// \brief Get a "quoted.h" or <angled.h> include path to use in a diagnostic
+/// suggesting the addition of a #include of the specified file.
+static std::string getIncludeStringForHeader(Preprocessor &PP,
+ const FileEntry *E) {
+ bool IsSystem;
+ auto Path =
+ PP.getHeaderSearchInfo().suggestPathToFileForDiagnostics(E, &IsSystem);
+ return (IsSystem ? '<' : '"') + Path + (IsSystem ? '>' : '"');
+}
+
void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
SourceLocation DeclLoc,
ArrayRef<Module *> Modules,
@@ -4911,7 +5001,18 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
Diag(UseLoc, diag::err_module_unimported_use_multiple)
<< (int)MIK << Decl << ModuleList;
+ } else if (const FileEntry *E =
+ PP.getModuleHeaderToIncludeForDiagnostics(UseLoc, DeclLoc)) {
+ // The right way to make the declaration visible is to include a header;
+ // suggest doing so.
+ //
+ // FIXME: Find a smart place to suggest inserting a #include, and add
+ // a FixItHint there.
+ Diag(UseLoc, diag::err_module_unimported_use_header)
+ << (int)MIK << Decl << Modules[0]->getFullModuleName()
+ << getIncludeStringForHeader(PP, E);
} else {
+ // FIXME: Add a FixItHint that imports the corresponding module.
Diag(UseLoc, diag::err_module_unimported_use)
<< (int)MIK << Decl << Modules[0]->getFullModuleName();
}
@@ -4927,6 +5028,12 @@ void Sema::diagnoseMissingImport(SourceLocation UseLoc, NamedDecl *Decl,
case MissingImportKind::DefaultArgument:
DiagID = diag::note_default_argument_declared_here;
break;
+ case MissingImportKind::ExplicitSpecialization:
+ DiagID = diag::note_explicit_specialization_declared_here;
+ break;
+ case MissingImportKind::PartialSpecialization:
+ DiagID = diag::note_partial_specialization_declared_here;
+ break;
}
Diag(DeclLoc, DiagID);
@@ -4962,7 +5069,7 @@ void Sema::diagnoseTypo(const TypoCorrection &Correction,
assert(Decl && "import required but no declaration to import");
diagnoseMissingImport(Correction.getCorrectionRange().getBegin(), Decl,
- /*NeedDefinition*/ false, ErrorRecovery);
+ MissingImportKind::Declaration, ErrorRecovery);
return;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
index 1cb84e448067..5e38751f44a5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaObjCProperty.cpp
@@ -303,6 +303,8 @@ makePropertyAttributesAsWritten(unsigned Attributes) {
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_nonatomic;
if (Attributes & ObjCDeclSpec::DQ_PR_atomic)
attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_atomic;
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ attributesAsWritten |= ObjCPropertyDecl::OBJC_PR_class;
return (ObjCPropertyDecl::PropertyAttributeKind)attributesAsWritten;
}
@@ -334,7 +336,6 @@ static bool LocPropertyAttribute( ASTContext &Context, const char *attrName,
}
} while (Tok.isNot(tok::r_paren));
return false;
-
}
/// Check for a mismatch in the atomicity of the given properties.
@@ -431,10 +432,13 @@ Sema::HandlePropertyInClassExtension(Scope *S,
return nullptr;
}
+ bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
+ (Attributes & ObjCDeclSpec::DQ_PR_class);
+
// Find the property in the extended class's primary class or
// extensions.
- ObjCPropertyDecl *PIDecl =
- CCPrimary->FindPropertyVisibleInPrimaryClass(PropertyId);
+ ObjCPropertyDecl *PIDecl = CCPrimary->FindPropertyVisibleInPrimaryClass(
+ PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty));
// If we found a property in an extension, complain.
if (PIDecl && isa<ObjCCategoryDecl>(PIDecl->getDeclContext())) {
@@ -612,8 +616,11 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
PropertyId, AtLoc,
LParenLoc, T, TInfo);
- if (ObjCPropertyDecl *prevDecl =
- ObjCPropertyDecl::findPropertyDecl(DC, PropertyId)) {
+ bool isClassProperty = (AttributesAsWritten & ObjCDeclSpec::DQ_PR_class) ||
+ (Attributes & ObjCDeclSpec::DQ_PR_class);
+ // Class property and instance property can have the same name.
+ if (ObjCPropertyDecl *prevDecl = ObjCPropertyDecl::findPropertyDecl(
+ DC, PropertyId, ObjCPropertyDecl::getQueryKind(isClassProperty))) {
Diag(PDecl->getLocation(), diag::err_duplicate_property);
Diag(prevDecl->getLocation(), diag::note_property_declare);
PDecl->setInvalidDecl();
@@ -691,6 +698,9 @@ ObjCPropertyDecl *Sema::CreatePropertyDecl(Scope *S,
if (Attributes & ObjCDeclSpec::DQ_PR_null_resettable)
PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_null_resettable);
+ if (Attributes & ObjCDeclSpec::DQ_PR_class)
+ PDecl->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_class);
+
return PDecl;
}
@@ -794,7 +804,6 @@ static void setImpliedPropertyAttributeForReadOnlyProperty(
property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_strong);
else if (ivarLifetime == Qualifiers::OCL_Weak)
property->setPropertyAttributes(ObjCPropertyDecl::OBJC_PR_weak);
- return;
}
/// DiagnosePropertyMismatchDeclInProtocols - diagnose properties declared
@@ -847,7 +856,8 @@ DiagnosePropertyMismatchDeclInProtocols(Sema &S, SourceLocation AtLoc,
}
/// Determine whether any storage attributes were written on the property.
-static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop) {
+static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop,
+ ObjCPropertyQueryKind QueryKind) {
if (Prop->getPropertyAttributesAsWritten() & OwnershipMask) return true;
// If this is a readwrite property in a class extension that refines
@@ -870,8 +880,8 @@ static bool hasWrittenStorageAttribute(ObjCPropertyDecl *Prop) {
// Look through all of the protocols.
for (const auto *Proto : OrigClass->all_referenced_protocols()) {
- if (ObjCPropertyDecl *OrigProp =
- Proto->FindPropertyDeclaration(Prop->getIdentifier()))
+ if (ObjCPropertyDecl *OrigProp = Proto->FindPropertyDeclaration(
+ Prop->getIdentifier(), QueryKind))
return OrigProp->getPropertyAttributesAsWritten() & OwnershipMask;
}
@@ -888,7 +898,8 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
bool Synthesize,
IdentifierInfo *PropertyId,
IdentifierInfo *PropertyIvar,
- SourceLocation PropertyIvarLoc) {
+ SourceLocation PropertyIvarLoc,
+ ObjCPropertyQueryKind QueryKind) {
ObjCContainerDecl *ClassImpDecl =
dyn_cast<ObjCContainerDecl>(CurContext);
// Make sure we have a context for the property implementation declaration.
@@ -915,11 +926,15 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
"ActOnPropertyImplDecl - @implementation without @interface");
// Look for this property declaration in the @implementation's @interface
- property = IDecl->FindPropertyDeclaration(PropertyId);
+ property = IDecl->FindPropertyDeclaration(PropertyId, QueryKind);
if (!property) {
Diag(PropertyLoc, diag::error_bad_property_decl) << IDecl->getDeclName();
return nullptr;
}
+ if (property->isClassProperty() && Synthesize) {
+ Diag(PropertyLoc, diag::error_synthesize_on_class_property) << PropertyId;
+ return nullptr;
+ }
unsigned PIkind = property->getPropertyAttributesAsWritten();
if ((PIkind & (ObjCPropertyDecl::OBJC_PR_atomic |
ObjCPropertyDecl::OBJC_PR_nonatomic) ) == 0) {
@@ -993,7 +1008,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
if (!Category)
return nullptr;
// Look for this property declaration in @implementation's category
- property = Category->FindPropertyDeclaration(PropertyId);
+ property = Category->FindPropertyDeclaration(PropertyId, QueryKind);
if (!property) {
Diag(PropertyLoc, diag::error_bad_category_property_decl)
<< Category->getDeclName();
@@ -1105,7 +1120,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
// It's an error if we have to do this and the user didn't
// explicitly write an ownership attribute on the property.
- if (!hasWrittenStorageAttribute(property) &&
+ if (!hasWrittenStorageAttribute(property, QueryKind) &&
!(kind & ObjCPropertyDecl::OBJC_PR_strong)) {
Diag(PropertyDiagLoc,
diag::err_arc_objc_property_default_assign_on_object);
@@ -1340,7 +1355,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (ObjCPropertyImplDecl *PPIDecl
- = IC->FindPropertyImplDecl(PropertyId)) {
+ = IC->FindPropertyImplDecl(PropertyId, QueryKind)) {
Diag(PropertyLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return nullptr;
@@ -1379,7 +1394,7 @@ Decl *Sema::ActOnPropertyImplDecl(Scope *S,
}
if (ObjCPropertyImplDecl *PPIDecl =
- CatImplClass->FindPropertyImplDecl(PropertyId)) {
+ CatImplClass->FindPropertyImplDecl(PropertyId, QueryKind)) {
Diag(PropertyDiagLoc, diag::error_property_implemented) << PropertyId;
Diag(PPIDecl->getLocation(), diag::note_previous_declaration);
return nullptr;
@@ -1478,24 +1493,26 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
if (!GetterMethod)
return false;
QualType GetterType = GetterMethod->getReturnType().getNonReferenceType();
- QualType PropertyIvarType = property->getType().getNonReferenceType();
- bool compat = Context.hasSameType(PropertyIvarType, GetterType);
+ QualType PropertyRValueType =
+ property->getType().getNonReferenceType().getAtomicUnqualifiedType();
+ bool compat = Context.hasSameType(PropertyRValueType, GetterType);
if (!compat) {
const ObjCObjectPointerType *propertyObjCPtr = nullptr;
const ObjCObjectPointerType *getterObjCPtr = nullptr;
- if ((propertyObjCPtr = PropertyIvarType->getAs<ObjCObjectPointerType>()) &&
+ if ((propertyObjCPtr =
+ PropertyRValueType->getAs<ObjCObjectPointerType>()) &&
(getterObjCPtr = GetterType->getAs<ObjCObjectPointerType>()))
compat = Context.canAssignObjCInterfaces(getterObjCPtr, propertyObjCPtr);
- else if (CheckAssignmentConstraints(Loc, GetterType, PropertyIvarType)
+ else if (CheckAssignmentConstraints(Loc, GetterType, PropertyRValueType)
!= Compatible) {
Diag(Loc, diag::error_property_accessor_type)
- << property->getDeclName() << PropertyIvarType
+ << property->getDeclName() << PropertyRValueType
<< GetterMethod->getSelector() << GetterType;
Diag(GetterMethod->getLocation(), diag::note_declared_at);
return true;
} else {
compat = true;
- QualType lhsType =Context.getCanonicalType(PropertyIvarType).getUnqualifiedType();
+ QualType lhsType = Context.getCanonicalType(PropertyRValueType);
QualType rhsType =Context.getCanonicalType(GetterType).getUnqualifiedType();
if (lhsType != rhsType && lhsType->isArithmeticType())
compat = false;
@@ -1515,49 +1532,68 @@ bool Sema::DiagnosePropertyAccessorMismatch(ObjCPropertyDecl *property,
/// CollectImmediateProperties - This routine collects all properties in
/// the class and its conforming protocols; but not those in its super class.
-static void CollectImmediateProperties(ObjCContainerDecl *CDecl,
- ObjCContainerDecl::PropertyMap &PropMap,
- ObjCContainerDecl::PropertyMap &SuperPropMap,
- bool IncludeProtocols = true) {
-
+static void
+CollectImmediateProperties(ObjCContainerDecl *CDecl,
+ ObjCContainerDecl::PropertyMap &PropMap,
+ ObjCContainerDecl::PropertyMap &SuperPropMap,
+ bool CollectClassPropsOnly = false,
+ bool IncludeProtocols = true) {
if (ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl)) {
- for (auto *Prop : IDecl->properties())
- PropMap[Prop->getIdentifier()] = Prop;
+ for (auto *Prop : IDecl->properties()) {
+ if (CollectClassPropsOnly && !Prop->isClassProperty())
+ continue;
+ PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
+ Prop;
+ }
// Collect the properties from visible extensions.
for (auto *Ext : IDecl->visible_extensions())
- CollectImmediateProperties(Ext, PropMap, SuperPropMap, IncludeProtocols);
+ CollectImmediateProperties(Ext, PropMap, SuperPropMap,
+ CollectClassPropsOnly, IncludeProtocols);
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : IDecl->all_referenced_protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap);
+ CollectImmediateProperties(PI, PropMap, SuperPropMap,
+ CollectClassPropsOnly);
}
}
if (ObjCCategoryDecl *CATDecl = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- for (auto *Prop : CATDecl->properties())
- PropMap[Prop->getIdentifier()] = Prop;
+ for (auto *Prop : CATDecl->properties()) {
+ if (CollectClassPropsOnly && !Prop->isClassProperty())
+ continue;
+ PropMap[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] =
+ Prop;
+ }
if (IncludeProtocols) {
// Scan through class's protocols.
for (auto *PI : CATDecl->protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap);
+ CollectImmediateProperties(PI, PropMap, SuperPropMap,
+ CollectClassPropsOnly);
}
}
else if (ObjCProtocolDecl *PDecl = dyn_cast<ObjCProtocolDecl>(CDecl)) {
for (auto *Prop : PDecl->properties()) {
- ObjCPropertyDecl *PropertyFromSuper = SuperPropMap[Prop->getIdentifier()];
+ if (CollectClassPropsOnly && !Prop->isClassProperty())
+ continue;
+ ObjCPropertyDecl *PropertyFromSuper =
+ SuperPropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
// Exclude property for protocols which conform to class's super-class,
// as super-class has to implement the property.
if (!PropertyFromSuper ||
PropertyFromSuper->getIdentifier() != Prop->getIdentifier()) {
- ObjCPropertyDecl *&PropEntry = PropMap[Prop->getIdentifier()];
+ ObjCPropertyDecl *&PropEntry =
+ PropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
if (!PropEntry)
PropEntry = Prop;
}
}
- // scan through protocol's protocols.
+ // Scan through protocol's protocols.
for (auto *PI : PDecl->protocols())
- CollectImmediateProperties(PI, PropMap, SuperPropMap);
+ CollectImmediateProperties(PI, PropMap, SuperPropMap,
+ CollectClassPropsOnly);
}
}
@@ -1590,7 +1626,7 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
// look up a property declaration whose one of its accessors is implemented
// by this method.
- for (const auto *Property : IFace->properties()) {
+ for (const auto *Property : IFace->instance_properties()) {
if ((Property->getGetterName() == IMD->getSelector() ||
Property->getSetterName() == IMD->getSelector()) &&
(Property->getPropertyIvarDecl() == IV))
@@ -1599,7 +1635,7 @@ Sema::IvarBacksCurrentMethodAccessor(ObjCInterfaceDecl *IFace,
// Also look up property declaration in class extension whose one of its
// accessors is implemented by this method.
for (const auto *Ext : IFace->known_extensions())
- for (const auto *Property : Ext->properties())
+ for (const auto *Property : Ext->instance_properties())
if ((Property->getGetterName() == IMD->getSelector() ||
Property->getSetterName() == IMD->getSelector()) &&
(Property->getPropertyIvarDecl() == IV))
@@ -1632,7 +1668,6 @@ static bool SuperClassImplementsProperty(ObjCInterfaceDecl *IDecl,
/// in class's \@implementation.
void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCInterfaceDecl *IDecl) {
-
ObjCInterfaceDecl::PropertyMap PropMap;
ObjCInterfaceDecl::PropertyDeclOrder PropertyOrder;
IDecl->collectPropertiesToImplement(PropMap, PropertyOrder);
@@ -1645,10 +1680,12 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCPropertyDecl *Prop = PropertyOrder[i];
// Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
+ Prop->isClassProperty() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional)
continue;
// Property may have been synthesized by user.
- if (IMPDecl->FindPropertyImplDecl(Prop->getIdentifier()))
+ if (IMPDecl->FindPropertyImplDecl(
+ Prop->getIdentifier(), Prop->getQueryKind()))
continue;
if (IMPDecl->getInstanceMethod(Prop->getGetterName())) {
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_readonly)
@@ -1664,7 +1701,9 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
Diag(PID->getLocation(), diag::note_property_synthesize);
continue;
}
- ObjCPropertyDecl *PropInSuperClass = SuperPropMap[Prop->getIdentifier()];
+ ObjCPropertyDecl *PropInSuperClass =
+ SuperPropMap[std::make_pair(Prop->getIdentifier(),
+ Prop->isClassProperty())];
if (ObjCProtocolDecl *Proto =
dyn_cast<ObjCProtocolDecl>(Prop->getDeclContext())) {
// We won't auto-synthesize properties declared in protocols.
@@ -1707,7 +1746,7 @@ void Sema::DefaultSynthesizeProperties(Scope *S, ObjCImplDecl* IMPDecl,
true,
/* property = */ Prop->getIdentifier(),
/* ivar = */ Prop->getDefaultSynthIvarName(Context),
- Prop->getLocation()));
+ Prop->getLocation(), Prop->getQueryKind()));
if (PIDecl) {
Diag(Prop->getLocation(), diag::warn_missing_explicit_synthesis);
Diag(IMPDecl->getLocation(), diag::note_while_in_implementation);
@@ -1726,34 +1765,42 @@ void Sema::DefaultSynthesizeProperties(Scope *S, Decl *D) {
DefaultSynthesizeProperties(S, IC, IDecl);
}
-static void DiagnoseUnimplementedAccessor(Sema &S,
- ObjCInterfaceDecl *PrimaryClass,
- Selector Method,
- ObjCImplDecl* IMPDecl,
- ObjCContainerDecl *CDecl,
- ObjCCategoryDecl *C,
- ObjCPropertyDecl *Prop,
- Sema::SelectorSet &SMap) {
+static void DiagnoseUnimplementedAccessor(
+ Sema &S, ObjCInterfaceDecl *PrimaryClass, Selector Method,
+ ObjCImplDecl *IMPDecl, ObjCContainerDecl *CDecl, ObjCCategoryDecl *C,
+ ObjCPropertyDecl *Prop,
+ llvm::SmallPtrSet<const ObjCMethodDecl *, 8> &SMap) {
+ // Check to see if we have a corresponding selector in SMap and with the
+ // right method type.
+ auto I = std::find_if(SMap.begin(), SMap.end(),
+ [&](const ObjCMethodDecl *x) {
+ return x->getSelector() == Method &&
+ x->isClassMethod() == Prop->isClassProperty();
+ });
// When reporting on missing property setter/getter implementation in
// categories, do not report when they are declared in primary class,
// class's protocol, or one of it super classes. This is because,
// the class is going to implement them.
- if (!SMap.count(Method) &&
+ if (I == SMap.end() &&
(PrimaryClass == nullptr ||
- !PrimaryClass->lookupPropertyAccessor(Method, C))) {
- S.Diag(IMPDecl->getLocation(),
- isa<ObjCCategoryDecl>(CDecl) ?
- diag::warn_setter_getter_impl_required_in_category :
- diag::warn_setter_getter_impl_required)
- << Prop->getDeclName() << Method;
- S.Diag(Prop->getLocation(),
- diag::note_property_declare);
- if (S.LangOpts.ObjCDefaultSynthProperties &&
- S.LangOpts.ObjCRuntime.isNonFragile())
- if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
- if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
- S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
- }
+ !PrimaryClass->lookupPropertyAccessor(Method, C,
+ Prop->isClassProperty()))) {
+ unsigned diag =
+ isa<ObjCCategoryDecl>(CDecl)
+ ? (Prop->isClassProperty()
+ ? diag::warn_impl_required_in_category_for_class_property
+ : diag::warn_setter_getter_impl_required_in_category)
+ : (Prop->isClassProperty()
+ ? diag::warn_impl_required_for_class_property
+ : diag::warn_setter_getter_impl_required);
+ S.Diag(IMPDecl->getLocation(), diag) << Prop->getDeclName() << Method;
+ S.Diag(Prop->getLocation(), diag::note_property_declare);
+ if (S.LangOpts.ObjCDefaultSynthProperties &&
+ S.LangOpts.ObjCRuntime.isNonFragile())
+ if (ObjCInterfaceDecl *ID = dyn_cast<ObjCInterfaceDecl>(CDecl))
+ if (const ObjCInterfaceDecl *RID = ID->isObjCRequiresPropertyDefs())
+ S.Diag(RID->getLocation(), diag::note_suppressed_class_declare);
+ }
}
void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
@@ -1762,25 +1809,27 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl::PropertyMap PropMap;
ObjCInterfaceDecl *IDecl = dyn_cast<ObjCInterfaceDecl>(CDecl);
- if (!SynthesizeProperties) {
- ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
- // Gather properties which need not be implemented in this class
- // or category.
- if (!IDecl)
- if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
- // For categories, no need to implement properties declared in
- // its primary class (and its super classes) if property is
- // declared in one of those containers.
- if ((IDecl = C->getClassInterface())) {
- ObjCInterfaceDecl::PropertyDeclOrder PO;
- IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
- }
+ // Since we don't synthesize class properties, we should emit diagnose even
+ // if SynthesizeProperties is true.
+ ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
+ // Gather properties which need not be implemented in this class
+ // or category.
+ if (!IDecl)
+ if (ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl)) {
+ // For categories, no need to implement properties declared in
+ // its primary class (and its super classes) if property is
+ // declared in one of those containers.
+ if ((IDecl = C->getClassInterface())) {
+ ObjCInterfaceDecl::PropertyDeclOrder PO;
+ IDecl->collectPropertiesToImplement(NoNeedToImplPropMap, PO);
}
- if (IDecl)
- CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
+ }
+ if (IDecl)
+ CollectSuperClassPropertyImplementations(IDecl, NoNeedToImplPropMap);
- CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap);
- }
+ // When SynthesizeProperties is true, we only check class properties.
+ CollectImmediateProperties(CDecl, PropMap, NoNeedToImplPropMap,
+ SynthesizeProperties/*CollectClassPropsOnly*/);
// Scan the @interface to see if any of the protocols it adopts
// require an explicit implementation, via attribute
@@ -1802,14 +1851,17 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
ObjCContainerDecl::PropertyMap NoNeedToImplPropMap;
LazyMap.reset(new ObjCContainerDecl::PropertyMap());
CollectImmediateProperties(CDecl, *LazyMap, NoNeedToImplPropMap,
+ /* CollectClassPropsOnly */ false,
/* IncludeProtocols */ false);
}
// Add the properties of 'PDecl' to the list of properties that
// need to be implemented.
for (auto *PropDecl : PDecl->properties()) {
- if ((*LazyMap)[PropDecl->getIdentifier()])
+ if ((*LazyMap)[std::make_pair(PropDecl->getIdentifier(),
+ PropDecl->isClassProperty())])
continue;
- PropMap[PropDecl->getIdentifier()] = PropDecl;
+ PropMap[std::make_pair(PropDecl->getIdentifier(),
+ PropDecl->isClassProperty())] = PropDecl;
}
}
}
@@ -1821,10 +1873,10 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
for (const auto *I : IMPDecl->property_impls())
PropImplMap.insert(I->getPropertyDecl());
- SelectorSet InsMap;
+ llvm::SmallPtrSet<const ObjCMethodDecl *, 8> InsMap;
// Collect property accessors implemented in current implementation.
- for (const auto *I : IMPDecl->instance_methods())
- InsMap.insert(I->getSelector());
+ for (const auto *I : IMPDecl->methods())
+ InsMap.insert(I);
ObjCCategoryDecl *C = dyn_cast<ObjCCategoryDecl>(CDecl);
ObjCInterfaceDecl *PrimaryClass = nullptr;
@@ -1835,14 +1887,14 @@ void Sema::DiagnoseUnimplementedProperties(Scope *S, ObjCImplDecl* IMPDecl,
// When reporting on missing setter/getters, do not report when
// setter/getter is implemented in category's primary class
// implementation.
- for (const auto *I : IMP->instance_methods())
- InsMap.insert(I->getSelector());
+ for (const auto *I : IMP->methods())
+ InsMap.insert(I);
}
for (ObjCContainerDecl::PropertyMap::iterator
P = PropMap.begin(), E = PropMap.end(); P != E; ++P) {
ObjCPropertyDecl *Prop = P->second;
- // Is there a matching propery synthesize/dynamic?
+ // Is there a matching property synthesize/dynamic?
if (Prop->isInvalidDecl() ||
Prop->getPropertyImplementation() == ObjCPropertyDecl::Optional ||
PropImplMap.count(Prop) ||
@@ -1894,13 +1946,13 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
return;
ObjCContainerDecl::PropertyMap PM;
for (auto *Prop : IDecl->properties())
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
for (const auto *Ext : IDecl->known_extensions())
for (auto *Prop : Ext->properties())
- PM[Prop->getIdentifier()] = Prop;
+ PM[std::make_pair(Prop->getIdentifier(), Prop->isClassProperty())] = Prop;
- for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
- I != E; ++I) {
+ for (ObjCContainerDecl::PropertyMap::iterator I = PM.begin(), E = PM.end();
+ I != E; ++I) {
const ObjCPropertyDecl *Property = I->second;
ObjCMethodDecl *GetterMethod = nullptr;
ObjCMethodDecl *SetterMethod = nullptr;
@@ -1911,8 +1963,12 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
if (!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_atomic) &&
!(AttributesAsWritten & ObjCPropertyDecl::OBJC_PR_nonatomic)) {
- GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
+ GetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getGetterName()) :
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ SetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getSetterName()) :
+ IMPDecl->getInstanceMethod(Property->getSetterName());
LookedUpGetterSetter = true;
if (GetterMethod) {
Diag(GetterMethod->getLocation(),
@@ -1932,13 +1988,17 @@ Sema::AtomicPropertySetterGetterRules (ObjCImplDecl* IMPDecl,
if ((Attributes & ObjCPropertyDecl::OBJC_PR_nonatomic) ||
!(Attributes & ObjCPropertyDecl::OBJC_PR_readwrite))
continue;
- if (const ObjCPropertyImplDecl *PIDecl
- = IMPDecl->FindPropertyImplDecl(Property->getIdentifier())) {
+ if (const ObjCPropertyImplDecl *PIDecl = IMPDecl->FindPropertyImplDecl(
+ Property->getIdentifier(), Property->getQueryKind())) {
if (PIDecl->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic)
continue;
if (!LookedUpGetterSetter) {
- GetterMethod = IMPDecl->getInstanceMethod(Property->getGetterName());
- SetterMethod = IMPDecl->getInstanceMethod(Property->getSetterName());
+ GetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getGetterName()) :
+ IMPDecl->getInstanceMethod(Property->getGetterName());
+ SetterMethod = Property->isClassProperty() ?
+ IMPDecl->getClassMethod(Property->getSetterName()) :
+ IMPDecl->getInstanceMethod(Property->getSetterName());
}
if ((GetterMethod && !SetterMethod) || (!GetterMethod && SetterMethod)) {
SourceLocation MethodLoc =
@@ -1981,6 +2041,7 @@ void Sema::DiagnoseOwningPropertyGetterSynthesis(const ObjCImplementationDecl *D
for (const auto *PID : D->property_impls()) {
const ObjCPropertyDecl *PD = PID->getPropertyDecl();
if (PD && !PD->hasAttr<NSReturnsNotRetainedAttr>() &&
+ !PD->isClassProperty() &&
!D->getInstanceMethod(PD->getGetterName())) {
ObjCMethodDecl *method = PD->getGetterMethodDecl();
if (!method)
@@ -2086,20 +2147,30 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
if (CD->isInvalidDecl())
return;
- GetterMethod = CD->getInstanceMethod(property->getGetterName());
+ bool IsClassProperty = property->isClassProperty();
+ GetterMethod = IsClassProperty ?
+ CD->getClassMethod(property->getGetterName()) :
+ CD->getInstanceMethod(property->getGetterName());
+
// if setter or getter is not found in class extension, it might be
// in the primary class.
if (!GetterMethod)
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
if (CatDecl->IsClassExtension())
- GetterMethod = CatDecl->getClassInterface()->
+ GetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
+ getClassMethod(property->getGetterName()) :
+ CatDecl->getClassInterface()->
getInstanceMethod(property->getGetterName());
- SetterMethod = CD->getInstanceMethod(property->getSetterName());
+ SetterMethod = IsClassProperty ?
+ CD->getClassMethod(property->getSetterName()) :
+ CD->getInstanceMethod(property->getSetterName());
if (!SetterMethod)
if (const ObjCCategoryDecl *CatDecl = dyn_cast<ObjCCategoryDecl>(CD))
if (CatDecl->IsClassExtension())
- SetterMethod = CatDecl->getClassInterface()->
+ SetterMethod = IsClassProperty ? CatDecl->getClassInterface()->
+ getClassMethod(property->getSetterName()) :
+ CatDecl->getClassInterface()->
getInstanceMethod(property->getSetterName());
DiagnosePropertyAccessorMismatch(property, GetterMethod,
property->getLocation());
@@ -2130,13 +2201,16 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// (which is odd, but allowed). Sema should be typechecking that the
// declarations jive in that situation (which it is not currently).
if (!GetterMethod) {
- // No instance method of same name as property getter name was found.
+ // No instance/class method of same name as property getter name was found.
// Declare a getter method and add it to the list of methods
// for this class.
SourceLocation Loc = property->getLocation();
+ // The getter returns the declared property type with all qualifiers
+ // removed.
+ QualType resultTy = property->getType().getAtomicUnqualifiedType();
+
// If the property is null_resettable, the getter returns nonnull.
- QualType resultTy = property->getType();
if (property->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_null_resettable) {
QualType modifiedTy = resultTy;
@@ -2150,7 +2224,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
GetterMethod = ObjCMethodDecl::Create(Context, Loc, Loc,
property->getGetterName(),
resultTy, nullptr, CD,
- /*isInstance=*/true, /*isVariadic=*/false,
+ !IsClassProperty, /*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true, /*isDefined=*/false,
(property->getPropertyImplementation() ==
@@ -2186,7 +2260,8 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
if (!property->isReadOnly()) {
// Find the default setter and if one not found, add one.
if (!SetterMethod) {
- // No instance method of same name as property setter name was found.
+ // No instance/class method of same name as property setter name was
+ // found.
// Declare a setter method and add it to the list of methods
// for this class.
SourceLocation Loc = property->getLocation();
@@ -2194,7 +2269,7 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
SetterMethod =
ObjCMethodDecl::Create(Context, Loc, Loc,
property->getSetterName(), Context.VoidTy,
- nullptr, CD, /*isInstance=*/true,
+ nullptr, CD, !IsClassProperty,
/*isVariadic=*/false,
/*isPropertyAccessor=*/true,
/*isImplicitlyDeclared=*/true,
@@ -2204,9 +2279,12 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
ObjCMethodDecl::Optional :
ObjCMethodDecl::Required);
+ // Remove all qualifiers from the setter's parameter type.
+ QualType paramTy =
+ property->getType().getUnqualifiedType().getAtomicUnqualifiedType();
+
// If the property is null_resettable, the setter accepts a
// nullable value.
- QualType paramTy = property->getType().getUnqualifiedType();
if (property->getPropertyAttributes() &
ObjCPropertyDecl::OBJC_PR_null_resettable) {
QualType modifiedTy = paramTy;
@@ -2257,10 +2335,17 @@ void Sema::ProcessPropertyDecl(ObjCPropertyDecl *property) {
// double bar = [foo bar];
// }
//
- if (GetterMethod)
- AddInstanceMethodToGlobalPool(GetterMethod);
- if (SetterMethod)
- AddInstanceMethodToGlobalPool(SetterMethod);
+ if (!IsClassProperty) {
+ if (GetterMethod)
+ AddInstanceMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddInstanceMethodToGlobalPool(SetterMethod);
+ } else {
+ if (GetterMethod)
+ AddFactoryMethodToGlobalPool(GetterMethod);
+ if (SetterMethod)
+ AddFactoryMethodToGlobalPool(SetterMethod);
+ }
ObjCInterfaceDecl *CurrentClass = dyn_cast<ObjCInterfaceDecl>(CD);
if (!CurrentClass) {
@@ -2447,5 +2532,4 @@ void Sema::CheckObjCPropertyAttributes(Decl *PDecl,
if ((Attributes & ObjCDeclSpec::DQ_PR_readonly) &&
(Attributes & ObjCDeclSpec::DQ_PR_setter))
Diag(Loc, diag::warn_objc_readonly_property_has_setter);
-
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
index 0d51ee11d109..3c8554893b43 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaOpenMP.cpp
@@ -15,12 +15,14 @@
#include "TreeTransform.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTMutationListener.h"
+#include "clang/AST/CXXInheritance.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclCXX.h"
#include "clang/AST/DeclOpenMP.h"
#include "clang/AST/StmtCXX.h"
#include "clang/AST/StmtOpenMP.h"
#include "clang/AST/StmtVisitor.h"
+#include "clang/AST/TypeOrdering.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -43,111 +45,91 @@ enum DefaultDataSharingAttributes {
DSA_shared = 1 << 1 /// \brief Default data sharing attribute 'shared'.
};
-template <class T> struct MatchesAny {
- explicit MatchesAny(ArrayRef<T> Arr) : Arr(std::move(Arr)) {}
- bool operator()(T Kind) {
- for (auto KindEl : Arr)
- if (KindEl == Kind)
- return true;
- return false;
- }
-
-private:
- ArrayRef<T> Arr;
-};
-struct MatchesAlways {
- MatchesAlways() {}
- template <class T> bool operator()(T) { return true; }
-};
-
-typedef MatchesAny<OpenMPClauseKind> MatchesAnyClause;
-typedef MatchesAny<OpenMPDirectiveKind> MatchesAnyDirective;
-
/// \brief Stack for tracking declarations used in OpenMP directives and
/// clauses and their data-sharing attributes.
-class DSAStackTy {
+class DSAStackTy final {
public:
- struct DSAVarData {
- OpenMPDirectiveKind DKind;
- OpenMPClauseKind CKind;
- DeclRefExpr *RefExpr;
+ struct DSAVarData final {
+ OpenMPDirectiveKind DKind = OMPD_unknown;
+ OpenMPClauseKind CKind = OMPC_unknown;
+ Expr *RefExpr = nullptr;
+ DeclRefExpr *PrivateCopy = nullptr;
SourceLocation ImplicitDSALoc;
- DSAVarData()
- : DKind(OMPD_unknown), CKind(OMPC_unknown), RefExpr(nullptr),
- ImplicitDSALoc() {}
- };
-
-public:
- struct MapInfo {
- Expr *RefExpr;
+ DSAVarData() {}
};
+ typedef llvm::SmallVector<std::pair<Expr *, OverloadedOperatorKind>, 4>
+ OperatorOffsetTy;
private:
- struct DSAInfo {
- OpenMPClauseKind Attributes;
- DeclRefExpr *RefExpr;
+ struct DSAInfo final {
+ OpenMPClauseKind Attributes = OMPC_unknown;
+ /// Pointer to a reference expression and a flag which shows that the
+ /// variable is marked as lastprivate(true) or not (false).
+ llvm::PointerIntPair<Expr *, 1, bool> RefExpr;
+ DeclRefExpr *PrivateCopy = nullptr;
};
- typedef llvm::SmallDenseMap<VarDecl *, DSAInfo, 64> DeclSAMapTy;
- typedef llvm::SmallDenseMap<VarDecl *, DeclRefExpr *, 64> AlignedMapTy;
- typedef llvm::DenseMap<VarDecl *, unsigned> LoopControlVariablesMapTy;
- typedef llvm::SmallDenseMap<VarDecl *, MapInfo, 64> MappedDeclsTy;
+ typedef llvm::DenseMap<ValueDecl *, DSAInfo> DeclSAMapTy;
+ typedef llvm::DenseMap<ValueDecl *, Expr *> AlignedMapTy;
+ typedef std::pair<unsigned, VarDecl *> LCDeclInfo;
+ typedef llvm::DenseMap<ValueDecl *, LCDeclInfo> LoopControlVariablesMapTy;
+ typedef llvm::DenseMap<
+ ValueDecl *, OMPClauseMappableExprCommon::MappableExprComponentLists>
+ MappedExprComponentsTy;
typedef llvm::StringMap<std::pair<OMPCriticalDirective *, llvm::APSInt>>
CriticalsWithHintsTy;
+ typedef llvm::DenseMap<OMPDependClause *, OperatorOffsetTy>
+ DoacrossDependMapTy;
- struct SharingMapTy {
+ struct SharingMapTy final {
DeclSAMapTy SharingMap;
AlignedMapTy AlignedMap;
- MappedDeclsTy MappedDecls;
+ MappedExprComponentsTy MappedExprComponents;
LoopControlVariablesMapTy LCVMap;
- DefaultDataSharingAttributes DefaultAttr;
+ DefaultDataSharingAttributes DefaultAttr = DSA_unspecified;
SourceLocation DefaultAttrLoc;
- OpenMPDirectiveKind Directive;
+ OpenMPDirectiveKind Directive = OMPD_unknown;
DeclarationNameInfo DirectiveName;
- Scope *CurScope;
+ Scope *CurScope = nullptr;
SourceLocation ConstructLoc;
+ /// Set of 'depend' clauses with 'sink|source' dependence kind. Required to
+ /// get the data (loop counters etc.) about enclosing loop-based construct.
+ /// This data is required during codegen.
+ DoacrossDependMapTy DoacrossDepends;
/// \brief first argument (Expr *) contains optional argument of the
/// 'ordered' clause, the second one is true if the regions has 'ordered'
/// clause, false otherwise.
llvm::PointerIntPair<Expr *, 1, bool> OrderedRegion;
- bool NowaitRegion;
- bool CancelRegion;
- unsigned AssociatedLoops;
+ bool NowaitRegion = false;
+ bool CancelRegion = false;
+ unsigned AssociatedLoops = 1;
SourceLocation InnerTeamsRegionLoc;
SharingMapTy(OpenMPDirectiveKind DKind, DeclarationNameInfo Name,
Scope *CurScope, SourceLocation Loc)
- : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified),
- Directive(DKind), DirectiveName(std::move(Name)), CurScope(CurScope),
- ConstructLoc(Loc), OrderedRegion(), NowaitRegion(false),
- CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {}
- SharingMapTy()
- : SharingMap(), AlignedMap(), LCVMap(), DefaultAttr(DSA_unspecified),
- Directive(OMPD_unknown), DirectiveName(), CurScope(nullptr),
- ConstructLoc(), OrderedRegion(), NowaitRegion(false),
- CancelRegion(false), AssociatedLoops(1), InnerTeamsRegionLoc() {}
+ : Directive(DKind), DirectiveName(Name), CurScope(CurScope),
+ ConstructLoc(Loc) {}
+ SharingMapTy() {}
};
- typedef SmallVector<SharingMapTy, 64> StackTy;
+ typedef SmallVector<SharingMapTy, 4> StackTy;
/// \brief Stack of used declaration and their data-sharing attributes.
StackTy Stack;
/// \brief true, if check for DSA must be from parent directive, false, if
/// from current directive.
- OpenMPClauseKind ClauseKindMode;
+ OpenMPClauseKind ClauseKindMode = OMPC_unknown;
Sema &SemaRef;
- bool ForceCapturing;
+ bool ForceCapturing = false;
CriticalsWithHintsTy Criticals;
typedef SmallVector<SharingMapTy, 8>::reverse_iterator reverse_iterator;
- DSAVarData getDSA(StackTy::reverse_iterator Iter, VarDecl *D);
+ DSAVarData getDSA(StackTy::reverse_iterator& Iter, ValueDecl *D);
/// \brief Checks if the variable is a local for OpenMP region.
bool isOpenMPLocal(VarDecl *D, StackTy::reverse_iterator Iter);
public:
- explicit DSAStackTy(Sema &S)
- : Stack(1), ClauseKindMode(OMPC_unknown), SemaRef(S),
- ForceCapturing(false) {}
+ explicit DSAStackTy(Sema &S) : Stack(1), SemaRef(S) {}
bool isClauseParsingMode() const { return ClauseKindMode != OMPC_unknown; }
void setClauseParsingMode(OpenMPClauseKind K) { ClauseKindMode = K; }
@@ -179,51 +161,54 @@ public:
/// \brief If 'aligned' declaration for given variable \a D was not seen yet,
/// add it and return NULL; otherwise return previous occurrence's expression
/// for diagnostics.
- DeclRefExpr *addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE);
+ Expr *addUniqueAligned(ValueDecl *D, Expr *NewDE);
/// \brief Register specified variable as loop control variable.
- void addLoopControlVariable(VarDecl *D);
+ void addLoopControlVariable(ValueDecl *D, VarDecl *Capture);
/// \brief Check if the specified variable is a loop control variable for
/// current region.
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
- unsigned isLoopControlVariable(VarDecl *D);
+ LCDeclInfo isLoopControlVariable(ValueDecl *D);
/// \brief Check if the specified variable is a loop control variable for
/// parent region.
/// \return The index of the loop control variable in the list of associated
/// for-loops (from outer to inner).
- unsigned isParentLoopControlVariable(VarDecl *D);
+ LCDeclInfo isParentLoopControlVariable(ValueDecl *D);
/// \brief Get the loop control variable for the I-th loop (or nullptr) in
/// parent directive.
- VarDecl *getParentLoopControlVariable(unsigned I);
+ ValueDecl *getParentLoopControlVariable(unsigned I);
/// \brief Adds explicit data sharing attribute to the specified declaration.
- void addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A);
+ void addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
+ DeclRefExpr *PrivateCopy = nullptr);
/// \brief Returns data sharing attributes from top of the stack for the
/// specified declaration.
- DSAVarData getTopDSA(VarDecl *D, bool FromParent);
+ DSAVarData getTopDSA(ValueDecl *D, bool FromParent);
/// \brief Returns data-sharing attributes for the specified declaration.
- DSAVarData getImplicitDSA(VarDecl *D, bool FromParent);
+ DSAVarData getImplicitDSA(ValueDecl *D, bool FromParent);
/// \brief Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any directive which matches \a DPred
/// predicate.
- template <class ClausesPredicate, class DirectivesPredicate>
- DSAVarData hasDSA(VarDecl *D, ClausesPredicate CPred,
- DirectivesPredicate DPred, bool FromParent);
+ DSAVarData hasDSA(ValueDecl *D,
+ const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
+ const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
+ bool FromParent);
/// \brief Checks if the specified variables has data-sharing attributes which
/// match specified \a CPred predicate in any innermost directive which
/// matches \a DPred predicate.
- template <class ClausesPredicate, class DirectivesPredicate>
- DSAVarData hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
- DirectivesPredicate DPred,
- bool FromParent);
+ DSAVarData
+ hasInnermostDSA(ValueDecl *D,
+ const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
+ const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
+ bool FromParent);
/// \brief Checks if the specified variables has explicit data-sharing
/// attributes which match specified \a CPred predicate at the specified
/// OpenMP region.
- bool hasExplicitDSA(VarDecl *D,
+ bool hasExplicitDSA(ValueDecl *D,
const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
- unsigned Level);
+ unsigned Level, bool NotLastprivate = false);
/// \brief Returns true if the directive at level \Level matches in the
/// specified \a DPred predicate.
@@ -232,8 +217,10 @@ public:
unsigned Level);
/// \brief Finds a directive which matches specified \a DPred predicate.
- template <class NamedDirectivesPredicate>
- bool hasDirective(NamedDirectivesPredicate DPred, bool FromParent);
+ bool hasDirective(const llvm::function_ref<bool(OpenMPDirectiveKind,
+ const DeclarationNameInfo &,
+ SourceLocation)> &DPred,
+ bool FromParent);
/// \brief Returns currently analyzed directive.
OpenMPDirectiveKind getCurrentDirective() const {
@@ -245,8 +232,6 @@ public:
return Stack[Stack.size() - 2].Directive;
return OMPD_unknown;
}
- /// \brief Return the directive associated with the provided scope.
- OpenMPDirectiveKind getDirectiveForScope(const Scope *S) const;
/// \brief Set default data sharing attribute to none.
void setDefaultDSANone(SourceLocation Loc) {
@@ -338,42 +323,92 @@ public:
Scope *getCurScope() { return Stack.back().CurScope; }
SourceLocation getConstructLoc() { return Stack.back().ConstructLoc; }
- MapInfo getMapInfoForVar(VarDecl *VD) {
- MapInfo VarMI = {0};
- for (auto Cnt = Stack.size() - 1; Cnt > 0; --Cnt) {
- if (Stack[Cnt].MappedDecls.count(VD)) {
- VarMI = Stack[Cnt].MappedDecls[VD];
- break;
- }
+ // Do the check specified in \a Check to all component lists and return true
+ // if any issue is found.
+ bool checkMappableExprComponentListsForDecl(
+ ValueDecl *VD, bool CurrentRegionOnly,
+ const llvm::function_ref<bool(
+ OMPClauseMappableExprCommon::MappableExprComponentListRef)> &Check) {
+ auto SI = Stack.rbegin();
+ auto SE = Stack.rend();
+
+ if (SI == SE)
+ return false;
+
+ if (CurrentRegionOnly) {
+ SE = std::next(SI);
+ } else {
+ ++SI;
}
- return VarMI;
- }
- void addMapInfoForVar(VarDecl *VD, MapInfo MI) {
- if (Stack.size() > 1) {
- Stack.back().MappedDecls[VD] = MI;
+ for (; SI != SE; ++SI) {
+ auto MI = SI->MappedExprComponents.find(VD);
+ if (MI != SI->MappedExprComponents.end())
+ for (auto &L : MI->second)
+ if (Check(L))
+ return true;
}
+ return false;
}
- MapInfo IsMappedInCurrentRegion(VarDecl *VD) {
- assert(Stack.size() > 1 && "Target level is 0");
- MapInfo VarMI = {0};
- if (Stack.size() > 1 && Stack.back().MappedDecls.count(VD)) {
- VarMI = Stack.back().MappedDecls[VD];
+ // Create a new mappable expression component list associated with a given
+ // declaration and initialize it with the provided list of components.
+ void addMappableExpressionComponents(
+ ValueDecl *VD,
+ OMPClauseMappableExprCommon::MappableExprComponentListRef Components) {
+ assert(Stack.size() > 1 &&
+ "Not expecting to retrieve components from a empty stack!");
+ auto &MEC = Stack.back().MappedExprComponents[VD];
+ // Create new entry and append the new components there.
+ MEC.resize(MEC.size() + 1);
+ MEC.back().append(Components.begin(), Components.end());
+ }
+
+ unsigned getNestingLevel() const {
+ assert(Stack.size() > 1);
+ return Stack.size() - 2;
+ }
+ void addDoacrossDependClause(OMPDependClause *C, OperatorOffsetTy &OpsOffs) {
+ assert(Stack.size() > 2);
+ assert(isOpenMPWorksharingDirective(Stack[Stack.size() - 2].Directive));
+ Stack[Stack.size() - 2].DoacrossDepends.insert({C, OpsOffs});
+ }
+ llvm::iterator_range<DoacrossDependMapTy::const_iterator>
+ getDoacrossDependClauses() const {
+ assert(Stack.size() > 1);
+ if (isOpenMPWorksharingDirective(Stack[Stack.size() - 1].Directive)) {
+ auto &Ref = Stack[Stack.size() - 1].DoacrossDepends;
+ return llvm::make_range(Ref.begin(), Ref.end());
}
- return VarMI;
+ return llvm::make_range(Stack[0].DoacrossDepends.end(),
+ Stack[0].DoacrossDepends.end());
}
};
bool isParallelOrTaskRegion(OpenMPDirectiveKind DKind) {
- return isOpenMPParallelDirective(DKind) || DKind == OMPD_task ||
- isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown ||
- isOpenMPTaskLoopDirective(DKind);
+ return isOpenMPParallelDirective(DKind) || isOpenMPTaskingDirective(DKind) ||
+ isOpenMPTeamsDirective(DKind) || DKind == OMPD_unknown;
}
} // namespace
-DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
- VarDecl *D) {
- D = D->getCanonicalDecl();
+static ValueDecl *getCanonicalDecl(ValueDecl *D) {
+ auto *VD = dyn_cast<VarDecl>(D);
+ auto *FD = dyn_cast<FieldDecl>(D);
+ if (VD != nullptr) {
+ VD = VD->getCanonicalDecl();
+ D = VD;
+ } else {
+ assert(FD);
+ FD = FD->getCanonicalDecl();
+ D = FD;
+ }
+ return D;
+}
+
+DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator& Iter,
+ ValueDecl *D) {
+ D = getCanonicalDecl(D);
+ auto *VD = dyn_cast<VarDecl>(D);
+ auto *FD = dyn_cast<FieldDecl>(D);
DSAVarData DVar;
if (Iter == std::prev(Stack.rend())) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -381,14 +416,18 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// File-scope or namespace-scope variables referenced in called routines
// in the region are shared unless they appear in a threadprivate
// directive.
- if (!D->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D))
+ if (VD && !VD->isFunctionOrMethodVarDecl() && !isa<ParmVarDecl>(D))
DVar.CKind = OMPC_shared;
// OpenMP [2.9.1.2, Data-sharing Attribute Rules for Variables Referenced
// in a region but not in construct]
// Variables with static storage duration that are declared in called
// routines in the region are shared.
- if (D->hasGlobalStorage())
+ if (VD && VD->hasGlobalStorage())
+ DVar.CKind = OMPC_shared;
+
+ // Non-static data members are shared by default.
+ if (FD)
DVar.CKind = OMPC_shared;
return DVar;
@@ -399,8 +438,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// in a Construct, C/C++, predetermined, p.1]
// Variables with automatic storage duration that are declared in a scope
// inside the construct are private.
- if (isOpenMPLocal(D, Iter) && D->isLocalVarDecl() &&
- (D->getStorageClass() == SC_Auto || D->getStorageClass() == SC_None)) {
+ if (VD && isOpenMPLocal(VD, Iter) && VD->isLocalVarDecl() &&
+ (VD->getStorageClass() == SC_Auto || VD->getStorageClass() == SC_None)) {
DVar.CKind = OMPC_private;
return DVar;
}
@@ -408,7 +447,8 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// Explicitly specified attributes and local variables with predetermined
// attributes.
if (Iter->SharingMap.count(D)) {
- DVar.RefExpr = Iter->SharingMap[D].RefExpr;
+ DVar.RefExpr = Iter->SharingMap[D].RefExpr.getPointer();
+ DVar.PrivateCopy = Iter->SharingMap[D].PrivateCopy;
DVar.CKind = Iter->SharingMap[D].Attributes;
DVar.ImplicitDSALoc = Iter->DefaultAttrLoc;
return DVar;
@@ -442,27 +482,24 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// In a task construct, if no default clause is present, a variable that in
// the enclosing context is determined to be shared by all implicit tasks
// bound to the current team is shared.
- if (DVar.DKind == OMPD_task) {
+ if (isOpenMPTaskingDirective(DVar.DKind)) {
DSAVarData DVarTemp;
for (StackTy::reverse_iterator I = std::next(Iter), EE = Stack.rend();
I != EE; ++I) {
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables
- // Referenced
- // in a Construct, implicitly determined, p.6]
+ // Referenced in a Construct, implicitly determined, p.6]
// In a task construct, if no default clause is present, a variable
// whose data-sharing attribute is not determined by the rules above is
// firstprivate.
DVarTemp = getDSA(I, D);
if (DVarTemp.CKind != OMPC_shared) {
DVar.RefExpr = nullptr;
- DVar.DKind = OMPD_task;
DVar.CKind = OMPC_firstprivate;
return DVar;
}
if (isParallelOrTaskRegion(I->Directive))
break;
}
- DVar.DKind = OMPD_task;
DVar.CKind =
(DVarTemp.CKind == OMPC_unknown) ? OMPC_firstprivate : OMPC_shared;
return DVar;
@@ -473,12 +510,12 @@ DSAStackTy::DSAVarData DSAStackTy::getDSA(StackTy::reverse_iterator Iter,
// For constructs other than task, if no default clause is present, these
// variables inherit their data-sharing attributes from the enclosing
// context.
- return getDSA(std::next(Iter), D);
+ return getDSA(++Iter, D);
}
-DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) {
+Expr *DSAStackTy::addUniqueAligned(ValueDecl *D, Expr *NewDE) {
assert(Stack.size() > 1 && "Data sharing attributes stack is empty");
- D = D->getCanonicalDecl();
+ D = getCanonicalDecl(D);
auto It = Stack.back().AlignedMap.find(D);
if (It == Stack.back().AlignedMap.end()) {
assert(NewDE && "Unexpected nullptr expr to be added into aligned map");
@@ -491,46 +528,69 @@ DeclRefExpr *DSAStackTy::addUniqueAligned(VarDecl *D, DeclRefExpr *NewDE) {
return nullptr;
}
-void DSAStackTy::addLoopControlVariable(VarDecl *D) {
+void DSAStackTy::addLoopControlVariable(ValueDecl *D, VarDecl *Capture) {
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
- D = D->getCanonicalDecl();
- Stack.back().LCVMap.insert(std::make_pair(D, Stack.back().LCVMap.size() + 1));
+ D = getCanonicalDecl(D);
+ Stack.back().LCVMap.insert(
+ std::make_pair(D, LCDeclInfo(Stack.back().LCVMap.size() + 1, Capture)));
}
-unsigned DSAStackTy::isLoopControlVariable(VarDecl *D) {
+DSAStackTy::LCDeclInfo DSAStackTy::isLoopControlVariable(ValueDecl *D) {
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
- D = D->getCanonicalDecl();
- return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D] : 0;
+ D = getCanonicalDecl(D);
+ return Stack.back().LCVMap.count(D) > 0 ? Stack.back().LCVMap[D]
+ : LCDeclInfo(0, nullptr);
}
-unsigned DSAStackTy::isParentLoopControlVariable(VarDecl *D) {
+DSAStackTy::LCDeclInfo DSAStackTy::isParentLoopControlVariable(ValueDecl *D) {
assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
- D = D->getCanonicalDecl();
+ D = getCanonicalDecl(D);
return Stack[Stack.size() - 2].LCVMap.count(D) > 0
? Stack[Stack.size() - 2].LCVMap[D]
- : 0;
+ : LCDeclInfo(0, nullptr);
}
-VarDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
+ValueDecl *DSAStackTy::getParentLoopControlVariable(unsigned I) {
assert(Stack.size() > 2 && "Data-sharing attributes stack is empty");
if (Stack[Stack.size() - 2].LCVMap.size() < I)
return nullptr;
for (auto &Pair : Stack[Stack.size() - 2].LCVMap) {
- if (Pair.second == I)
+ if (Pair.second.first == I)
return Pair.first;
}
return nullptr;
}
-void DSAStackTy::addDSA(VarDecl *D, DeclRefExpr *E, OpenMPClauseKind A) {
- D = D->getCanonicalDecl();
+void DSAStackTy::addDSA(ValueDecl *D, Expr *E, OpenMPClauseKind A,
+ DeclRefExpr *PrivateCopy) {
+ D = getCanonicalDecl(D);
if (A == OMPC_threadprivate) {
- Stack[0].SharingMap[D].Attributes = A;
- Stack[0].SharingMap[D].RefExpr = E;
+ auto &Data = Stack[0].SharingMap[D];
+ Data.Attributes = A;
+ Data.RefExpr.setPointer(E);
+ Data.PrivateCopy = nullptr;
} else {
assert(Stack.size() > 1 && "Data-sharing attributes stack is empty");
- Stack.back().SharingMap[D].Attributes = A;
- Stack.back().SharingMap[D].RefExpr = E;
+ auto &Data = Stack.back().SharingMap[D];
+ assert(Data.Attributes == OMPC_unknown || (A == Data.Attributes) ||
+ (A == OMPC_firstprivate && Data.Attributes == OMPC_lastprivate) ||
+ (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) ||
+ (isLoopControlVariable(D).first && A == OMPC_private));
+ if (A == OMPC_lastprivate && Data.Attributes == OMPC_firstprivate) {
+ Data.RefExpr.setInt(/*IntVal=*/true);
+ return;
+ }
+ const bool IsLastprivate =
+ A == OMPC_lastprivate || Data.Attributes == OMPC_lastprivate;
+ Data.Attributes = A;
+ Data.RefExpr.setPointerAndInt(E, IsLastprivate);
+ Data.PrivateCopy = PrivateCopy;
+ if (PrivateCopy) {
+ auto &Data = Stack.back().SharingMap[PrivateCopy->getDecl()];
+ Data.Attributes = A;
+ Data.RefExpr.setPointerAndInt(PrivateCopy, IsLastprivate);
+ Data.PrivateCopy = nullptr;
+ }
}
}
@@ -581,29 +641,35 @@ static DeclRefExpr *buildDeclRefExpr(Sema &S, VarDecl *D, QualType Ty,
VK_LValue);
}
-DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
- D = D->getCanonicalDecl();
+DSAStackTy::DSAVarData DSAStackTy::getTopDSA(ValueDecl *D, bool FromParent) {
+ D = getCanonicalDecl(D);
DSAVarData DVar;
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.1]
// Variables appearing in threadprivate directives are threadprivate.
- if ((D->getTLSKind() != VarDecl::TLS_None &&
- !(D->hasAttr<OMPThreadPrivateDeclAttr>() &&
+ auto *VD = dyn_cast<VarDecl>(D);
+ if ((VD && VD->getTLSKind() != VarDecl::TLS_None &&
+ !(VD->hasAttr<OMPThreadPrivateDeclAttr>() &&
SemaRef.getLangOpts().OpenMPUseTLS &&
SemaRef.getASTContext().getTargetInfo().isTLSSupported())) ||
- (D->getStorageClass() == SC_Register && D->hasAttr<AsmLabelAttr>() &&
- !D->isLocalVarDecl())) {
- addDSA(D, buildDeclRefExpr(SemaRef, D, D->getType().getNonReferenceType(),
+ (VD && VD->getStorageClass() == SC_Register &&
+ VD->hasAttr<AsmLabelAttr>() && !VD->isLocalVarDecl())) {
+ addDSA(D, buildDeclRefExpr(SemaRef, VD, D->getType().getNonReferenceType(),
D->getLocation()),
OMPC_threadprivate);
}
if (Stack[0].SharingMap.count(D)) {
- DVar.RefExpr = Stack[0].SharingMap[D].RefExpr;
+ DVar.RefExpr = Stack[0].SharingMap[D].RefExpr.getPointer();
DVar.CKind = OMPC_threadprivate;
return DVar;
}
+ if (Stack.size() == 1) {
+ // Not in OpenMP execution region and top scope was already checked.
+ return DVar;
+ }
+
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct, C/C++, predetermined, p.4]
// Static data members are shared.
@@ -611,9 +677,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
// in a Construct, C/C++, predetermined, p.7]
// Variables with static storage duration that are declared in a scope
// inside the construct are shared.
- if (D->isStaticDataMember()) {
- DSAVarData DVarTemp =
- hasDSA(D, isOpenMPPrivate, MatchesAlways(), FromParent);
+ auto &&MatchesAlways = [](OpenMPDirectiveKind) -> bool { return true; };
+ if (VD && VD->isStaticDataMember()) {
+ DSAVarData DVarTemp = hasDSA(D, isOpenMPPrivate, MatchesAlways, FromParent);
if (DVarTemp.CKind != OMPC_unknown && DVarTemp.RefExpr)
return DVar;
@@ -638,8 +704,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
RD->hasMutableFields())) {
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
- DSAVarData DVarTemp = hasDSA(D, MatchesAnyClause(OMPC_firstprivate),
- MatchesAlways(), FromParent);
+ DSAVarData DVarTemp = hasDSA(
+ D, [](OpenMPClauseKind C) -> bool { return C == OMPC_firstprivate; },
+ MatchesAlways, FromParent);
if (DVarTemp.CKind == OMPC_firstprivate && DVarTemp.RefExpr)
return DVar;
@@ -656,7 +723,8 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
}
auto I = std::prev(StartI);
if (I->SharingMap.count(D)) {
- DVar.RefExpr = I->SharingMap[D].RefExpr;
+ DVar.RefExpr = I->SharingMap[D].RefExpr.getPointer();
+ DVar.PrivateCopy = I->SharingMap[D].PrivateCopy;
DVar.CKind = I->SharingMap[D].Attributes;
DVar.ImplicitDSALoc = I->DefaultAttrLoc;
}
@@ -664,8 +732,9 @@ DSAStackTy::DSAVarData DSAStackTy::getTopDSA(VarDecl *D, bool FromParent) {
return DVar;
}
-DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) {
- D = D->getCanonicalDecl();
+DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(ValueDecl *D,
+ bool FromParent) {
+ D = getCanonicalDecl(D);
auto StartI = Stack.rbegin();
auto EndI = std::prev(Stack.rend());
if (FromParent && StartI != EndI) {
@@ -674,13 +743,14 @@ DSAStackTy::DSAVarData DSAStackTy::getImplicitDSA(VarDecl *D, bool FromParent) {
return getDSA(StartI, D);
}
-template <class ClausesPredicate, class DirectivesPredicate>
-DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred,
- DirectivesPredicate DPred,
- bool FromParent) {
- D = D->getCanonicalDecl();
+DSAStackTy::DSAVarData
+DSAStackTy::hasDSA(ValueDecl *D,
+ const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
+ const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
+ bool FromParent) {
+ D = getCanonicalDecl(D);
auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
+ auto EndI = Stack.rend();
if (FromParent && StartI != EndI) {
StartI = std::next(StartI);
}
@@ -694,13 +764,13 @@ DSAStackTy::DSAVarData DSAStackTy::hasDSA(VarDecl *D, ClausesPredicate CPred,
return DSAVarData();
}
-template <class ClausesPredicate, class DirectivesPredicate>
-DSAStackTy::DSAVarData
-DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
- DirectivesPredicate DPred, bool FromParent) {
- D = D->getCanonicalDecl();
+DSAStackTy::DSAVarData DSAStackTy::hasInnermostDSA(
+ ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
+ const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
+ bool FromParent) {
+ D = getCanonicalDecl(D);
auto StartI = std::next(Stack.rbegin());
- auto EndI = std::prev(Stack.rend());
+ auto EndI = Stack.rend();
if (FromParent && StartI != EndI) {
StartI = std::next(StartI);
}
@@ -716,37 +786,41 @@ DSAStackTy::hasInnermostDSA(VarDecl *D, ClausesPredicate CPred,
}
bool DSAStackTy::hasExplicitDSA(
- VarDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
- unsigned Level) {
+ ValueDecl *D, const llvm::function_ref<bool(OpenMPClauseKind)> &CPred,
+ unsigned Level, bool NotLastprivate) {
if (CPred(ClauseKindMode))
return true;
- if (isClauseParsingMode())
- ++Level;
- D = D->getCanonicalDecl();
- auto StartI = Stack.rbegin();
- auto EndI = std::prev(Stack.rend());
+ D = getCanonicalDecl(D);
+ auto StartI = std::next(Stack.begin());
+ auto EndI = Stack.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
- return (StartI->SharingMap.count(D) > 0) && StartI->SharingMap[D].RefExpr &&
- CPred(StartI->SharingMap[D].Attributes);
+ return (StartI->SharingMap.count(D) > 0) &&
+ StartI->SharingMap[D].RefExpr.getPointer() &&
+ CPred(StartI->SharingMap[D].Attributes) &&
+ (!NotLastprivate || !StartI->SharingMap[D].RefExpr.getInt());
}
bool DSAStackTy::hasExplicitDirective(
const llvm::function_ref<bool(OpenMPDirectiveKind)> &DPred,
unsigned Level) {
- if (isClauseParsingMode())
- ++Level;
- auto StartI = Stack.rbegin();
- auto EndI = std::prev(Stack.rend());
+ auto StartI = std::next(Stack.begin());
+ auto EndI = Stack.end();
if (std::distance(StartI, EndI) <= (int)Level)
return false;
std::advance(StartI, Level);
return DPred(StartI->Directive);
}
-template <class NamedDirectivesPredicate>
-bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) {
+bool DSAStackTy::hasDirective(
+ const llvm::function_ref<bool(OpenMPDirectiveKind,
+ const DeclarationNameInfo &, SourceLocation)>
+ &DPred,
+ bool FromParent) {
+ // We look only in the enclosing region.
+ if (Stack.size() < 2)
+ return false;
auto StartI = std::next(Stack.rbegin());
auto EndI = std::prev(Stack.rend());
if (FromParent && StartI != EndI) {
@@ -759,31 +833,22 @@ bool DSAStackTy::hasDirective(NamedDirectivesPredicate DPred, bool FromParent) {
return false;
}
-OpenMPDirectiveKind DSAStackTy::getDirectiveForScope(const Scope *S) const {
- for (auto I = Stack.rbegin(), EE = Stack.rend(); I != EE; ++I)
- if (I->CurScope == S)
- return I->Directive;
- return OMPD_unknown;
-}
-
void Sema::InitDataSharingAttributesStack() {
VarDataSharingAttributesStack = new DSAStackTy(*this);
}
#define DSAStack static_cast<DSAStackTy *>(VarDataSharingAttributesStack)
-bool Sema::IsOpenMPCapturedByRef(VarDecl *VD,
- const CapturedRegionScopeInfo *RSI) {
+bool Sema::IsOpenMPCapturedByRef(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
auto &Ctx = getASTContext();
bool IsByRef = true;
// Find the directive that is associated with the provided scope.
- auto DKind = DSAStack->getDirectiveForScope(RSI->TheScope);
- auto Ty = VD->getType();
+ auto Ty = D->getType();
- if (isOpenMPTargetDirective(DKind)) {
+ if (DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective, Level)) {
// This table summarizes how a given variable should be passed to the device
// given its type and the clauses where it appears. This table is based on
// the description in OpenMP 4.5 [2.10.4, target Construct] and
@@ -838,31 +903,83 @@ bool Sema::IsOpenMPCapturedByRef(VarDecl *VD,
// array section, the runtime library may pass the NULL value to the
// device instead of the value passed to it by the compiler.
- // FIXME: Right now, only implicit maps are implemented. Properly mapping
- // values requires having the map, private, and firstprivate clauses SEMA
- // and parsing in place, which we don't yet.
if (Ty->isReferenceType())
Ty = Ty->castAs<ReferenceType>()->getPointeeType();
- IsByRef = !Ty->isScalarType();
+
+ // Locate map clauses and see if the variable being captured is referred to
+ // in any of those clauses. Here we only care about variables, not fields,
+ // because fields are part of aggregates.
+ bool IsVariableUsedInMapClause = false;
+ bool IsVariableAssociatedWithSection = false;
+
+ DSAStack->checkMappableExprComponentListsForDecl(
+ D, /*CurrentRegionOnly=*/true,
+ [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ MapExprComponents) {
+
+ auto EI = MapExprComponents.rbegin();
+ auto EE = MapExprComponents.rend();
+
+ assert(EI != EE && "Invalid map expression!");
+
+ if (isa<DeclRefExpr>(EI->getAssociatedExpression()))
+ IsVariableUsedInMapClause |= EI->getAssociatedDeclaration() == D;
+
+ ++EI;
+ if (EI == EE)
+ return false;
+
+ if (isa<ArraySubscriptExpr>(EI->getAssociatedExpression()) ||
+ isa<OMPArraySectionExpr>(EI->getAssociatedExpression()) ||
+ isa<MemberExpr>(EI->getAssociatedExpression())) {
+ IsVariableAssociatedWithSection = true;
+ // There is nothing more we need to know about this variable.
+ return true;
+ }
+
+ // Keep looking for more map info.
+ return false;
+ });
+
+ if (IsVariableUsedInMapClause) {
+ // If variable is identified in a map clause it is always captured by
+ // reference except if it is a pointer that is dereferenced somehow.
+ IsByRef = !(Ty->isPointerType() && IsVariableAssociatedWithSection);
+ } else {
+ // By default, all the data that has a scalar type is mapped by copy.
+ IsByRef = !Ty->isScalarType();
+ }
}
- // When passing data by value, we need to make sure it fits the uintptr size
+ if (IsByRef && Ty.getNonReferenceType()->isScalarType()) {
+ IsByRef = !DSAStack->hasExplicitDSA(
+ D, [](OpenMPClauseKind K) -> bool { return K == OMPC_firstprivate; },
+ Level, /*NotLastprivate=*/true);
+ }
+
+ // When passing data by copy, we need to make sure it fits the uintptr size
// and alignment, because the runtime library only deals with uintptr types.
// If it does not fit the uintptr size, we need to pass the data by reference
// instead.
if (!IsByRef &&
(Ctx.getTypeSizeInChars(Ty) >
Ctx.getTypeSizeInChars(Ctx.getUIntPtrType()) ||
- Ctx.getDeclAlign(VD) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType())))
+ Ctx.getDeclAlign(D) > Ctx.getTypeAlignInChars(Ctx.getUIntPtrType()))) {
IsByRef = true;
+ }
return IsByRef;
}
-bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
+unsigned Sema::getOpenMPNestingLevel() const {
+ assert(getLangOpts().OpenMP);
+ return DSAStack->getNestingLevel();
+}
+
+VarDecl *Sema::IsOpenMPCapturedDecl(ValueDecl *D) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
- VD = VD->getCanonicalDecl();
+ D = getCanonicalDecl(D);
// If we are attempting to capture a global variable in a directive with
// 'target' we return true so that this global is also mapped to the device.
@@ -871,52 +988,55 @@ bool Sema::IsOpenMPCapturedVar(VarDecl *VD) {
// then it should not be captured. Therefore, an extra check has to be
// inserted here once support for 'declare target' is added.
//
- if (!VD->hasLocalStorage()) {
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (VD && !VD->hasLocalStorage()) {
if (DSAStack->getCurrentDirective() == OMPD_target &&
- !DSAStack->isClauseParsingMode()) {
- return true;
- }
- if (DSAStack->getCurScope() &&
- DSAStack->hasDirective(
- [](OpenMPDirectiveKind K, const DeclarationNameInfo &DNI,
- SourceLocation Loc) -> bool {
- return isOpenMPTargetDirective(K);
+ !DSAStack->isClauseParsingMode())
+ return VD;
+ if (DSAStack->hasDirective(
+ [](OpenMPDirectiveKind K, const DeclarationNameInfo &,
+ SourceLocation) -> bool {
+ return isOpenMPTargetExecutionDirective(K);
},
- false)) {
- return true;
- }
+ false))
+ return VD;
}
if (DSAStack->getCurrentDirective() != OMPD_unknown &&
(!DSAStack->isClauseParsingMode() ||
DSAStack->getParentDirective() != OMPD_unknown)) {
- if (DSAStack->isLoopControlVariable(VD) ||
- (VD->hasLocalStorage() &&
+ auto &&Info = DSAStack->isLoopControlVariable(D);
+ if (Info.first ||
+ (VD && VD->hasLocalStorage() &&
isParallelOrTaskRegion(DSAStack->getCurrentDirective())) ||
- DSAStack->isForceVarCapturing())
- return true;
- auto DVarPrivate = DSAStack->getTopDSA(VD, DSAStack->isClauseParsingMode());
+ (VD && DSAStack->isForceVarCapturing()))
+ return VD ? VD : Info.second;
+ auto DVarPrivate = DSAStack->getTopDSA(D, DSAStack->isClauseParsingMode());
if (DVarPrivate.CKind != OMPC_unknown && isOpenMPPrivate(DVarPrivate.CKind))
- return true;
- DVarPrivate = DSAStack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(),
- DSAStack->isClauseParsingMode());
- return DVarPrivate.CKind != OMPC_unknown;
+ return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
+ DVarPrivate = DSAStack->hasDSA(
+ D, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; },
+ DSAStack->isClauseParsingMode());
+ if (DVarPrivate.CKind != OMPC_unknown)
+ return VD ? VD : cast<VarDecl>(DVarPrivate.PrivateCopy->getDecl());
}
- return false;
+ return nullptr;
}
-bool Sema::isOpenMPPrivateVar(VarDecl *VD, unsigned Level) {
+bool Sema::isOpenMPPrivateDecl(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
return DSAStack->hasExplicitDSA(
- VD, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level);
+ D, [](OpenMPClauseKind K) -> bool { return K == OMPC_private; }, Level);
}
-bool Sema::isOpenMPTargetCapturedVar(VarDecl *VD, unsigned Level) {
+bool Sema::isOpenMPTargetCapturedDecl(ValueDecl *D, unsigned Level) {
assert(LangOpts.OpenMP && "OpenMP is not allowed");
// Return true if the current level is no longer enclosed in a target region.
- return !VD->hasLocalStorage() &&
- DSAStack->hasExplicitDirective(isOpenMPTargetDirective, Level);
+ auto *VD = dyn_cast<VarDecl>(D);
+ return VD && !VD->hasLocalStorage() &&
+ DSAStack->hasExplicitDirective(isOpenMPTargetExecutionDirective,
+ Level);
}
void Sema::DestroyDataSharingAttributesStack() { delete DSAStack; }
@@ -951,7 +1071,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
PrivateCopies.push_back(nullptr);
continue;
}
- auto *VD = cast<VarDecl>(cast<DeclRefExpr>(DE)->getDecl());
+ auto *DRE = cast<DeclRefExpr>(DE->IgnoreParens());
+ VarDecl *VD = cast<VarDecl>(DRE->getDecl());
QualType Type = VD->getType().getNonReferenceType();
auto DVar = DSAStack->getTopDSA(VD, false);
if (DVar.CKind == OMPC_lastprivate) {
@@ -975,9 +1096,8 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
}
}
// Set initializers to private copies if no errors were found.
- if (PrivateCopies.size() == Clause->varlist_size()) {
+ if (PrivateCopies.size() == Clause->varlist_size())
Clause->setPrivateCopies(PrivateCopies);
- }
}
}
}
@@ -989,7 +1109,7 @@ void Sema::EndOpenMPDSABlock(Stmt *CurDirective) {
static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
Expr *NumIterations, Sema &SemaRef,
- Scope *S);
+ Scope *S, DSAStackTy *Stack);
namespace {
@@ -1009,6 +1129,23 @@ public:
return false;
}
};
+
+class VarOrFuncDeclFilterCCC : public CorrectionCandidateCallback {
+private:
+ Sema &SemaRef;
+
+public:
+ explicit VarOrFuncDeclFilterCCC(Sema &S) : SemaRef(S) {}
+ bool ValidateCandidate(const TypoCorrection &Candidate) override {
+ NamedDecl *ND = Candidate.getCorrectionDecl();
+ if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
+ return SemaRef.isDeclInScope(ND, SemaRef.getCurLexicalContext(),
+ SemaRef.getCurScope());
+ }
+ return false;
+ }
+};
+
} // namespace
ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
@@ -1131,8 +1268,10 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
}
QualType ExprType = VD->getType().getNonReferenceType();
- ExprResult DE = buildDeclRefExpr(*this, VD, ExprType, Id.getLoc());
- return DE;
+ return DeclRefExpr::Create(Context, NestedNameSpecifierLoc(),
+ SourceLocation(), VD,
+ /*RefersToEnclosingVariableOrCapture=*/false,
+ Id.getLoc(), ExprType, VK_LValue);
}
Sema::DeclGroupPtrTy
@@ -1142,7 +1281,7 @@ Sema::ActOnOpenMPThreadprivateDirective(SourceLocation Loc,
CurContext->addDecl(D);
return DeclGroupPtrTy::make(DeclGroupRef(D));
}
- return DeclGroupPtrTy();
+ return nullptr;
}
namespace {
@@ -1182,6 +1321,10 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
VarDecl *VD = cast<VarDecl>(DE->getDecl());
SourceLocation ILoc = DE->getExprLoc();
+ // Mark variable as used.
+ VD->setReferenced();
+ VD->markUsed(Context);
+
QualType QType = VD->getType();
if (QType->isDependentType() || QType->isInstantiationDependentType()) {
// It will be analyzed later.
@@ -1252,7 +1395,7 @@ Sema::CheckOMPThreadPrivateDecl(SourceLocation Loc, ArrayRef<Expr *> VarList) {
}
static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
- const VarDecl *VD, DSAStackTy::DSAVarData DVar,
+ const ValueDecl *D, DSAStackTy::DSAVarData DVar,
bool IsLoopIterVar = false) {
if (DVar.RefExpr) {
SemaRef.Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_explicit_dsa)
@@ -1272,7 +1415,8 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
PDSA_Implicit
} Reason = PDSA_Implicit;
bool ReportHint = false;
- auto ReportLoc = VD->getLocation();
+ auto ReportLoc = D->getLocation();
+ auto *VD = dyn_cast<VarDecl>(D);
if (IsLoopIterVar) {
if (DVar.CKind == OMPC_private)
Reason = PDSA_LoopIterVarPrivate;
@@ -1280,18 +1424,19 @@ static void ReportOriginalDSA(Sema &SemaRef, DSAStackTy *Stack,
Reason = PDSA_LoopIterVarLastprivate;
else
Reason = PDSA_LoopIterVarLinear;
- } else if (DVar.DKind == OMPD_task && DVar.CKind == OMPC_firstprivate) {
+ } else if (isOpenMPTaskingDirective(DVar.DKind) &&
+ DVar.CKind == OMPC_firstprivate) {
Reason = PDSA_TaskVarFirstprivate;
ReportLoc = DVar.ImplicitDSALoc;
- } else if (VD->isStaticLocal())
+ } else if (VD && VD->isStaticLocal())
Reason = PDSA_StaticLocalVarShared;
- else if (VD->isStaticDataMember())
+ else if (VD && VD->isStaticDataMember())
Reason = PDSA_StaticMemberShared;
- else if (VD->isFileVarDecl())
+ else if (VD && VD->isFileVarDecl())
Reason = PDSA_GlobalVarShared;
- else if (VD->getType().isConstant(SemaRef.getASTContext()))
+ else if (D->getType().isConstant(SemaRef.getASTContext()))
Reason = PDSA_ConstVarShared;
- else if (VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
+ else if (VD && VD->isLocalVarDecl() && DVar.CKind == OMPC_private) {
ReportHint = true;
Reason = PDSA_LocalVarPrivate;
}
@@ -1312,10 +1457,13 @@ class DSAAttrChecker : public StmtVisitor<DSAAttrChecker, void> {
bool ErrorFound;
CapturedStmt *CS;
llvm::SmallVector<Expr *, 8> ImplicitFirstprivate;
- llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA;
+ llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
public:
void VisitDeclRefExpr(DeclRefExpr *E) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
+ return;
if (auto *VD = dyn_cast<VarDecl>(E->getDecl())) {
// Skip internally declared variables.
if (VD->isLocalVarDecl() && !CS->capturesVariable(VD))
@@ -1342,14 +1490,14 @@ public:
// A list item that appears in a reduction clause of the innermost
// enclosing worksharing or parallel construct may not be accessed in an
// explicit task.
- DVar = Stack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K) ||
- isOpenMPTeamsDirective(K);
- },
- false);
- if (DKind == OMPD_task && DVar.CKind == OMPC_reduction) {
+ DVar = Stack->hasInnermostDSA(
+ VD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K) || isOpenMPTeamsDirective(K);
+ },
+ false);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
ErrorFound = true;
SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
ReportOriginalDSA(SemaRef, Stack, VD, DVar);
@@ -1358,10 +1506,52 @@ public:
// Define implicit data-sharing attributes for task.
DVar = Stack->getImplicitDSA(VD, false);
- if (DKind == OMPD_task && DVar.CKind != OMPC_shared)
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ !Stack->isLoopControlVariable(VD).first)
ImplicitFirstprivate.push_back(E);
}
}
+ void VisitMemberExpr(MemberExpr *E) {
+ if (E->isTypeDependent() || E->isValueDependent() ||
+ E->containsUnexpandedParameterPack() || E->isInstantiationDependent())
+ return;
+ if (isa<CXXThisExpr>(E->getBase()->IgnoreParens())) {
+ if (auto *FD = dyn_cast<FieldDecl>(E->getMemberDecl())) {
+ auto DVar = Stack->getTopDSA(FD, false);
+ // Check if the variable has explicit DSA set and stop analysis if it
+ // so.
+ if (DVar.RefExpr)
+ return;
+
+ auto ELoc = E->getExprLoc();
+ auto DKind = Stack->getCurrentDirective();
+ // OpenMP [2.9.3.6, Restrictions, p.2]
+ // A list item that appears in a reduction clause of the innermost
+ // enclosing worksharing or parallel construct may not be accessed in
+ // an explicit task.
+ DVar = Stack->hasInnermostDSA(
+ FD, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K) ||
+ isOpenMPTeamsDirective(K);
+ },
+ false);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind == OMPC_reduction) {
+ ErrorFound = true;
+ SemaRef.Diag(ELoc, diag::err_omp_reduction_in_task);
+ ReportOriginalDSA(SemaRef, Stack, FD, DVar);
+ return;
+ }
+
+ // Define implicit data-sharing attributes for task.
+ DVar = Stack->getImplicitDSA(FD, false);
+ if (isOpenMPTaskingDirective(DKind) && DVar.CKind != OMPC_shared &&
+ !Stack->isLoopControlVariable(FD).first)
+ ImplicitFirstprivate.push_back(E);
+ }
+ }
+ }
void VisitOMPExecutableDirective(OMPExecutableDirective *S) {
for (auto *C : S->clauses()) {
// Skip analysis of arguments of implicitly defined firstprivate clause
@@ -1382,7 +1572,7 @@ public:
bool isErrorFound() { return ErrorFound; }
ArrayRef<Expr *> getImplicitFirstprivate() { return ImplicitFirstprivate; }
- llvm::DenseMap<VarDecl *, Expr *> &getVarsWithInheritedDSA() {
+ llvm::DenseMap<ValueDecl *, Expr *> &getVarsWithInheritedDSA() {
return VarsWithInheritedDSA;
}
@@ -1393,84 +1583,11 @@ public:
void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
switch (DKind) {
- case OMPD_parallel: {
- QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
- QualType KmpInt32PtrTy =
- Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(".global_tid.", KmpInt32PtrTy),
- std::make_pair(".bound_tid.", KmpInt32PtrTy),
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_simd: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_for: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_for_simd: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_sections: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_section: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_single: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_master: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_critical: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_parallel_for: {
+ case OMPD_parallel:
+ case OMPD_parallel_for:
+ case OMPD_parallel_for_simd:
+ case OMPD_parallel_sections:
+ case OMPD_teams: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
@@ -1483,46 +1600,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
- case OMPD_parallel_for_simd: {
- QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
- QualType KmpInt32PtrTy =
- Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ case OMPD_simd:
+ case OMPD_for:
+ case OMPD_for_simd:
+ case OMPD_sections:
+ case OMPD_section:
+ case OMPD_single:
+ case OMPD_master:
+ case OMPD_critical:
+ case OMPD_taskgroup:
+ case OMPD_distribute:
+ case OMPD_ordered:
+ case OMPD_atomic:
+ case OMPD_target_data:
+ case OMPD_target:
+ case OMPD_target_parallel:
+ case OMPD_target_parallel_for:
+ case OMPD_target_parallel_for_simd: {
Sema::CapturedParamNameType Params[] = {
- std::make_pair(".global_tid.", KmpInt32PtrTy),
- std::make_pair(".bound_tid.", KmpInt32PtrTy),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
break;
}
- case OMPD_parallel_sections: {
+ case OMPD_task: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
- QualType KmpInt32PtrTy =
- Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
+ QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()};
+ FunctionProtoType::ExtProtoInfo EPI;
+ EPI.Variadic = true;
+ QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
- std::make_pair(".global_tid.", KmpInt32PtrTy),
- std::make_pair(".bound_tid.", KmpInt32PtrTy),
+ std::make_pair(".global_tid.", KmpInt32Ty),
+ std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)),
+ std::make_pair(".privates.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".copy_fn.",
+ Context.getPointerType(CopyFnType).withConst()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
Params);
+ // Mark this captured region as inlined, because we don't use outlined
+ // function directly.
+ getCurCapturedRegion()->TheCapturedDecl->addAttr(
+ AlwaysInlineAttr::CreateImplicit(
+ Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange()));
break;
}
- case OMPD_task: {
- QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
+ case OMPD_taskloop:
+ case OMPD_taskloop_simd: {
+ QualType KmpInt32Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/32, /*Signed=*/1);
+ QualType KmpUInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
+ QualType KmpInt64Ty =
+ Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
QualType Args[] = {Context.VoidPtrTy.withConst().withRestrict()};
FunctionProtoType::ExtProtoInfo EPI;
EPI.Variadic = true;
QualType CopyFnType = Context.getFunctionType(Context.VoidTy, Args, EPI);
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32Ty),
- std::make_pair(".part_id.", KmpInt32Ty),
+ std::make_pair(".part_id.", Context.getPointerType(KmpInt32Ty)),
std::make_pair(".privates.",
Context.VoidPtrTy.withConst().withRestrict()),
std::make_pair(
".copy_fn.",
Context.getPointerType(CopyFnType).withConst().withRestrict()),
+ std::make_pair(".task_t.", Context.VoidPtrTy.withConst()),
+ std::make_pair(".lb.", KmpUInt64Ty),
+ std::make_pair(".ub.", KmpUInt64Ty), std::make_pair(".st.", KmpInt64Ty),
+ std::make_pair(".liter.", KmpInt32Ty),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1534,70 +1683,17 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Context, AlwaysInlineAttr::Keyword_forceinline, SourceRange()));
break;
}
- case OMPD_ordered: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_atomic: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_target_data:
- case OMPD_target: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_teams: {
+ case OMPD_distribute_parallel_for_simd:
+ case OMPD_distribute_simd:
+ case OMPD_distribute_parallel_for: {
QualType KmpInt32Ty = Context.getIntTypeForBitwidth(32, 1);
QualType KmpInt32PtrTy =
Context.getPointerType(KmpInt32Ty).withConst().withRestrict();
Sema::CapturedParamNameType Params[] = {
std::make_pair(".global_tid.", KmpInt32PtrTy),
std::make_pair(".bound_tid.", KmpInt32PtrTy),
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_taskgroup: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_taskloop: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_taskloop_simd: {
- Sema::CapturedParamNameType Params[] = {
- std::make_pair(StringRef(), QualType()) // __context with shared vars
- };
- ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
- Params);
- break;
- }
- case OMPD_distribute: {
- Sema::CapturedParamNameType Params[] = {
+ std::make_pair(".previous.lb.", Context.getSizeType()),
+ std::make_pair(".previous.ub.", Context.getSizeType()),
std::make_pair(StringRef(), QualType()) // __context with shared vars
};
ActOnCapturedRegionStart(DSAStack->getConstructLoc(), CurScope, CR_OpenMP,
@@ -1611,12 +1707,78 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_flush:
+ case OMPD_target_enter_data:
+ case OMPD_target_exit_data:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
+ case OMPD_target_update:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
}
}
+static OMPCapturedExprDecl *buildCaptureDecl(Sema &S, IdentifierInfo *Id,
+ Expr *CaptureExpr, bool WithInit,
+ bool AsExpression) {
+ assert(CaptureExpr);
+ ASTContext &C = S.getASTContext();
+ Expr *Init = AsExpression ? CaptureExpr : CaptureExpr->IgnoreImpCasts();
+ QualType Ty = Init->getType();
+ if (CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue()) {
+ if (S.getLangOpts().CPlusPlus)
+ Ty = C.getLValueReferenceType(Ty);
+ else {
+ Ty = C.getPointerType(Ty);
+ ExprResult Res =
+ S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_AddrOf, Init);
+ if (!Res.isUsable())
+ return nullptr;
+ Init = Res.get();
+ }
+ WithInit = true;
+ }
+ auto *CED = OMPCapturedExprDecl::Create(C, S.CurContext, Id, Ty);
+ if (!WithInit)
+ CED->addAttr(OMPCaptureNoInitAttr::CreateImplicit(C, SourceRange()));
+ S.CurContext->addHiddenDecl(CED);
+ S.AddInitializerToDecl(CED, Init, /*DirectInit=*/false,
+ /*TypeMayContainAuto=*/true);
+ return CED;
+}
+
+static DeclRefExpr *buildCapture(Sema &S, ValueDecl *D, Expr *CaptureExpr,
+ bool WithInit) {
+ OMPCapturedExprDecl *CD;
+ if (auto *VD = S.IsOpenMPCapturedDecl(D))
+ CD = cast<OMPCapturedExprDecl>(VD);
+ else
+ CD = buildCaptureDecl(S, D->getIdentifier(), CaptureExpr, WithInit,
+ /*AsExpression=*/false);
+ return buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
+ CaptureExpr->getExprLoc());
+}
+
+static ExprResult buildCapture(Sema &S, Expr *CaptureExpr, DeclRefExpr *&Ref) {
+ if (!Ref) {
+ auto *CD =
+ buildCaptureDecl(S, &S.getASTContext().Idents.get(".capture_expr."),
+ CaptureExpr, /*WithInit=*/true, /*AsExpression=*/true);
+ Ref = buildDeclRefExpr(S, CD, CD->getType().getNonReferenceType(),
+ CaptureExpr->getExprLoc());
+ }
+ ExprResult Res = Ref;
+ if (!S.getLangOpts().CPlusPlus &&
+ CaptureExpr->getObjectKind() == OK_Ordinary && CaptureExpr->isGLValue() &&
+ Ref->getType()->isPointerType())
+ Res = S.CreateBuiltinUnaryOp(CaptureExpr->getExprLoc(), UO_Deref, Ref);
+ if (!Res.isUsable())
+ return ExprError();
+ return CaptureExpr->isGLValue() ? Res : S.DefaultLvalueConversion(Res.get());
+}
+
StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
ArrayRef<OMPClause *> Clauses) {
if (!S.isUsable()) {
@@ -1642,14 +1804,20 @@ StmtResult Sema::ActOnOpenMPRegionEnd(StmtResult S,
}
}
DSAStack->setForceVarCapturing(/*V=*/false);
- } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) &&
- Clause->getClauseKind() == OMPC_schedule) {
+ } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
// Mark all variables in private list clauses as used in inner region.
// Required for proper codegen of combined directives.
// TODO: add processing for other clauses.
- if (auto *E = cast_or_null<Expr>(
- cast<OMPScheduleClause>(Clause)->getHelperChunkSize()))
- MarkDeclarationsReferencedInExpr(E);
+ if (auto *C = OMPClauseWithPreInit::get(Clause)) {
+ if (auto *DS = cast_or_null<DeclStmt>(C->getPreInitStmt())) {
+ for (auto *D : DS->decls())
+ MarkVariableReferenced(D->getLocation(), cast<VarDecl>(D));
+ }
+ }
+ if (auto *C = OMPClauseWithPostUpdate::get(Clause)) {
+ if (auto *E = C->getPostUpdateExpr())
+ MarkDeclarationsReferencedInExpr(E);
+ }
}
if (Clause->getClauseKind() == OMPC_schedule)
SC = cast<OMPScheduleClause>(Clause);
@@ -1725,13 +1893,25 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel | ordered | + |
// | parallel | atomic | * |
// | parallel | target | * |
+ // | parallel | target parallel | * |
+ // | parallel | target parallel | * |
+ // | | for | |
+ // | parallel | target enter | * |
+ // | | data | |
+ // | parallel | target exit | * |
+ // | | data | |
// | parallel | teams | + |
// | parallel | cancellation | |
// | | point | ! |
// | parallel | cancel | ! |
// | parallel | taskloop | * |
// | parallel | taskloop simd | * |
- // | parallel | distribute | |
+ // | parallel | distribute | + |
+ // | parallel | distribute | + |
+ // | | parallel for | |
+ // | parallel | distribute | + |
+ // | |parallel for simd| |
+ // | parallel | distribute simd | + |
// +------------------+-----------------+------------------------------------+
// | for | parallel | * |
// | for | for | + |
@@ -1754,13 +1934,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | for | ordered | * (if construct is ordered) |
// | for | atomic | * |
// | for | target | * |
+ // | for | target parallel | * |
+ // | for | target parallel | * |
+ // | | for | |
+ // | for | target enter | * |
+ // | | data | |
+ // | for | target exit | * |
+ // | | data | |
// | for | teams | + |
// | for | cancellation | |
// | | point | ! |
// | for | cancel | ! |
// | for | taskloop | * |
// | for | taskloop simd | * |
- // | for | distribute | |
+ // | for | distribute | + |
+ // | for | distribute | + |
+ // | | parallel for | |
+ // | for | distribute | + |
+ // | |parallel for simd| |
+ // | for | distribute simd | + |
+ // | for | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | master | parallel | * |
// | master | for | + |
@@ -1783,13 +1977,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | master | ordered | + |
// | master | atomic | * |
// | master | target | * |
+ // | master | target parallel | * |
+ // | master | target parallel | * |
+ // | | for | |
+ // | master | target enter | * |
+ // | | data | |
+ // | master | target exit | * |
+ // | | data | |
// | master | teams | + |
// | master | cancellation | |
// | | point | |
// | master | cancel | |
// | master | taskloop | * |
// | master | taskloop simd | * |
- // | master | distribute | |
+ // | master | distribute | + |
+ // | master | distribute | + |
+ // | | parallel for | |
+ // | master | distribute | + |
+ // | |parallel for simd| |
+ // | master | distribute simd | + |
+ // | master | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | critical | parallel | * |
// | critical | for | + |
@@ -1811,20 +2019,34 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | critical | ordered | + |
// | critical | atomic | * |
// | critical | target | * |
+ // | critical | target parallel | * |
+ // | critical | target parallel | * |
+ // | | for | |
+ // | critical | target enter | * |
+ // | | data | |
+ // | critical | target exit | * |
+ // | | data | |
// | critical | teams | + |
// | critical | cancellation | |
// | | point | |
// | critical | cancel | |
// | critical | taskloop | * |
// | critical | taskloop simd | * |
- // | critical | distribute | |
+ // | critical | distribute | + |
+ // | critical | distribute | + |
+ // | | parallel for | |
+ // | critical | distribute | + |
+ // | |parallel for simd| |
+ // | critical | distribute simd | + |
+ // | critical | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | simd | parallel | |
// | simd | for | |
// | simd | for simd | |
// | simd | master | |
// | simd | critical | |
- // | simd | simd | |
+ // | simd | simd | * |
// | simd | sections | |
// | simd | section | |
// | simd | single | |
@@ -1840,6 +2062,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | simd | ordered | + (with simd clause) |
// | simd | atomic | |
// | simd | target | |
+ // | simd | target parallel | |
+ // | simd | target parallel | |
+ // | | for | |
+ // | simd | target enter | |
+ // | | data | |
+ // | simd | target exit | |
+ // | | data | |
// | simd | teams | |
// | simd | cancellation | |
// | | point | |
@@ -1847,13 +2076,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | simd | taskloop | |
// | simd | taskloop simd | |
// | simd | distribute | |
+ // | simd | distribute | |
+ // | | parallel for | |
+ // | simd | distribute | |
+ // | |parallel for simd| |
+ // | simd | distribute simd | |
+ // | simd | target parallel | |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | for simd | parallel | |
// | for simd | for | |
// | for simd | for simd | |
// | for simd | master | |
// | for simd | critical | |
- // | for simd | simd | |
+ // | for simd | simd | * |
// | for simd | sections | |
// | for simd | section | |
// | for simd | single | |
@@ -1869,6 +2105,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | for simd | ordered | + (with simd clause) |
// | for simd | atomic | |
// | for simd | target | |
+ // | for simd | target parallel | |
+ // | for simd | target parallel | |
+ // | | for | |
+ // | for simd | target enter | |
+ // | | data | |
+ // | for simd | target exit | |
+ // | | data | |
// | for simd | teams | |
// | for simd | cancellation | |
// | | point | |
@@ -1876,13 +2119,20 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | for simd | taskloop | |
// | for simd | taskloop simd | |
// | for simd | distribute | |
+ // | for simd | distribute | |
+ // | | parallel for | |
+ // | for simd | distribute | |
+ // | |parallel for simd| |
+ // | for simd | distribute simd | |
+ // | for simd | target parallel | |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | parallel for simd| parallel | |
// | parallel for simd| for | |
// | parallel for simd| for simd | |
// | parallel for simd| master | |
// | parallel for simd| critical | |
- // | parallel for simd| simd | |
+ // | parallel for simd| simd | * |
// | parallel for simd| sections | |
// | parallel for simd| section | |
// | parallel for simd| single | |
@@ -1898,6 +2148,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel for simd| ordered | + (with simd clause) |
// | parallel for simd| atomic | |
// | parallel for simd| target | |
+ // | parallel for simd| target parallel | |
+ // | parallel for simd| target parallel | |
+ // | | for | |
+ // | parallel for simd| target enter | |
+ // | | data | |
+ // | parallel for simd| target exit | |
+ // | | data | |
// | parallel for simd| teams | |
// | parallel for simd| cancellation | |
// | | point | |
@@ -1905,6 +2162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel for simd| taskloop | |
// | parallel for simd| taskloop simd | |
// | parallel for simd| distribute | |
+ // | parallel for simd| distribute | |
+ // | | parallel for | |
+ // | parallel for simd| distribute | |
+ // | |parallel for simd| |
+ // | parallel for simd| distribute simd | |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | sections | parallel | * |
// | sections | for | + |
@@ -1927,13 +2190,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | sections | ordered | + |
// | sections | atomic | * |
// | sections | target | * |
+ // | sections | target parallel | * |
+ // | sections | target parallel | * |
+ // | | for | |
+ // | sections | target enter | * |
+ // | | data | |
+ // | sections | target exit | * |
+ // | | data | |
// | sections | teams | + |
// | sections | cancellation | |
// | | point | ! |
// | sections | cancel | ! |
// | sections | taskloop | * |
// | sections | taskloop simd | * |
- // | sections | distribute | |
+ // | sections | distribute | + |
+ // | sections | distribute | + |
+ // | | parallel for | |
+ // | sections | distribute | + |
+ // | |parallel for simd| |
+ // | sections | distribute simd | + |
+ // | sections | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | section | parallel | * |
// | section | for | + |
@@ -1956,13 +2233,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | section | ordered | + |
// | section | atomic | * |
// | section | target | * |
+ // | section | target parallel | * |
+ // | section | target parallel | * |
+ // | | for | |
+ // | section | target enter | * |
+ // | | data | |
+ // | section | target exit | * |
+ // | | data | |
// | section | teams | + |
// | section | cancellation | |
// | | point | ! |
// | section | cancel | ! |
// | section | taskloop | * |
// | section | taskloop simd | * |
- // | section | distribute | |
+ // | section | distribute | + |
+ // | section | distribute | + |
+ // | | parallel for | |
+ // | section | distribute | + |
+ // | |parallel for simd| |
+ // | section | distribute simd | + |
+ // | section | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | single | parallel | * |
// | single | for | + |
@@ -1985,13 +2276,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | single | ordered | + |
// | single | atomic | * |
// | single | target | * |
+ // | single | target parallel | * |
+ // | single | target parallel | * |
+ // | | for | |
+ // | single | target enter | * |
+ // | | data | |
+ // | single | target exit | * |
+ // | | data | |
// | single | teams | + |
// | single | cancellation | |
// | | point | |
// | single | cancel | |
// | single | taskloop | * |
// | single | taskloop simd | * |
- // | single | distribute | |
+ // | single | distribute | + |
+ // | single | distribute | + |
+ // | | parallel for | |
+ // | single | distribute | + |
+ // | |parallel for simd| |
+ // | single | distribute simd | + |
+ // | single | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | parallel for | parallel | * |
// | parallel for | for | + |
@@ -2014,13 +2319,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel for | ordered | * (if construct is ordered) |
// | parallel for | atomic | * |
// | parallel for | target | * |
+ // | parallel for | target parallel | * |
+ // | parallel for | target parallel | * |
+ // | | for | |
+ // | parallel for | target enter | * |
+ // | | data | |
+ // | parallel for | target exit | * |
+ // | | data | |
// | parallel for | teams | + |
// | parallel for | cancellation | |
// | | point | ! |
// | parallel for | cancel | ! |
// | parallel for | taskloop | * |
// | parallel for | taskloop simd | * |
- // | parallel for | distribute | |
+ // | parallel for | distribute | + |
+ // | parallel for | distribute | + |
+ // | | parallel for | |
+ // | parallel for | distribute | + |
+ // | |parallel for simd| |
+ // | parallel for | distribute simd | + |
+ // | parallel for | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | parallel sections| parallel | * |
// | parallel sections| for | + |
@@ -2043,13 +2362,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | parallel sections| ordered | + |
// | parallel sections| atomic | * |
// | parallel sections| target | * |
+ // | parallel sections| target parallel | * |
+ // | parallel sections| target parallel | * |
+ // | | for | |
+ // | parallel sections| target enter | * |
+ // | | data | |
+ // | parallel sections| target exit | * |
+ // | | data | |
// | parallel sections| teams | + |
// | parallel sections| cancellation | |
// | | point | ! |
// | parallel sections| cancel | ! |
// | parallel sections| taskloop | * |
// | parallel sections| taskloop simd | * |
- // | parallel sections| distribute | |
+ // | parallel sections| distribute | + |
+ // | parallel sections| distribute | + |
+ // | | parallel for | |
+ // | parallel sections| distribute | + |
+ // | |parallel for simd| |
+ // | parallel sections| distribute simd | + |
+ // | parallel sections| target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | task | parallel | * |
// | task | for | + |
@@ -2072,13 +2405,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | task | ordered | + |
// | task | atomic | * |
// | task | target | * |
+ // | task | target parallel | * |
+ // | task | target parallel | * |
+ // | | for | |
+ // | task | target enter | * |
+ // | | data | |
+ // | task | target exit | * |
+ // | | data | |
// | task | teams | + |
// | task | cancellation | |
// | | point | ! |
// | task | cancel | ! |
// | task | taskloop | * |
// | task | taskloop simd | * |
- // | task | distribute | |
+ // | task | distribute | + |
+ // | task | distribute | + |
+ // | | parallel for | |
+ // | task | distribute | + |
+ // | |parallel for simd| |
+ // | task | distribute simd | + |
+ // | task | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | ordered | parallel | * |
// | ordered | for | + |
@@ -2101,13 +2448,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | ordered | ordered | + |
// | ordered | atomic | * |
// | ordered | target | * |
+ // | ordered | target parallel | * |
+ // | ordered | target parallel | * |
+ // | | for | |
+ // | ordered | target enter | * |
+ // | | data | |
+ // | ordered | target exit | * |
+ // | | data | |
// | ordered | teams | + |
// | ordered | cancellation | |
// | | point | |
// | ordered | cancel | |
// | ordered | taskloop | * |
// | ordered | taskloop simd | * |
- // | ordered | distribute | |
+ // | ordered | distribute | + |
+ // | ordered | distribute | + |
+ // | | parallel for | |
+ // | ordered | distribute | + |
+ // | |parallel for simd| |
+ // | ordered | distribute simd | + |
+ // | ordered | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | atomic | parallel | |
// | atomic | for | |
@@ -2130,13 +2491,27 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | atomic | ordered | |
// | atomic | atomic | |
// | atomic | target | |
+ // | atomic | target parallel | |
+ // | atomic | target parallel | |
+ // | | for | |
+ // | atomic | target enter | |
+ // | | data | |
+ // | atomic | target exit | |
+ // | | data | |
// | atomic | teams | |
// | atomic | cancellation | |
// | | point | |
// | atomic | cancel | |
// | atomic | taskloop | |
// | atomic | taskloop simd | |
- // | atomic | distribute | |
+ // | atomic | distribute | |
+ // | atomic | distribute | |
+ // | | parallel for | |
+ // | atomic | distribute | |
+ // | |parallel for simd| |
+ // | atomic | distribute simd | |
+ // | atomic | target parallel | |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | target | parallel | * |
// | target | for | * |
@@ -2158,14 +2533,142 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | target | flush | * |
// | target | ordered | * |
// | target | atomic | * |
- // | target | target | * |
+ // | target | target | |
+ // | target | target parallel | |
+ // | target | target parallel | |
+ // | | for | |
+ // | target | target enter | |
+ // | | data | |
+ // | target | target exit | |
+ // | | data | |
// | target | teams | * |
// | target | cancellation | |
// | | point | |
// | target | cancel | |
// | target | taskloop | * |
// | target | taskloop simd | * |
- // | target | distribute | |
+ // | target | distribute | + |
+ // | target | distribute | + |
+ // | | parallel for | |
+ // | target | distribute | + |
+ // | |parallel for simd| |
+ // | target | distribute simd | + |
+ // | target | target parallel | |
+ // | | for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | target parallel | parallel | * |
+ // | target parallel | for | * |
+ // | target parallel | for simd | * |
+ // | target parallel | master | * |
+ // | target parallel | critical | * |
+ // | target parallel | simd | * |
+ // | target parallel | sections | * |
+ // | target parallel | section | * |
+ // | target parallel | single | * |
+ // | target parallel | parallel for | * |
+ // | target parallel |parallel for simd| * |
+ // | target parallel |parallel sections| * |
+ // | target parallel | task | * |
+ // | target parallel | taskyield | * |
+ // | target parallel | barrier | * |
+ // | target parallel | taskwait | * |
+ // | target parallel | taskgroup | * |
+ // | target parallel | flush | * |
+ // | target parallel | ordered | * |
+ // | target parallel | atomic | * |
+ // | target parallel | target | |
+ // | target parallel | target parallel | |
+ // | target parallel | target parallel | |
+ // | | for | |
+ // | target parallel | target enter | |
+ // | | data | |
+ // | target parallel | target exit | |
+ // | | data | |
+ // | target parallel | teams | |
+ // | target parallel | cancellation | |
+ // | | point | ! |
+ // | target parallel | cancel | ! |
+ // | target parallel | taskloop | * |
+ // | target parallel | taskloop simd | * |
+ // | target parallel | distribute | |
+ // | target parallel | distribute | |
+ // | | parallel for | |
+ // | target parallel | distribute | |
+ // | |parallel for simd| |
+ // | target parallel | distribute simd | |
+ // | target parallel | target parallel | |
+ // | | for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | target parallel | parallel | * |
+ // | for | | |
+ // | target parallel | for | * |
+ // | for | | |
+ // | target parallel | for simd | * |
+ // | for | | |
+ // | target parallel | master | * |
+ // | for | | |
+ // | target parallel | critical | * |
+ // | for | | |
+ // | target parallel | simd | * |
+ // | for | | |
+ // | target parallel | sections | * |
+ // | for | | |
+ // | target parallel | section | * |
+ // | for | | |
+ // | target parallel | single | * |
+ // | for | | |
+ // | target parallel | parallel for | * |
+ // | for | | |
+ // | target parallel |parallel for simd| * |
+ // | for | | |
+ // | target parallel |parallel sections| * |
+ // | for | | |
+ // | target parallel | task | * |
+ // | for | | |
+ // | target parallel | taskyield | * |
+ // | for | | |
+ // | target parallel | barrier | * |
+ // | for | | |
+ // | target parallel | taskwait | * |
+ // | for | | |
+ // | target parallel | taskgroup | * |
+ // | for | | |
+ // | target parallel | flush | * |
+ // | for | | |
+ // | target parallel | ordered | * |
+ // | for | | |
+ // | target parallel | atomic | * |
+ // | for | | |
+ // | target parallel | target | |
+ // | for | | |
+ // | target parallel | target parallel | |
+ // | for | | |
+ // | target parallel | target parallel | |
+ // | for | for | |
+ // | target parallel | target enter | |
+ // | for | data | |
+ // | target parallel | target exit | |
+ // | for | data | |
+ // | target parallel | teams | |
+ // | for | | |
+ // | target parallel | cancellation | |
+ // | for | point | ! |
+ // | target parallel | cancel | ! |
+ // | for | | |
+ // | target parallel | taskloop | * |
+ // | for | | |
+ // | target parallel | taskloop simd | * |
+ // | for | | |
+ // | target parallel | distribute | |
+ // | for | | |
+ // | target parallel | distribute | |
+ // | for | parallel for | |
+ // | target parallel | distribute | |
+ // | for |parallel for simd| |
+ // | target parallel | distribute simd | |
+ // | for | | |
+ // | target parallel | target parallel | |
+ // | for | for simd | |
// +------------------+-----------------+------------------------------------+
// | teams | parallel | * |
// | teams | for | + |
@@ -2188,6 +2691,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | teams | ordered | + |
// | teams | atomic | + |
// | teams | target | + |
+ // | teams | target parallel | + |
+ // | teams | target parallel | + |
+ // | | for | |
+ // | teams | target enter | + |
+ // | | data | |
+ // | teams | target exit | + |
+ // | | data | |
// | teams | teams | + |
// | teams | cancellation | |
// | | point | |
@@ -2195,6 +2705,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | teams | taskloop | + |
// | teams | taskloop simd | + |
// | teams | distribute | ! |
+ // | teams | distribute | ! |
+ // | | parallel for | |
+ // | teams | distribute | ! |
+ // | |parallel for simd| |
+ // | teams | distribute simd | ! |
+ // | teams | target parallel | + |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | taskloop | parallel | * |
// | taskloop | for | + |
@@ -2217,19 +2734,33 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | taskloop | ordered | + |
// | taskloop | atomic | * |
// | taskloop | target | * |
+ // | taskloop | target parallel | * |
+ // | taskloop | target parallel | * |
+ // | | for | |
+ // | taskloop | target enter | * |
+ // | | data | |
+ // | taskloop | target exit | * |
+ // | | data | |
// | taskloop | teams | + |
// | taskloop | cancellation | |
// | | point | |
// | taskloop | cancel | |
// | taskloop | taskloop | * |
- // | taskloop | distribute | |
+ // | taskloop | distribute | + |
+ // | taskloop | distribute | + |
+ // | | parallel for | |
+ // | taskloop | distribute | + |
+ // | |parallel for simd| |
+ // | taskloop | distribute simd | + |
+ // | taskloop | target parallel | * |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | taskloop simd | parallel | |
// | taskloop simd | for | |
// | taskloop simd | for simd | |
// | taskloop simd | master | |
// | taskloop simd | critical | |
- // | taskloop simd | simd | |
+ // | taskloop simd | simd | * |
// | taskloop simd | sections | |
// | taskloop simd | section | |
// | taskloop simd | single | |
@@ -2245,6 +2776,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | taskloop simd | ordered | + (with simd clause) |
// | taskloop simd | atomic | |
// | taskloop simd | target | |
+ // | taskloop simd | target parallel | |
+ // | taskloop simd | target parallel | |
+ // | | for | |
+ // | taskloop simd | target enter | |
+ // | | data | |
+ // | taskloop simd | target exit | |
+ // | | data | |
// | taskloop simd | teams | |
// | taskloop simd | cancellation | |
// | | point | |
@@ -2252,6 +2790,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | taskloop simd | taskloop | |
// | taskloop simd | taskloop simd | |
// | taskloop simd | distribute | |
+ // | taskloop simd | distribute | |
+ // | | parallel for | |
+ // | taskloop simd | distribute | |
+ // | |parallel for simd| |
+ // | taskloop simd | distribute simd | |
+ // | taskloop simd | target parallel | |
+ // | | for simd | |
// +------------------+-----------------+------------------------------------+
// | distribute | parallel | * |
// | distribute | for | * |
@@ -2274,6 +2819,13 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | distribute | ordered | + |
// | distribute | atomic | * |
// | distribute | target | |
+ // | distribute | target parallel | |
+ // | distribute | target parallel | |
+ // | | for | |
+ // | distribute | target enter | |
+ // | | data | |
+ // | distribute | target exit | |
+ // | | data | |
// | distribute | teams | |
// | distribute | cancellation | + |
// | | point | |
@@ -2281,9 +2833,274 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// | distribute | taskloop | * |
// | distribute | taskloop simd | * |
// | distribute | distribute | |
+ // | distribute | distribute | |
+ // | | parallel for | |
+ // | distribute | distribute | |
+ // | |parallel for simd| |
+ // | distribute | distribute simd | |
+ // | distribute | target parallel | |
+ // | | for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | distribute | parallel | * |
+ // | parallel for | | |
+ // | distribute | for | * |
+ // | parallel for | | |
+ // | distribute | for simd | * |
+ // | parallel for | | |
+ // | distribute | master | * |
+ // | parallel for | | |
+ // | distribute | critical | * |
+ // | parallel for | | |
+ // | distribute | simd | * |
+ // | parallel for | | |
+ // | distribute | sections | * |
+ // | parallel for | | |
+ // | distribute | section | * |
+ // | parallel for | | |
+ // | distribute | single | * |
+ // | parallel for | | |
+ // | distribute | parallel for | * |
+ // | parallel for | | |
+ // | distribute |parallel for simd| * |
+ // | parallel for | | |
+ // | distribute |parallel sections| * |
+ // | parallel for | | |
+ // | distribute | task | * |
+ // | parallel for | | |
+ // | parallel for | | |
+ // | distribute | taskyield | * |
+ // | parallel for | | |
+ // | distribute | barrier | * |
+ // | parallel for | | |
+ // | distribute | taskwait | * |
+ // | parallel for | | |
+ // | distribute | taskgroup | * |
+ // | parallel for | | |
+ // | distribute | flush | * |
+ // | parallel for | | |
+ // | distribute | ordered | + |
+ // | parallel for | | |
+ // | distribute | atomic | * |
+ // | parallel for | | |
+ // | distribute | target | |
+ // | parallel for | | |
+ // | distribute | target parallel | |
+ // | parallel for | | |
+ // | distribute | target parallel | |
+ // | parallel for | for | |
+ // | distribute | target enter | |
+ // | parallel for | data | |
+ // | distribute | target exit | |
+ // | parallel for | data | |
+ // | distribute | teams | |
+ // | parallel for | | |
+ // | distribute | cancellation | + |
+ // | parallel for | point | |
+ // | distribute | cancel | + |
+ // | parallel for | | |
+ // | distribute | taskloop | * |
+ // | parallel for | | |
+ // | distribute | taskloop simd | * |
+ // | parallel for | | |
+ // | distribute | distribute | |
+ // | parallel for | | |
+ // | distribute | distribute | |
+ // | parallel for | parallel for | |
+ // | distribute | distribute | |
+ // | parallel for |parallel for simd| |
+ // | distribute | distribute simd | |
+ // | parallel for | | |
+ // | distribute | target parallel | |
+ // | parallel for | for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | distribute | parallel | * |
+ // | parallel for simd| | |
+ // | distribute | for | * |
+ // | parallel for simd| | |
+ // | distribute | for simd | * |
+ // | parallel for simd| | |
+ // | distribute | master | * |
+ // | parallel for simd| | |
+ // | distribute | critical | * |
+ // | parallel for simd| | |
+ // | distribute | simd | * |
+ // | parallel for simd| | |
+ // | distribute | sections | * |
+ // | parallel for simd| | |
+ // | distribute | section | * |
+ // | parallel for simd| | |
+ // | distribute | single | * |
+ // | parallel for simd| | |
+ // | distribute | parallel for | * |
+ // | parallel for simd| | |
+ // | distribute |parallel for simd| * |
+ // | parallel for simd| | |
+ // | distribute |parallel sections| * |
+ // | parallel for simd| | |
+ // | distribute | task | * |
+ // | parallel for simd| | |
+ // | distribute | taskyield | * |
+ // | parallel for simd| | |
+ // | distribute | barrier | * |
+ // | parallel for simd| | |
+ // | distribute | taskwait | * |
+ // | parallel for simd| | |
+ // | distribute | taskgroup | * |
+ // | parallel for simd| | |
+ // | distribute | flush | * |
+ // | parallel for simd| | |
+ // | distribute | ordered | + |
+ // | parallel for simd| | |
+ // | distribute | atomic | * |
+ // | parallel for simd| | |
+ // | distribute | target | |
+ // | parallel for simd| | |
+ // | distribute | target parallel | |
+ // | parallel for simd| | |
+ // | distribute | target parallel | |
+ // | parallel for simd| for | |
+ // | distribute | target enter | |
+ // | parallel for simd| data | |
+ // | distribute | target exit | |
+ // | parallel for simd| data | |
+ // | distribute | teams | |
+ // | parallel for simd| | |
+ // | distribute | cancellation | + |
+ // | parallel for simd| point | |
+ // | distribute | cancel | + |
+ // | parallel for simd| | |
+ // | distribute | taskloop | * |
+ // | parallel for simd| | |
+ // | distribute | taskloop simd | * |
+ // | parallel for simd| | |
+ // | distribute | distribute | |
+ // | parallel for simd| | |
+ // | distribute | distribute | * |
+ // | parallel for simd| parallel for | |
+ // | distribute | distribute | * |
+ // | parallel for simd|parallel for simd| |
+ // | distribute | distribute simd | * |
+ // | parallel for simd| | |
+ // | distribute | target parallel | |
+ // | parallel for simd| for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | distribute simd | parallel | * |
+ // | distribute simd | for | * |
+ // | distribute simd | for simd | * |
+ // | distribute simd | master | * |
+ // | distribute simd | critical | * |
+ // | distribute simd | simd | * |
+ // | distribute simd | sections | * |
+ // | distribute simd | section | * |
+ // | distribute simd | single | * |
+ // | distribute simd | parallel for | * |
+ // | distribute simd |parallel for simd| * |
+ // | distribute simd |parallel sections| * |
+ // | distribute simd | task | * |
+ // | distribute simd | taskyield | * |
+ // | distribute simd | barrier | * |
+ // | distribute simd | taskwait | * |
+ // | distribute simd | taskgroup | * |
+ // | distribute simd | flush | * |
+ // | distribute simd | ordered | + |
+ // | distribute simd | atomic | * |
+ // | distribute simd | target | * |
+ // | distribute simd | target parallel | * |
+ // | distribute simd | target parallel | * |
+ // | | for | |
+ // | distribute simd | target enter | * |
+ // | | data | |
+ // | distribute simd | target exit | * |
+ // | | data | |
+ // | distribute simd | teams | * |
+ // | distribute simd | cancellation | + |
+ // | | point | |
+ // | distribute simd | cancel | + |
+ // | distribute simd | taskloop | * |
+ // | distribute simd | taskloop simd | * |
+ // | distribute simd | distribute | |
+ // | distribute simd | distribute | * |
+ // | | parallel for | |
+ // | distribute simd | distribute | * |
+ // | |parallel for simd| |
+ // | distribute simd | distribute simd | * |
+ // | distribute simd | target parallel | * |
+ // | | for simd | |
+ // +------------------+-----------------+------------------------------------+
+ // | target parallel | parallel | * |
+ // | for simd | | |
+ // | target parallel | for | * |
+ // | for simd | | |
+ // | target parallel | for simd | * |
+ // | for simd | | |
+ // | target parallel | master | * |
+ // | for simd | | |
+ // | target parallel | critical | * |
+ // | for simd | | |
+ // | target parallel | simd | ! |
+ // | for simd | | |
+ // | target parallel | sections | * |
+ // | for simd | | |
+ // | target parallel | section | * |
+ // | for simd | | |
+ // | target parallel | single | * |
+ // | for simd | | |
+ // | target parallel | parallel for | * |
+ // | for simd | | |
+ // | target parallel |parallel for simd| * |
+ // | for simd | | |
+ // | target parallel |parallel sections| * |
+ // | for simd | | |
+ // | target parallel | task | * |
+ // | for simd | | |
+ // | target parallel | taskyield | * |
+ // | for simd | | |
+ // | target parallel | barrier | * |
+ // | for simd | | |
+ // | target parallel | taskwait | * |
+ // | for simd | | |
+ // | target parallel | taskgroup | * |
+ // | for simd | | |
+ // | target parallel | flush | * |
+ // | for simd | | |
+ // | target parallel | ordered | + (with simd clause) |
+ // | for simd | | |
+ // | target parallel | atomic | * |
+ // | for simd | | |
+ // | target parallel | target | * |
+ // | for simd | | |
+ // | target parallel | target parallel | * |
+ // | for simd | | |
+ // | target parallel | target parallel | * |
+ // | for simd | for | |
+ // | target parallel | target enter | * |
+ // | for simd | data | |
+ // | target parallel | target exit | * |
+ // | for simd | data | |
+ // | target parallel | teams | * |
+ // | for simd | | |
+ // | target parallel | cancellation | * |
+ // | for simd | point | |
+ // | target parallel | cancel | * |
+ // | for simd | | |
+ // | target parallel | taskloop | * |
+ // | for simd | | |
+ // | target parallel | taskloop simd | * |
+ // | for simd | | |
+ // | target parallel | distribute | * |
+ // | for simd | | |
+ // | target parallel | distribute | * |
+ // | for simd | parallel for | |
+ // | target parallel | distribute | * |
+ // | for simd |parallel for simd| |
+ // | target parallel | distribute simd | * |
+ // | for simd | | |
+ // | target parallel | target parallel | * |
+ // | for simd | for simd | |
// +------------------+-----------------+------------------------------------+
if (Stack->getCurScope()) {
auto ParentRegion = Stack->getParentDirective();
+ auto OffendingRegion = ParentRegion;
bool NestingProhibited = false;
bool CloseNesting = true;
enum {
@@ -2297,10 +3114,15 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// OpenMP [2.16, Nesting of Regions]
// OpenMP constructs may not be nested inside a simd region.
// OpenMP [2.8.1,simd Construct, Restrictions]
- // An ordered construct with the simd clause is the only OpenMP construct
- // that can appear in the simd region.
- SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region_simd);
- return true;
+ // An ordered construct with the simd clause is the only OpenMP
+ // construct that can appear in the simd region.
+ // Allowing a SIMD consruct nested in another SIMD construct is an
+ // extension. The OpenMP 4.5 spec does not allow it. Issue a warning
+ // message.
+ SemaRef.Diag(StartLoc, (CurrentRegion != OMPD_simd)
+ ? diag::err_omp_prohibited_region_simd
+ : diag::warn_omp_nesting_simd);
+ return CurrentRegion != OMPD_simd;
}
if (ParentRegion == OMPD_atomic) {
// OpenMP [2.16, Nesting of Regions]
@@ -2340,9 +3162,12 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// OpenMP construct that matches the type specified in
// construct-type-clause.
NestingProhibited =
- !((CancelRegion == OMPD_parallel && ParentRegion == OMPD_parallel) ||
+ !((CancelRegion == OMPD_parallel &&
+ (ParentRegion == OMPD_parallel ||
+ ParentRegion == OMPD_target_parallel)) ||
(CancelRegion == OMPD_for &&
- (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for)) ||
+ (ParentRegion == OMPD_for || ParentRegion == OMPD_parallel_for ||
+ ParentRegion == OMPD_target_parallel_for)) ||
(CancelRegion == OMPD_taskgroup && ParentRegion == OMPD_task) ||
(CancelRegion == OMPD_sections &&
(ParentRegion == OMPD_section || ParentRegion == OMPD_sections ||
@@ -2352,8 +3177,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// A master region may not be closely nested inside a worksharing,
// atomic, or explicit task region.
NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
- ParentRegion == OMPD_task ||
- isOpenMPTaskLoopDirective(ParentRegion);
+ isOpenMPTaskingDirective(ParentRegion);
} else if (CurrentRegion == OMPD_critical && CurrentName.getName()) {
// OpenMP [2.16, Nesting of Regions]
// A critical region may not be nested (closely or otherwise) inside a
@@ -2387,21 +3211,21 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// OpenMP [2.16, Nesting of Regions]
// A barrier region may not be closely nested inside a worksharing,
// explicit task, critical, ordered, atomic, or master region.
- NestingProhibited =
- isOpenMPWorksharingDirective(ParentRegion) ||
- ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered ||
- isOpenMPTaskLoopDirective(ParentRegion);
+ NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
+ isOpenMPTaskingDirective(ParentRegion) ||
+ ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical ||
+ ParentRegion == OMPD_ordered;
} else if (isOpenMPWorksharingDirective(CurrentRegion) &&
!isOpenMPParallelDirective(CurrentRegion)) {
// OpenMP [2.16, Nesting of Regions]
// A worksharing region may not be closely nested inside a worksharing,
// explicit task, critical, ordered, atomic, or master region.
- NestingProhibited =
- isOpenMPWorksharingDirective(ParentRegion) ||
- ParentRegion == OMPD_task || ParentRegion == OMPD_master ||
- ParentRegion == OMPD_critical || ParentRegion == OMPD_ordered ||
- isOpenMPTaskLoopDirective(ParentRegion);
+ NestingProhibited = isOpenMPWorksharingDirective(ParentRegion) ||
+ isOpenMPTaskingDirective(ParentRegion) ||
+ ParentRegion == OMPD_master ||
+ ParentRegion == OMPD_critical ||
+ ParentRegion == OMPD_ordered;
Recommend = ShouldBeInParallelRegion;
} else if (CurrentRegion == OMPD_ordered) {
// OpenMP [2.16, Nesting of Regions]
@@ -2413,8 +3237,7 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
// An ordered construct with the simd clause is the only OpenMP construct
// that can appear in the simd region.
NestingProhibited = ParentRegion == OMPD_critical ||
- ParentRegion == OMPD_task ||
- isOpenMPTaskLoopDirective(ParentRegion) ||
+ isOpenMPTaskingDirective(ParentRegion) ||
!(isOpenMPSimdDirective(ParentRegion) ||
Stack->isParentOrderedRegion());
Recommend = ShouldBeInOrderedRegion;
@@ -2442,10 +3265,29 @@ static bool CheckNestingOfRegions(Sema &SemaRef, DSAStackTy *Stack,
NestingProhibited = !isOpenMPTeamsDirective(ParentRegion);
Recommend = ShouldBeInTeamsRegion;
}
+ if (!NestingProhibited &&
+ (isOpenMPTargetExecutionDirective(CurrentRegion) ||
+ isOpenMPTargetDataManagementDirective(CurrentRegion))) {
+ // OpenMP 4.5 [2.17 Nesting of Regions]
+ // If a target, target update, target data, target enter data, or
+ // target exit data construct is encountered during execution of a
+ // target region, the behavior is unspecified.
+ NestingProhibited = Stack->hasDirective(
+ [&OffendingRegion](OpenMPDirectiveKind K, const DeclarationNameInfo &,
+ SourceLocation) -> bool {
+ if (isOpenMPTargetExecutionDirective(K)) {
+ OffendingRegion = K;
+ return true;
+ } else
+ return false;
+ },
+ false /* don't skip top directive */);
+ CloseNesting = false;
+ }
if (NestingProhibited) {
SemaRef.Diag(StartLoc, diag::err_omp_prohibited_region)
- << CloseNesting << getOpenMPDirectiveName(ParentRegion) << Recommend
- << getOpenMPDirectiveName(CurrentRegion);
+ << CloseNesting << getOpenMPDirectiveName(OffendingRegion)
+ << Recommend << getOpenMPDirectiveName(CurrentRegion);
return true;
}
}
@@ -2544,7 +3386,7 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
return StmtError();
llvm::SmallVector<OMPClause *, 8> ClausesWithImplicit;
- llvm::DenseMap<VarDecl *, Expr *> VarsWithInheritedDSA;
+ llvm::DenseMap<ValueDecl *, Expr *> VarsWithInheritedDSA;
bool ErrorFound = false;
ClausesWithImplicit.append(Clauses.begin(), Clauses.end());
if (AStmt) {
@@ -2679,6 +3521,18 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc);
AllowedNameModifiers.push_back(OMPD_target);
break;
+ case OMPD_target_parallel:
+ Res = ActOnOpenMPTargetParallelDirective(ClausesWithImplicit, AStmt,
+ StartLoc, EndLoc);
+ AllowedNameModifiers.push_back(OMPD_target);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
+ case OMPD_target_parallel_for:
+ Res = ActOnOpenMPTargetParallelForDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_target);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
case OMPD_cancellation_point:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp cancellation point' directive");
@@ -2698,6 +3552,16 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
EndLoc);
AllowedNameModifiers.push_back(OMPD_target_data);
break;
+ case OMPD_target_enter_data:
+ Res = ActOnOpenMPTargetEnterDataDirective(ClausesWithImplicit, StartLoc,
+ EndLoc);
+ AllowedNameModifiers.push_back(OMPD_target_enter_data);
+ break;
+ case OMPD_target_exit_data:
+ Res = ActOnOpenMPTargetExitDataDirective(ClausesWithImplicit, StartLoc,
+ EndLoc);
+ AllowedNameModifiers.push_back(OMPD_target_exit_data);
+ break;
case OMPD_taskloop:
Res = ActOnOpenMPTaskLoopDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
@@ -2712,7 +3576,37 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPDistributeDirective(ClausesWithImplicit, AStmt, StartLoc,
EndLoc, VarsWithInheritedDSA);
break;
+ case OMPD_target_update:
+ assert(!AStmt && "Statement is not allowed for target update");
+ Res =
+ ActOnOpenMPTargetUpdateDirective(ClausesWithImplicit, StartLoc, EndLoc);
+ AllowedNameModifiers.push_back(OMPD_target_update);
+ break;
+ case OMPD_distribute_parallel_for:
+ Res = ActOnOpenMPDistributeParallelForDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
+ case OMPD_distribute_parallel_for_simd:
+ Res = ActOnOpenMPDistributeParallelForSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
+ case OMPD_distribute_simd:
+ Res = ActOnOpenMPDistributeSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ break;
+ case OMPD_target_parallel_for_simd:
+ Res = ActOnOpenMPTargetParallelForSimdDirective(
+ ClausesWithImplicit, AStmt, StartLoc, EndLoc, VarsWithInheritedDSA);
+ AllowedNameModifiers.push_back(OMPD_target);
+ AllowedNameModifiers.push_back(OMPD_parallel);
+ break;
+ case OMPD_declare_target:
+ case OMPD_end_declare_target:
case OMPD_threadprivate:
+ case OMPD_declare_reduction:
+ case OMPD_declare_simd:
llvm_unreachable("OpenMP Directive is not allowed");
case OMPD_unknown:
llvm_unreachable("Unknown OpenMP directive");
@@ -2733,6 +3627,252 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
return Res;
}
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareSimdDirective(
+ DeclGroupPtrTy DG, OMPDeclareSimdDeclAttr::BranchStateTy BS, Expr *Simdlen,
+ ArrayRef<Expr *> Uniforms, ArrayRef<Expr *> Aligneds,
+ ArrayRef<Expr *> Alignments, ArrayRef<Expr *> Linears,
+ ArrayRef<unsigned> LinModifiers, ArrayRef<Expr *> Steps, SourceRange SR) {
+ assert(Aligneds.size() == Alignments.size());
+ assert(Linears.size() == LinModifiers.size());
+ assert(Linears.size() == Steps.size());
+ if (!DG || DG.get().isNull())
+ return DeclGroupPtrTy();
+
+ if (!DG.get().isSingleDecl()) {
+ Diag(SR.getBegin(), diag::err_omp_single_decl_in_declare_simd);
+ return DG;
+ }
+ auto *ADecl = DG.get().getSingleDecl();
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(ADecl))
+ ADecl = FTD->getTemplatedDecl();
+
+ auto *FD = dyn_cast<FunctionDecl>(ADecl);
+ if (!FD) {
+ Diag(ADecl->getLocation(), diag::err_omp_function_expected);
+ return DeclGroupPtrTy();
+ }
+
+ // OpenMP [2.8.2, declare simd construct, Description]
+ // The parameter of the simdlen clause must be a constant positive integer
+ // expression.
+ ExprResult SL;
+ if (Simdlen)
+ SL = VerifyPositiveIntegerConstantInClause(Simdlen, OMPC_simdlen);
+ // OpenMP [2.8.2, declare simd construct, Description]
+ // The special this pointer can be used as if was one of the arguments to the
+ // function in any of the linear, aligned, or uniform clauses.
+ // The uniform clause declares one or more arguments to have an invariant
+ // value for all concurrent invocations of the function in the execution of a
+ // single SIMD loop.
+ llvm::DenseMap<Decl *, Expr *> UniformedArgs;
+ Expr *UniformedLinearThis = nullptr;
+ for (auto *E : Uniforms) {
+ E = E->IgnoreParenImpCasts();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl()))
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+ FD->getParamDecl(PVD->getFunctionScopeIndex())
+ ->getCanonicalDecl() == PVD->getCanonicalDecl()) {
+ UniformedArgs.insert(std::make_pair(PVD->getCanonicalDecl(), E));
+ continue;
+ }
+ if (isa<CXXThisExpr>(E)) {
+ UniformedLinearThis = E;
+ continue;
+ }
+ Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+ << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
+ }
+ // OpenMP [2.8.2, declare simd construct, Description]
+ // The aligned clause declares that the object to which each list item points
+ // is aligned to the number of bytes expressed in the optional parameter of
+ // the aligned clause.
+ // The special this pointer can be used as if was one of the arguments to the
+ // function in any of the linear, aligned, or uniform clauses.
+ // The type of list items appearing in the aligned clause must be array,
+ // pointer, reference to array, or reference to pointer.
+ llvm::DenseMap<Decl *, Expr *> AlignedArgs;
+ Expr *AlignedThis = nullptr;
+ for (auto *E : Aligneds) {
+ E = E->IgnoreParenImpCasts();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ auto *CanonPVD = PVD->getCanonicalDecl();
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+ FD->getParamDecl(PVD->getFunctionScopeIndex())
+ ->getCanonicalDecl() == CanonPVD) {
+ // OpenMP [2.8.1, simd construct, Restrictions]
+ // A list-item cannot appear in more than one aligned clause.
+ if (AlignedArgs.count(CanonPVD) > 0) {
+ Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
+ << 1 << E->getSourceRange();
+ Diag(AlignedArgs[CanonPVD]->getExprLoc(),
+ diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_aligned);
+ continue;
+ }
+ AlignedArgs[CanonPVD] = E;
+ QualType QTy = PVD->getType()
+ .getNonReferenceType()
+ .getUnqualifiedType()
+ .getCanonicalType();
+ const Type *Ty = QTy.getTypePtrOrNull();
+ if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
+ Diag(E->getExprLoc(), diag::err_omp_aligned_expected_array_or_ptr)
+ << QTy << getLangOpts().CPlusPlus << E->getSourceRange();
+ Diag(PVD->getLocation(), diag::note_previous_decl) << PVD;
+ }
+ continue;
+ }
+ }
+ if (isa<CXXThisExpr>(E)) {
+ if (AlignedThis) {
+ Diag(E->getExprLoc(), diag::err_omp_aligned_twice)
+ << 2 << E->getSourceRange();
+ Diag(AlignedThis->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_aligned);
+ }
+ AlignedThis = E;
+ continue;
+ }
+ Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+ << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
+ }
+ // The optional parameter of the aligned clause, alignment, must be a constant
+ // positive integer expression. If no optional parameter is specified,
+ // implementation-defined default alignments for SIMD instructions on the
+ // target platforms are assumed.
+ SmallVector<Expr *, 4> NewAligns;
+ for (auto *E : Alignments) {
+ ExprResult Align;
+ if (E)
+ Align = VerifyPositiveIntegerConstantInClause(E, OMPC_aligned);
+ NewAligns.push_back(Align.get());
+ }
+ // OpenMP [2.8.2, declare simd construct, Description]
+ // The linear clause declares one or more list items to be private to a SIMD
+ // lane and to have a linear relationship with respect to the iteration space
+ // of a loop.
+ // The special this pointer can be used as if was one of the arguments to the
+ // function in any of the linear, aligned, or uniform clauses.
+ // When a linear-step expression is specified in a linear clause it must be
+ // either a constant integer expression or an integer-typed parameter that is
+ // specified in a uniform clause on the directive.
+ llvm::DenseMap<Decl *, Expr *> LinearArgs;
+ const bool IsUniformedThis = UniformedLinearThis != nullptr;
+ auto MI = LinModifiers.begin();
+ for (auto *E : Linears) {
+ auto LinKind = static_cast<OpenMPLinearClauseKind>(*MI);
+ ++MI;
+ E = E->IgnoreParenImpCasts();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ auto *CanonPVD = PVD->getCanonicalDecl();
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex() &&
+ FD->getParamDecl(PVD->getFunctionScopeIndex())
+ ->getCanonicalDecl() == CanonPVD) {
+ // OpenMP [2.15.3.7, linear Clause, Restrictions]
+ // A list-item cannot appear in more than one linear clause.
+ if (LinearArgs.count(CanonPVD) > 0) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(OMPC_linear) << E->getSourceRange();
+ Diag(LinearArgs[CanonPVD]->getExprLoc(),
+ diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_linear);
+ continue;
+ }
+ // Each argument can appear in at most one uniform or linear clause.
+ if (UniformedArgs.count(CanonPVD) > 0) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(OMPC_uniform) << E->getSourceRange();
+ Diag(UniformedArgs[CanonPVD]->getExprLoc(),
+ diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(OMPC_uniform);
+ continue;
+ }
+ LinearArgs[CanonPVD] = E;
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() ||
+ E->containsUnexpandedParameterPack())
+ continue;
+ (void)CheckOpenMPLinearDecl(CanonPVD, E->getExprLoc(), LinKind,
+ PVD->getOriginalType());
+ continue;
+ }
+ }
+ if (isa<CXXThisExpr>(E)) {
+ if (UniformedLinearThis) {
+ Diag(E->getExprLoc(), diag::err_omp_wrong_dsa)
+ << getOpenMPClauseName(OMPC_linear)
+ << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform : OMPC_linear)
+ << E->getSourceRange();
+ Diag(UniformedLinearThis->getExprLoc(), diag::note_omp_explicit_dsa)
+ << getOpenMPClauseName(IsUniformedThis ? OMPC_uniform
+ : OMPC_linear);
+ continue;
+ }
+ UniformedLinearThis = E;
+ if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() || E->containsUnexpandedParameterPack())
+ continue;
+ (void)CheckOpenMPLinearDecl(/*D=*/nullptr, E->getExprLoc(), LinKind,
+ E->getType());
+ continue;
+ }
+ Diag(E->getExprLoc(), diag::err_omp_param_or_this_in_clause)
+ << FD->getDeclName() << (isa<CXXMethodDecl>(ADecl) ? 1 : 0);
+ }
+ Expr *Step = nullptr;
+ Expr *NewStep = nullptr;
+ SmallVector<Expr *, 4> NewSteps;
+ for (auto *E : Steps) {
+ // Skip the same step expression, it was checked already.
+ if (Step == E || !E) {
+ NewSteps.push_back(E ? NewStep : nullptr);
+ continue;
+ }
+ Step = E;
+ if (auto *DRE = dyn_cast<DeclRefExpr>(Step))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ auto *CanonPVD = PVD->getCanonicalDecl();
+ if (UniformedArgs.count(CanonPVD) == 0) {
+ Diag(Step->getExprLoc(), diag::err_omp_expected_uniform_param)
+ << Step->getSourceRange();
+ } else if (E->isValueDependent() || E->isTypeDependent() ||
+ E->isInstantiationDependent() ||
+ E->containsUnexpandedParameterPack() ||
+ CanonPVD->getType()->hasIntegerRepresentation())
+ NewSteps.push_back(Step);
+ else {
+ Diag(Step->getExprLoc(), diag::err_omp_expected_int_param)
+ << Step->getSourceRange();
+ }
+ continue;
+ }
+ NewStep = Step;
+ if (Step && !Step->isValueDependent() && !Step->isTypeDependent() &&
+ !Step->isInstantiationDependent() &&
+ !Step->containsUnexpandedParameterPack()) {
+ NewStep = PerformOpenMPImplicitIntegerConversion(Step->getExprLoc(), Step)
+ .get();
+ if (NewStep)
+ NewStep = VerifyIntegerConstantExpression(NewStep).get();
+ }
+ NewSteps.push_back(NewStep);
+ }
+ auto *NewAttr = OMPDeclareSimdDeclAttr::CreateImplicit(
+ Context, BS, SL.get(), const_cast<Expr **>(Uniforms.data()),
+ Uniforms.size(), const_cast<Expr **>(Aligneds.data()), Aligneds.size(),
+ const_cast<Expr **>(NewAligns.data()), NewAligns.size(),
+ const_cast<Expr **>(Linears.data()), Linears.size(),
+ const_cast<unsigned *>(LinModifiers.data()), LinModifiers.size(),
+ NewSteps.data(), NewSteps.size(), SR);
+ ADecl->addAttr(NewAttr);
+ return ConvertDeclToDeclGroup(ADecl);
+}
+
StmtResult Sema::ActOnOpenMPParallelDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -2772,33 +3912,29 @@ class OpenMPIterationSpaceChecker {
/// \brief A source location for referring to increment later.
SourceRange IncrementSrcRange;
/// \brief Loop variable.
- VarDecl *Var;
+ ValueDecl *LCDecl = nullptr;
/// \brief Reference to loop variable.
- DeclRefExpr *VarRef;
+ Expr *LCRef = nullptr;
/// \brief Lower bound (initializer for the var).
- Expr *LB;
+ Expr *LB = nullptr;
/// \brief Upper bound.
- Expr *UB;
+ Expr *UB = nullptr;
/// \brief Loop step (increment).
- Expr *Step;
+ Expr *Step = nullptr;
/// \brief This flag is true when condition is one of:
/// Var < UB
/// Var <= UB
/// UB > Var
/// UB >= Var
- bool TestIsLessOp;
+ bool TestIsLessOp = false;
/// \brief This flag is true when condition is strict ( < or > ).
- bool TestIsStrictOp;
+ bool TestIsStrictOp = false;
/// \brief This flag is true when step is subtracted on each iteration.
- bool SubtractStep;
+ bool SubtractStep = false;
public:
OpenMPIterationSpaceChecker(Sema &SemaRef, SourceLocation DefaultLoc)
- : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc),
- InitSrcRange(SourceRange()), ConditionSrcRange(SourceRange()),
- IncrementSrcRange(SourceRange()), Var(nullptr), VarRef(nullptr),
- LB(nullptr), UB(nullptr), Step(nullptr), TestIsLessOp(false),
- TestIsStrictOp(false), SubtractStep(false) {}
+ : SemaRef(SemaRef), DefaultLoc(DefaultLoc), ConditionLoc(DefaultLoc) {}
/// \brief Check init-expr for canonical loop form and save loop counter
/// variable - #Var and its initialization value - #LB.
bool CheckInit(Stmt *S, bool EmitDiags = true);
@@ -2809,9 +3945,9 @@ public:
/// does not conform, otherwise save loop step (#Step).
bool CheckInc(Expr *S);
/// \brief Return the loop counter variable.
- VarDecl *GetLoopVar() const { return Var; }
+ ValueDecl *GetLoopDecl() const { return LCDecl; }
/// \brief Return the reference expression to loop counter variable.
- DeclRefExpr *GetLoopVarRefExpr() const { return VarRef; }
+ Expr *GetLoopDeclRefExpr() const { return LCRef; }
/// \brief Source range of the loop init.
SourceRange GetInitSrcRange() const { return InitSrcRange; }
/// \brief Source range of the loop condition.
@@ -2821,11 +3957,15 @@ public:
/// \brief True if the step should be subtracted.
bool ShouldSubtractStep() const { return SubtractStep; }
/// \brief Build the expression to calculate the number of iterations.
- Expr *BuildNumIterations(Scope *S, const bool LimitedType) const;
+ Expr *
+ BuildNumIterations(Scope *S, const bool LimitedType,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const;
/// \brief Build the precondition expression for the loops.
- Expr *BuildPreCond(Scope *S, Expr *Cond) const;
+ Expr *BuildPreCond(Scope *S, Expr *Cond,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const;
/// \brief Build reference expression to the counter be used for codegen.
- Expr *BuildCounterVar() const;
+ DeclRefExpr *BuildCounterVar(llvm::MapVector<Expr *, DeclRefExpr *> &Captures,
+ DSAStackTy &DSA) const;
/// \brief Build reference expression to the private counter be used for
/// codegen.
Expr *BuildPrivateCounterVar() const;
@@ -2841,7 +3981,7 @@ private:
/// expression.
bool CheckIncRHS(Expr *RHS);
/// \brief Helper to set loop counter variable and its initializer.
- bool SetVarAndLB(VarDecl *NewVar, DeclRefExpr *NewVarRefExpr, Expr *NewLB);
+ bool SetLCDeclAndLB(ValueDecl *NewLCDecl, Expr *NewDeclRefExpr, Expr *NewLB);
/// \brief Helper to set upper bound.
bool SetUB(Expr *NewUB, bool LessOp, bool StrictOp, SourceRange SR,
SourceLocation SL);
@@ -2850,16 +3990,16 @@ private:
};
bool OpenMPIterationSpaceChecker::Dependent() const {
- if (!Var) {
+ if (!LCDecl) {
assert(!LB && !UB && !Step);
return false;
}
- return Var->getType()->isDependentType() || (LB && LB->isValueDependent()) ||
- (UB && UB->isValueDependent()) || (Step && Step->isValueDependent());
+ return LCDecl->getType()->isDependentType() ||
+ (LB && LB->isValueDependent()) || (UB && UB->isValueDependent()) ||
+ (Step && Step->isValueDependent());
}
-template <typename T>
-static T *getExprAsWritten(T *E) {
+static Expr *getExprAsWritten(Expr *E) {
if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(E))
E = ExprTemp->getSubExpr();
@@ -2874,16 +4014,16 @@ static T *getExprAsWritten(T *E) {
return E->IgnoreParens();
}
-bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar,
- DeclRefExpr *NewVarRefExpr,
- Expr *NewLB) {
+bool OpenMPIterationSpaceChecker::SetLCDeclAndLB(ValueDecl *NewLCDecl,
+ Expr *NewLCRefExpr,
+ Expr *NewLB) {
// State consistency checking to ensure correct usage.
- assert(Var == nullptr && LB == nullptr && VarRef == nullptr &&
+ assert(LCDecl == nullptr && LB == nullptr && LCRef == nullptr &&
UB == nullptr && Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
- if (!NewVar || !NewLB)
+ if (!NewLCDecl || !NewLB)
return true;
- Var = NewVar;
- VarRef = NewVarRefExpr;
+ LCDecl = getCanonicalDecl(NewLCDecl);
+ LCRef = NewLCRefExpr;
if (auto *CE = dyn_cast_or_null<CXXConstructExpr>(NewLB))
if (const CXXConstructorDecl *Ctor = CE->getConstructor())
if ((Ctor->isCopyOrMoveConstructor() ||
@@ -2897,8 +4037,8 @@ bool OpenMPIterationSpaceChecker::SetVarAndLB(VarDecl *NewVar,
bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp,
SourceRange SR, SourceLocation SL) {
// State consistency checking to ensure correct usage.
- assert(Var != nullptr && LB != nullptr && UB == nullptr && Step == nullptr &&
- !TestIsLessOp && !TestIsStrictOp);
+ assert(LCDecl != nullptr && LB != nullptr && UB == nullptr &&
+ Step == nullptr && !TestIsLessOp && !TestIsStrictOp);
if (!NewUB)
return true;
UB = NewUB;
@@ -2911,7 +4051,7 @@ bool OpenMPIterationSpaceChecker::SetUB(Expr *NewUB, bool LessOp, bool StrictOp,
bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
// State consistency checking to ensure correct usage.
- assert(Var != nullptr && LB != nullptr && Step == nullptr);
+ assert(LCDecl != nullptr && LB != nullptr && Step == nullptr);
if (!NewStep)
return true;
if (!NewStep->isValueDependent()) {
@@ -2947,7 +4087,7 @@ bool OpenMPIterationSpaceChecker::SetStep(Expr *NewStep, bool Subtract) {
: (IsConstPos || (IsUnsigned && !Subtract))))) {
SemaRef.Diag(NewStep->getExprLoc(),
diag::err_omp_loop_incr_not_compatible)
- << Var << TestIsLessOp << NewStep->getSourceRange();
+ << LCDecl << TestIsLessOp << NewStep->getSourceRange();
SemaRef.Diag(ConditionLoc,
diag::note_omp_loop_cond_requres_compatible_incr)
<< TestIsLessOp << ConditionSrcRange;
@@ -2980,14 +4120,28 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) {
}
return true;
}
+ if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S))
+ if (!ExprTemp->cleanupsHaveSideEffects())
+ S = ExprTemp->getSubExpr();
+
InitSrcRange = S->getSourceRange();
if (Expr *E = dyn_cast<Expr>(S))
S = E->IgnoreParens();
if (auto BO = dyn_cast<BinaryOperator>(S)) {
- if (BO->getOpcode() == BO_Assign)
- if (auto DRE = dyn_cast<DeclRefExpr>(BO->getLHS()->IgnoreParens()))
- return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE,
- BO->getRHS());
+ if (BO->getOpcode() == BO_Assign) {
+ auto *LHS = BO->getLHS()->IgnoreParens();
+ if (auto *DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
+ if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return SetLCDeclAndLB(DRE->getDecl(), DRE, BO->getRHS());
+ }
+ if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
+ if (ME->isArrow() &&
+ isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
+ return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ }
+ }
} else if (auto DS = dyn_cast<DeclStmt>(S)) {
if (DS->isSingleDecl()) {
if (auto Var = dyn_cast_or_null<VarDecl>(DS->getSingleDecl())) {
@@ -2997,16 +4151,29 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) {
SemaRef.Diag(S->getLocStart(),
diag::ext_omp_loop_not_canonical_init)
<< S->getSourceRange();
- return SetVarAndLB(Var, nullptr, Var->getInit());
+ return SetLCDeclAndLB(Var, nullptr, Var->getInit());
}
}
}
- } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S))
- if (CE->getOperator() == OO_Equal)
- if (auto DRE = dyn_cast<DeclRefExpr>(CE->getArg(0)))
- return SetVarAndLB(dyn_cast<VarDecl>(DRE->getDecl()), DRE,
- CE->getArg(1));
+ } else if (auto CE = dyn_cast<CXXOperatorCallExpr>(S)) {
+ if (CE->getOperator() == OO_Equal) {
+ auto *LHS = CE->getArg(0);
+ if (auto DRE = dyn_cast<DeclRefExpr>(LHS)) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(DRE->getDecl()))
+ if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ return SetLCDeclAndLB(DRE->getDecl(), DRE, CE->getArg(1));
+ }
+ if (auto *ME = dyn_cast<MemberExpr>(LHS)) {
+ if (ME->isArrow() &&
+ isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
+ return SetLCDeclAndLB(ME->getMemberDecl(), ME, BO->getRHS());
+ }
+ }
+ }
+ if (Dependent() || SemaRef.CurContext->isDependentContext())
+ return false;
if (EmitDiags) {
SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_init)
<< S->getSourceRange();
@@ -3016,7 +4183,7 @@ bool OpenMPIterationSpaceChecker::CheckInit(Stmt *S, bool EmitDiags) {
/// \brief Ignore parenthesizes, implicit casts, copy constructor and return the
/// variable (which may be the loop variable) if possible.
-static const VarDecl *GetInitVarDecl(const Expr *E) {
+static const ValueDecl *GetInitLCDecl(Expr *E) {
if (!E)
return nullptr;
E = getExprAsWritten(E);
@@ -3026,10 +4193,18 @@ static const VarDecl *GetInitVarDecl(const Expr *E) {
Ctor->isConvertingConstructor(/*AllowExplicit=*/false)) &&
CE->getNumArgs() > 0 && CE->getArg(0) != nullptr)
E = CE->getArg(0)->IgnoreParenImpCasts();
- auto DRE = dyn_cast_or_null<DeclRefExpr>(E);
- if (!DRE)
- return nullptr;
- return dyn_cast<VarDecl>(DRE->getDecl());
+ if (auto *DRE = dyn_cast_or_null<DeclRefExpr>(E)) {
+ if (auto *VD = dyn_cast<VarDecl>(DRE->getDecl())) {
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(VD))
+ if (auto *ME = dyn_cast<MemberExpr>(getExprAsWritten(CED->getInit())))
+ return getCanonicalDecl(ME->getMemberDecl());
+ return getCanonicalDecl(VD);
+ }
+ }
+ if (auto *ME = dyn_cast_or_null<MemberExpr>(E))
+ if (ME->isArrow() && isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()))
+ return getCanonicalDecl(ME->getMemberDecl());
+ return nullptr;
}
bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
@@ -3040,19 +4215,19 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
// b relational-op var
//
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << Var;
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_cond) << LCDecl;
return true;
}
S = getExprAsWritten(S);
SourceLocation CondLoc = S->getLocStart();
if (auto BO = dyn_cast<BinaryOperator>(S)) {
if (BO->isRelationalOp()) {
- if (GetInitVarDecl(BO->getLHS()) == Var)
+ if (GetInitLCDecl(BO->getLHS()) == LCDecl)
return SetUB(BO->getRHS(),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_LE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
BO->getSourceRange(), BO->getOperatorLoc());
- if (GetInitVarDecl(BO->getRHS()) == Var)
+ if (GetInitLCDecl(BO->getRHS()) == LCDecl)
return SetUB(BO->getLHS(),
(BO->getOpcode() == BO_GT || BO->getOpcode() == BO_GE),
(BO->getOpcode() == BO_LT || BO->getOpcode() == BO_GT),
@@ -3066,11 +4241,11 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
case OO_GreaterEqual:
case OO_Less:
case OO_LessEqual:
- if (GetInitVarDecl(CE->getArg(0)) == Var)
+ if (GetInitLCDecl(CE->getArg(0)) == LCDecl)
return SetUB(CE->getArg(1), Op == OO_Less || Op == OO_LessEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
- if (GetInitVarDecl(CE->getArg(1)) == Var)
+ if (GetInitLCDecl(CE->getArg(1)) == LCDecl)
return SetUB(CE->getArg(0), Op == OO_Greater || Op == OO_GreaterEqual,
Op == OO_Less || Op == OO_Greater, CE->getSourceRange(),
CE->getOperatorLoc());
@@ -3080,8 +4255,10 @@ bool OpenMPIterationSpaceChecker::CheckCond(Expr *S) {
}
}
}
+ if (Dependent() || SemaRef.CurContext->isDependentContext())
+ return false;
SemaRef.Diag(CondLoc, diag::err_omp_loop_not_canonical_cond)
- << S->getSourceRange() << Var;
+ << S->getSourceRange() << LCDecl;
return true;
}
@@ -3095,22 +4272,24 @@ bool OpenMPIterationSpaceChecker::CheckIncRHS(Expr *RHS) {
if (auto BO = dyn_cast<BinaryOperator>(RHS)) {
if (BO->isAdditiveOp()) {
bool IsAdd = BO->getOpcode() == BO_Add;
- if (GetInitVarDecl(BO->getLHS()) == Var)
+ if (GetInitLCDecl(BO->getLHS()) == LCDecl)
return SetStep(BO->getRHS(), !IsAdd);
- if (IsAdd && GetInitVarDecl(BO->getRHS()) == Var)
+ if (IsAdd && GetInitLCDecl(BO->getRHS()) == LCDecl)
return SetStep(BO->getLHS(), false);
}
} else if (auto CE = dyn_cast<CXXOperatorCallExpr>(RHS)) {
bool IsAdd = CE->getOperator() == OO_Plus;
if ((IsAdd || CE->getOperator() == OO_Minus) && CE->getNumArgs() == 2) {
- if (GetInitVarDecl(CE->getArg(0)) == Var)
+ if (GetInitLCDecl(CE->getArg(0)) == LCDecl)
return SetStep(CE->getArg(1), !IsAdd);
- if (IsAdd && GetInitVarDecl(CE->getArg(1)) == Var)
+ if (IsAdd && GetInitLCDecl(CE->getArg(1)) == LCDecl)
return SetStep(CE->getArg(0), false);
}
}
+ if (Dependent() || SemaRef.CurContext->isDependentContext())
+ return false;
SemaRef.Diag(RHS->getLocStart(), diag::err_omp_loop_not_canonical_incr)
- << RHS->getSourceRange() << Var;
+ << RHS->getSourceRange() << LCDecl;
return true;
}
@@ -3129,13 +4308,18 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
// var = var - incr
//
if (!S) {
- SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << Var;
+ SemaRef.Diag(DefaultLoc, diag::err_omp_loop_not_canonical_incr) << LCDecl;
return true;
}
+ if (auto *ExprTemp = dyn_cast<ExprWithCleanups>(S))
+ if (!ExprTemp->cleanupsHaveSideEffects())
+ S = ExprTemp->getSubExpr();
+
IncrementSrcRange = S->getSourceRange();
S = S->IgnoreParens();
if (auto UO = dyn_cast<UnaryOperator>(S)) {
- if (UO->isIncrementDecrementOp() && GetInitVarDecl(UO->getSubExpr()) == Var)
+ if (UO->isIncrementDecrementOp() &&
+ GetInitLCDecl(UO->getSubExpr()) == LCDecl)
return SetStep(
SemaRef.ActOnIntegerConstant(UO->getLocStart(),
(UO->isDecrementOp() ? -1 : 1)).get(),
@@ -3144,11 +4328,11 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
switch (BO->getOpcode()) {
case BO_AddAssign:
case BO_SubAssign:
- if (GetInitVarDecl(BO->getLHS()) == Var)
+ if (GetInitLCDecl(BO->getLHS()) == LCDecl)
return SetStep(BO->getRHS(), BO->getOpcode() == BO_SubAssign);
break;
case BO_Assign:
- if (GetInitVarDecl(BO->getLHS()) == Var)
+ if (GetInitLCDecl(BO->getLHS()) == LCDecl)
return CheckIncRHS(BO->getRHS());
break;
default:
@@ -3158,7 +4342,7 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
switch (CE->getOperator()) {
case OO_PlusPlus:
case OO_MinusMinus:
- if (GetInitVarDecl(CE->getArg(0)) == Var)
+ if (GetInitLCDecl(CE->getArg(0)) == LCDecl)
return SetStep(
SemaRef.ActOnIntegerConstant(
CE->getLocStart(),
@@ -3167,103 +4351,55 @@ bool OpenMPIterationSpaceChecker::CheckInc(Expr *S) {
break;
case OO_PlusEqual:
case OO_MinusEqual:
- if (GetInitVarDecl(CE->getArg(0)) == Var)
+ if (GetInitLCDecl(CE->getArg(0)) == LCDecl)
return SetStep(CE->getArg(1), CE->getOperator() == OO_MinusEqual);
break;
case OO_Equal:
- if (GetInitVarDecl(CE->getArg(0)) == Var)
+ if (GetInitLCDecl(CE->getArg(0)) == LCDecl)
return CheckIncRHS(CE->getArg(1));
break;
default:
break;
}
}
+ if (Dependent() || SemaRef.CurContext->isDependentContext())
+ return false;
SemaRef.Diag(S->getLocStart(), diag::err_omp_loop_not_canonical_incr)
- << S->getSourceRange() << Var;
+ << S->getSourceRange() << LCDecl;
return true;
}
-namespace {
-// Transform variables declared in GNU statement expressions to new ones to
-// avoid crash on codegen.
-class TransformToNewDefs : public TreeTransform<TransformToNewDefs> {
- typedef TreeTransform<TransformToNewDefs> BaseTransform;
-
-public:
- TransformToNewDefs(Sema &SemaRef) : BaseTransform(SemaRef) {}
-
- Decl *TransformDefinition(SourceLocation Loc, Decl *D) {
- if (auto *VD = cast<VarDecl>(D))
- if (!isa<ParmVarDecl>(D) && !isa<VarTemplateSpecializationDecl>(D) &&
- !isa<ImplicitParamDecl>(D)) {
- auto *NewVD = VarDecl::Create(
- SemaRef.Context, VD->getDeclContext(), VD->getLocStart(),
- VD->getLocation(), VD->getIdentifier(), VD->getType(),
- VD->getTypeSourceInfo(), VD->getStorageClass());
- NewVD->setTSCSpec(VD->getTSCSpec());
- NewVD->setInit(VD->getInit());
- NewVD->setInitStyle(VD->getInitStyle());
- NewVD->setExceptionVariable(VD->isExceptionVariable());
- NewVD->setNRVOVariable(VD->isNRVOVariable());
- NewVD->setCXXForRangeDecl(VD->isCXXForRangeDecl());
- NewVD->setConstexpr(VD->isConstexpr());
- NewVD->setInitCapture(VD->isInitCapture());
- NewVD->setPreviousDeclInSameBlockScope(
- VD->isPreviousDeclInSameBlockScope());
- VD->getDeclContext()->addHiddenDecl(NewVD);
- if (VD->hasAttrs())
- NewVD->setAttrs(VD->getAttrs());
- transformedLocalDecl(VD, NewVD);
- return NewVD;
- }
- return BaseTransform::TransformDefinition(Loc, D);
- }
-
- ExprResult TransformDeclRefExpr(DeclRefExpr *E) {
- if (auto *NewD = TransformDecl(E->getExprLoc(), E->getDecl()))
- if (E->getDecl() != NewD) {
- NewD->setReferenced();
- NewD->markUsed(SemaRef.Context);
- return DeclRefExpr::Create(
- SemaRef.Context, E->getQualifierLoc(), E->getTemplateKeywordLoc(),
- cast<ValueDecl>(NewD), E->refersToEnclosingVariableOrCapture(),
- E->getNameInfo(), E->getType(), E->getValueKind());
- }
- return BaseTransform::TransformDeclRefExpr(E);
- }
-};
+static ExprResult
+tryBuildCapture(Sema &SemaRef, Expr *Capture,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
+ if (SemaRef.CurContext->isDependentContext())
+ return ExprResult(Capture);
+ if (Capture->isEvaluatable(SemaRef.Context, Expr::SE_AllowSideEffects))
+ return SemaRef.PerformImplicitConversion(
+ Capture->IgnoreImpCasts(), Capture->getType(), Sema::AA_Converting,
+ /*AllowExplicit=*/true);
+ auto I = Captures.find(Capture);
+ if (I != Captures.end())
+ return buildCapture(SemaRef, Capture, I->second);
+ DeclRefExpr *Ref = nullptr;
+ ExprResult Res = buildCapture(SemaRef, Capture, Ref);
+ Captures[Capture] = Ref;
+ return Res;
}
/// \brief Build the expression to calculate the number of iterations.
-Expr *
-OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S,
- const bool LimitedType) const {
- TransformToNewDefs Transform(SemaRef);
+Expr *OpenMPIterationSpaceChecker::BuildNumIterations(
+ Scope *S, const bool LimitedType,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const {
ExprResult Diff;
- auto VarType = Var->getType().getNonReferenceType();
+ auto VarType = LCDecl->getType().getNonReferenceType();
if (VarType->isIntegerType() || VarType->isPointerType() ||
SemaRef.getLangOpts().CPlusPlus) {
// Upper - Lower
auto *UBExpr = TestIsLessOp ? UB : LB;
auto *LBExpr = TestIsLessOp ? LB : UB;
- Expr *Upper = Transform.TransformExpr(UBExpr).get();
- Expr *Lower = Transform.TransformExpr(LBExpr).get();
- if (!Upper || !Lower)
- return nullptr;
- if (!SemaRef.Context.hasSameType(Upper->getType(), UBExpr->getType())) {
- Upper = SemaRef
- .PerformImplicitConversion(Upper, UBExpr->getType(),
- Sema::AA_Converting,
- /*AllowExplicit=*/true)
- .get();
- }
- if (!SemaRef.Context.hasSameType(Lower->getType(), LBExpr->getType())) {
- Lower = SemaRef
- .PerformImplicitConversion(Lower, LBExpr->getType(),
- Sema::AA_Converting,
- /*AllowExplicit=*/true)
- .get();
- }
+ Expr *Upper = tryBuildCapture(SemaRef, UBExpr, Captures).get();
+ Expr *Lower = tryBuildCapture(SemaRef, LBExpr, Captures).get();
if (!Upper || !Lower)
return nullptr;
@@ -3290,18 +4426,9 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S,
return nullptr;
// Upper - Lower [- 1] + Step
- auto *StepNoImp = Step->IgnoreImplicit();
- auto NewStep = Transform.TransformExpr(StepNoImp);
- if (NewStep.isInvalid())
+ auto NewStep = tryBuildCapture(SemaRef, Step, Captures);
+ if (!NewStep.isUsable())
return nullptr;
- if (!SemaRef.Context.hasSameType(NewStep.get()->getType(),
- StepNoImp->getType())) {
- NewStep = SemaRef.PerformImplicitConversion(
- NewStep.get(), StepNoImp->getType(), Sema::AA_Converting,
- /*AllowExplicit=*/true);
- if (NewStep.isInvalid())
- return nullptr;
- }
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Add, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
@@ -3312,17 +4439,6 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S,
return nullptr;
// (Upper - Lower [- 1] + Step) / Step
- NewStep = Transform.TransformExpr(StepNoImp);
- if (NewStep.isInvalid())
- return nullptr;
- if (!SemaRef.Context.hasSameType(NewStep.get()->getType(),
- StepNoImp->getType())) {
- NewStep = SemaRef.PerformImplicitConversion(
- NewStep.get(), StepNoImp->getType(), Sema::AA_Converting,
- /*AllowExplicit=*/true);
- if (NewStep.isInvalid())
- return nullptr;
- }
Diff = SemaRef.BuildBinOp(S, DefaultLoc, BO_Div, Diff.get(), NewStep.get());
if (!Diff.isUsable())
return nullptr;
@@ -3368,35 +4484,25 @@ OpenMPIterationSpaceChecker::BuildNumIterations(Scope *S,
return Diff.get();
}
-Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const {
+Expr *OpenMPIterationSpaceChecker::BuildPreCond(
+ Scope *S, Expr *Cond,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) const {
// Try to build LB <op> UB, where <op> is <, >, <=, or >=.
bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
- TransformToNewDefs Transform(SemaRef);
-
- auto NewLB = Transform.TransformExpr(LB);
- auto NewUB = Transform.TransformExpr(UB);
- if (NewLB.isInvalid() || NewUB.isInvalid())
- return Cond;
- if (!SemaRef.Context.hasSameType(NewLB.get()->getType(), LB->getType())) {
- NewLB = SemaRef.PerformImplicitConversion(NewLB.get(), LB->getType(),
- Sema::AA_Converting,
- /*AllowExplicit=*/true);
- }
- if (!SemaRef.Context.hasSameType(NewUB.get()->getType(), UB->getType())) {
- NewUB = SemaRef.PerformImplicitConversion(NewUB.get(), UB->getType(),
- Sema::AA_Converting,
- /*AllowExplicit=*/true);
- }
- if (NewLB.isInvalid() || NewUB.isInvalid())
- return Cond;
+
+ auto NewLB = tryBuildCapture(SemaRef, LB, Captures);
+ auto NewUB = tryBuildCapture(SemaRef, UB, Captures);
+ if (!NewLB.isUsable() || !NewUB.isUsable())
+ return nullptr;
+
auto CondExpr = SemaRef.BuildBinOp(
S, DefaultLoc, TestIsLessOp ? (TestIsStrictOp ? BO_LT : BO_LE)
: (TestIsStrictOp ? BO_GT : BO_GE),
NewLB.get(), NewUB.get());
if (CondExpr.isUsable()) {
- if (!SemaRef.Context.hasSameType(CondExpr.get()->getType(),
- SemaRef.Context.BoolTy))
+ if (!SemaRef.Context.hasSameUnqualifiedType(CondExpr.get()->getType(),
+ SemaRef.Context.BoolTy))
CondExpr = SemaRef.PerformImplicitConversion(
CondExpr.get(), SemaRef.Context.BoolTy, /*Action=*/Sema::AA_Casting,
/*AllowExplicit=*/true);
@@ -3407,17 +4513,30 @@ Expr *OpenMPIterationSpaceChecker::BuildPreCond(Scope *S, Expr *Cond) const {
}
/// \brief Build reference expression to the counter be used for codegen.
-Expr *OpenMPIterationSpaceChecker::BuildCounterVar() const {
- return buildDeclRefExpr(SemaRef, Var, Var->getType().getNonReferenceType(),
+DeclRefExpr *OpenMPIterationSpaceChecker::BuildCounterVar(
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures, DSAStackTy &DSA) const {
+ auto *VD = dyn_cast<VarDecl>(LCDecl);
+ if (!VD) {
+ VD = SemaRef.IsOpenMPCapturedDecl(LCDecl);
+ auto *Ref = buildDeclRefExpr(
+ SemaRef, VD, VD->getType().getNonReferenceType(), DefaultLoc);
+ DSAStackTy::DSAVarData Data = DSA.getTopDSA(LCDecl, /*FromParent=*/false);
+ // If the loop control decl is explicitly marked as private, do not mark it
+ // as captured again.
+ if (!isOpenMPPrivate(Data.CKind) || !Data.RefExpr)
+ Captures.insert(std::make_pair(LCRef, Ref));
+ return Ref;
+ }
+ return buildDeclRefExpr(SemaRef, VD, VD->getType().getNonReferenceType(),
DefaultLoc);
}
Expr *OpenMPIterationSpaceChecker::BuildPrivateCounterVar() const {
- if (Var && !Var->isInvalidDecl()) {
- auto Type = Var->getType().getNonReferenceType();
+ if (LCDecl && !LCDecl->isInvalidDecl()) {
+ auto Type = LCDecl->getType().getNonReferenceType();
auto *PrivateVar =
- buildVarDecl(SemaRef, DefaultLoc, Type, Var->getName(),
- Var->hasAttrs() ? &Var->getAttrs() : nullptr);
+ buildVarDecl(SemaRef, DefaultLoc, Type, LCDecl->getName(),
+ LCDecl->hasAttrs() ? &LCDecl->getAttrs() : nullptr);
if (PrivateVar->isInvalidDecl())
return nullptr;
return buildDeclRefExpr(SemaRef, PrivateVar, Type, DefaultLoc);
@@ -3432,23 +4551,23 @@ Expr *OpenMPIterationSpaceChecker::BuildCounterInit() const { return LB; }
Expr *OpenMPIterationSpaceChecker::BuildCounterStep() const { return Step; }
/// \brief Iteration space of a single for loop.
-struct LoopIterationSpace {
+struct LoopIterationSpace final {
/// \brief Condition of the loop.
- Expr *PreCond;
+ Expr *PreCond = nullptr;
/// \brief This expression calculates the number of iterations in the loop.
/// It is always possible to calculate it before starting the loop.
- Expr *NumIterations;
+ Expr *NumIterations = nullptr;
/// \brief The loop counter variable.
- Expr *CounterVar;
+ Expr *CounterVar = nullptr;
/// \brief Private loop counter variable.
- Expr *PrivateCounterVar;
+ Expr *PrivateCounterVar = nullptr;
/// \brief This is initializer for the initial value of #CounterVar.
- Expr *CounterInit;
+ Expr *CounterInit = nullptr;
/// \brief This is step for the #CounterVar used to generate its update:
/// #CounterVar = #CounterInit + #CounterStep * CurrentIteration.
- Expr *CounterStep;
+ Expr *CounterStep = nullptr;
/// \brief Should step be subtracted?
- bool Subtract;
+ bool Subtract = false;
/// \brief Source range of the loop init.
SourceRange InitSrcRange;
/// \brief Source range of the loop condition.
@@ -3466,8 +4585,21 @@ void Sema::ActOnOpenMPLoopInitialization(SourceLocation ForLoc, Stmt *Init) {
if (AssociatedLoops > 0 &&
isOpenMPLoopDirective(DSAStack->getCurrentDirective())) {
OpenMPIterationSpaceChecker ISC(*this, ForLoc);
- if (!ISC.CheckInit(Init, /*EmitDiags=*/false))
- DSAStack->addLoopControlVariable(ISC.GetLoopVar());
+ if (!ISC.CheckInit(Init, /*EmitDiags=*/false)) {
+ if (auto *D = ISC.GetLoopDecl()) {
+ auto *VD = dyn_cast<VarDecl>(D);
+ if (!VD) {
+ if (auto *Private = IsOpenMPCapturedDecl(D))
+ VD = Private;
+ else {
+ auto *Ref = buildCapture(*this, D, ISC.GetLoopDeclRefExpr(),
+ /*WithInit=*/false);
+ VD = cast<VarDecl>(Ref->getDecl());
+ }
+ }
+ DSAStack->addLoopControlVariable(D, VD);
+ }
+ }
DSAStack->setAssociatedLoops(AssociatedLoops - 1);
}
}
@@ -3478,8 +4610,9 @@ static bool CheckOpenMPIterationSpace(
OpenMPDirectiveKind DKind, Stmt *S, Sema &SemaRef, DSAStackTy &DSA,
unsigned CurrentNestedLoopCount, unsigned NestedLoopCount,
Expr *CollapseLoopCountExpr, Expr *OrderedLoopCountExpr,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
- LoopIterationSpace &ResultIterSpace) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA,
+ LoopIterationSpace &ResultIterSpace,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
// OpenMP [2.6, Canonical Loop Form]
// for (init-expr; test-expr; incr-expr) structured-block
auto For = dyn_cast_or_null<ForStmt>(S);
@@ -3511,98 +4644,102 @@ static bool CheckOpenMPIterationSpace(
// Check init.
auto Init = For->getInit();
- if (ISC.CheckInit(Init)) {
+ if (ISC.CheckInit(Init))
return true;
- }
bool HasErrors = false;
// Check loop variable's type.
- auto Var = ISC.GetLoopVar();
+ if (auto *LCDecl = ISC.GetLoopDecl()) {
+ auto *LoopDeclRefExpr = ISC.GetLoopDeclRefExpr();
+
+ // OpenMP [2.6, Canonical Loop Form]
+ // Var is one of the following:
+ // A variable of signed or unsigned integer type.
+ // For C++, a variable of a random access iterator type.
+ // For C, a variable of a pointer type.
+ auto VarType = LCDecl->getType().getNonReferenceType();
+ if (!VarType->isDependentType() && !VarType->isIntegerType() &&
+ !VarType->isPointerType() &&
+ !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type)
+ << SemaRef.getLangOpts().CPlusPlus;
+ HasErrors = true;
+ }
- // OpenMP [2.6, Canonical Loop Form]
- // Var is one of the following:
- // A variable of signed or unsigned integer type.
- // For C++, a variable of a random access iterator type.
- // For C, a variable of a pointer type.
- auto VarType = Var->getType().getNonReferenceType();
- if (!VarType->isDependentType() && !VarType->isIntegerType() &&
- !VarType->isPointerType() &&
- !(SemaRef.getLangOpts().CPlusPlus && VarType->isOverloadableType())) {
- SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_variable_type)
- << SemaRef.getLangOpts().CPlusPlus;
- HasErrors = true;
- }
-
- // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in a
- // Construct
- // The loop iteration variable(s) in the associated for-loop(s) of a for or
- // parallel for construct is (are) private.
- // The loop iteration variable in the associated for-loop of a simd construct
- // with just one associated for-loop is linear with a constant-linear-step
- // that is the increment of the associated for-loop.
- // Exclude loop var from the list of variables with implicitly defined data
- // sharing attributes.
- VarsWithImplicitDSA.erase(Var);
-
- // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced in
- // a Construct, C/C++].
- // The loop iteration variable in the associated for-loop of a simd construct
- // with just one associated for-loop may be listed in a linear clause with a
- // constant-linear-step that is the increment of the associated for-loop.
- // The loop iteration variable(s) in the associated for-loop(s) of a for or
- // parallel for construct may be listed in a private or lastprivate clause.
- DSAStackTy::DSAVarData DVar = DSA.getTopDSA(Var, false);
- auto LoopVarRefExpr = ISC.GetLoopVarRefExpr();
- // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
- // declared in the loop and it is predetermined as a private.
- auto PredeterminedCKind =
- isOpenMPSimdDirective(DKind)
- ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
- : OMPC_private;
- if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != PredeterminedCKind) ||
- ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
- isOpenMPDistributeDirective(DKind)) &&
- !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
- DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
- (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
- SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
- << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
- << getOpenMPClauseName(PredeterminedCKind);
- if (DVar.RefExpr == nullptr)
- DVar.CKind = PredeterminedCKind;
- ReportOriginalDSA(SemaRef, &DSA, Var, DVar, /*IsLoopIterVar=*/true);
- HasErrors = true;
- } else if (LoopVarRefExpr != nullptr) {
- // Make the loop iteration variable private (for worksharing constructs),
- // linear (for simd directives with the only one associated loop) or
- // lastprivate (for simd directives with several collapsed or ordered
- // loops).
- if (DVar.CKind == OMPC_unknown)
- DVar = DSA.hasDSA(Var, isOpenMPPrivate, MatchesAlways(),
- /*FromParent=*/false);
- DSA.addDSA(Var, LoopVarRefExpr, PredeterminedCKind);
- }
-
- assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
-
- // Check test-expr.
- HasErrors |= ISC.CheckCond(For->getCond());
-
- // Check incr-expr.
- HasErrors |= ISC.CheckInc(For->getInc());
+ // OpenMP, 2.14.1.1 Data-sharing Attribute Rules for Variables Referenced in
+ // a Construct
+ // The loop iteration variable(s) in the associated for-loop(s) of a for or
+ // parallel for construct is (are) private.
+ // The loop iteration variable in the associated for-loop of a simd
+ // construct with just one associated for-loop is linear with a
+ // constant-linear-step that is the increment of the associated for-loop.
+ // Exclude loop var from the list of variables with implicitly defined data
+ // sharing attributes.
+ VarsWithImplicitDSA.erase(LCDecl);
+
+ // OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
+ // in a Construct, C/C++].
+ // The loop iteration variable in the associated for-loop of a simd
+ // construct with just one associated for-loop may be listed in a linear
+ // clause with a constant-linear-step that is the increment of the
+ // associated for-loop.
+ // The loop iteration variable(s) in the associated for-loop(s) of a for or
+ // parallel for construct may be listed in a private or lastprivate clause.
+ DSAStackTy::DSAVarData DVar = DSA.getTopDSA(LCDecl, false);
+ // If LoopVarRefExpr is nullptr it means the corresponding loop variable is
+ // declared in the loop and it is predetermined as a private.
+ auto PredeterminedCKind =
+ isOpenMPSimdDirective(DKind)
+ ? ((NestedLoopCount == 1) ? OMPC_linear : OMPC_lastprivate)
+ : OMPC_private;
+ if (((isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != PredeterminedCKind) ||
+ ((isOpenMPWorksharingDirective(DKind) || DKind == OMPD_taskloop ||
+ isOpenMPDistributeDirective(DKind)) &&
+ !isOpenMPSimdDirective(DKind) && DVar.CKind != OMPC_unknown &&
+ DVar.CKind != OMPC_private && DVar.CKind != OMPC_lastprivate)) &&
+ (DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
+ SemaRef.Diag(Init->getLocStart(), diag::err_omp_loop_var_dsa)
+ << getOpenMPClauseName(DVar.CKind) << getOpenMPDirectiveName(DKind)
+ << getOpenMPClauseName(PredeterminedCKind);
+ if (DVar.RefExpr == nullptr)
+ DVar.CKind = PredeterminedCKind;
+ ReportOriginalDSA(SemaRef, &DSA, LCDecl, DVar, /*IsLoopIterVar=*/true);
+ HasErrors = true;
+ } else if (LoopDeclRefExpr != nullptr) {
+ // Make the loop iteration variable private (for worksharing constructs),
+ // linear (for simd directives with the only one associated loop) or
+ // lastprivate (for simd directives with several collapsed or ordered
+ // loops).
+ if (DVar.CKind == OMPC_unknown)
+ DVar = DSA.hasDSA(LCDecl, isOpenMPPrivate,
+ [](OpenMPDirectiveKind) -> bool { return true; },
+ /*FromParent=*/false);
+ DSA.addDSA(LCDecl, LoopDeclRefExpr, PredeterminedCKind);
+ }
+
+ assert(isOpenMPLoopDirective(DKind) && "DSA for non-loop vars");
+
+ // Check test-expr.
+ HasErrors |= ISC.CheckCond(For->getCond());
+
+ // Check incr-expr.
+ HasErrors |= ISC.CheckInc(For->getInc());
+ }
if (ISC.Dependent() || SemaRef.CurContext->isDependentContext() || HasErrors)
return HasErrors;
// Build the loop's iteration space representation.
- ResultIterSpace.PreCond = ISC.BuildPreCond(DSA.getCurScope(), For->getCond());
+ ResultIterSpace.PreCond =
+ ISC.BuildPreCond(DSA.getCurScope(), For->getCond(), Captures);
ResultIterSpace.NumIterations = ISC.BuildNumIterations(
- DSA.getCurScope(), (isOpenMPWorksharingDirective(DKind) ||
- isOpenMPTaskLoopDirective(DKind) ||
- isOpenMPDistributeDirective(DKind)));
- ResultIterSpace.CounterVar = ISC.BuildCounterVar();
+ DSA.getCurScope(),
+ (isOpenMPWorksharingDirective(DKind) ||
+ isOpenMPTaskLoopDirective(DKind) || isOpenMPDistributeDirective(DKind)),
+ Captures);
+ ResultIterSpace.CounterVar = ISC.BuildCounterVar(Captures, DSA);
ResultIterSpace.PrivateCounterVar = ISC.BuildPrivateCounterVar();
ResultIterSpace.CounterInit = ISC.BuildCounterInit();
ResultIterSpace.CounterStep = ISC.BuildCounterStep();
@@ -3622,23 +4759,15 @@ static bool CheckOpenMPIterationSpace(
}
/// \brief Build 'VarRef = Start.
-static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc,
- ExprResult VarRef, ExprResult Start) {
- TransformToNewDefs Transform(SemaRef);
+static ExprResult
+BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc, ExprResult VarRef,
+ ExprResult Start,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
// Build 'VarRef = Start.
- auto *StartNoImp = Start.get()->IgnoreImplicit();
- auto NewStart = Transform.TransformExpr(StartNoImp);
- if (NewStart.isInvalid())
+ auto NewStart = tryBuildCapture(SemaRef, Start.get(), Captures);
+ if (!NewStart.isUsable())
return ExprError();
if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
- StartNoImp->getType())) {
- NewStart = SemaRef.PerformImplicitConversion(
- NewStart.get(), StartNoImp->getType(), Sema::AA_Converting,
- /*AllowExplicit=*/true);
- if (NewStart.isInvalid())
- return ExprError();
- }
- if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
VarRef.get()->getType())) {
NewStart = SemaRef.PerformImplicitConversion(
NewStart.get(), VarRef.get()->getType(), Sema::AA_Converting,
@@ -3653,58 +4782,74 @@ static ExprResult BuildCounterInit(Sema &SemaRef, Scope *S, SourceLocation Loc,
}
/// \brief Build 'VarRef = Start + Iter * Step'.
-static ExprResult BuildCounterUpdate(Sema &SemaRef, Scope *S,
- SourceLocation Loc, ExprResult VarRef,
- ExprResult Start, ExprResult Iter,
- ExprResult Step, bool Subtract) {
+static ExprResult
+BuildCounterUpdate(Sema &SemaRef, Scope *S, SourceLocation Loc,
+ ExprResult VarRef, ExprResult Start, ExprResult Iter,
+ ExprResult Step, bool Subtract,
+ llvm::MapVector<Expr *, DeclRefExpr *> *Captures = nullptr) {
// Add parentheses (for debugging purposes only).
Iter = SemaRef.ActOnParenExpr(Loc, Loc, Iter.get());
if (!VarRef.isUsable() || !Start.isUsable() || !Iter.isUsable() ||
!Step.isUsable())
return ExprError();
- auto *StepNoImp = Step.get()->IgnoreImplicit();
- TransformToNewDefs Transform(SemaRef);
- auto NewStep = Transform.TransformExpr(StepNoImp);
+ ExprResult NewStep = Step;
+ if (Captures)
+ NewStep = tryBuildCapture(SemaRef, Step.get(), *Captures);
if (NewStep.isInvalid())
return ExprError();
- if (!SemaRef.Context.hasSameType(NewStep.get()->getType(),
- StepNoImp->getType())) {
- NewStep = SemaRef.PerformImplicitConversion(
- NewStep.get(), StepNoImp->getType(), Sema::AA_Converting,
- /*AllowExplicit=*/true);
- if (NewStep.isInvalid())
- return ExprError();
- }
ExprResult Update =
SemaRef.BuildBinOp(S, Loc, BO_Mul, Iter.get(), NewStep.get());
if (!Update.isUsable())
return ExprError();
- // Build 'VarRef = Start + Iter * Step'.
- auto *StartNoImp = Start.get()->IgnoreImplicit();
- auto NewStart = Transform.TransformExpr(StartNoImp);
+ // Try to build 'VarRef = Start, VarRef (+|-)= Iter * Step' or
+ // 'VarRef = Start (+|-) Iter * Step'.
+ ExprResult NewStart = Start;
+ if (Captures)
+ NewStart = tryBuildCapture(SemaRef, Start.get(), *Captures);
if (NewStart.isInvalid())
return ExprError();
- if (!SemaRef.Context.hasSameType(NewStart.get()->getType(),
- StartNoImp->getType())) {
- NewStart = SemaRef.PerformImplicitConversion(
- NewStart.get(), StartNoImp->getType(), Sema::AA_Converting,
- /*AllowExplicit=*/true);
- if (NewStart.isInvalid())
- return ExprError();
+
+ // First attempt: try to build 'VarRef = Start, VarRef += Iter * Step'.
+ ExprResult SavedUpdate = Update;
+ ExprResult UpdateVal;
+ if (VarRef.get()->getType()->isOverloadableType() ||
+ NewStart.get()->getType()->isOverloadableType() ||
+ Update.get()->getType()->isOverloadableType()) {
+ bool Suppress = SemaRef.getDiagnostics().getSuppressAllDiagnostics();
+ SemaRef.getDiagnostics().setSuppressAllDiagnostics(/*Val=*/true);
+ Update =
+ SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), NewStart.get());
+ if (Update.isUsable()) {
+ UpdateVal =
+ SemaRef.BuildBinOp(S, Loc, Subtract ? BO_SubAssign : BO_AddAssign,
+ VarRef.get(), SavedUpdate.get());
+ if (UpdateVal.isUsable()) {
+ Update = SemaRef.CreateBuiltinBinOp(Loc, BO_Comma, Update.get(),
+ UpdateVal.get());
+ }
+ }
+ SemaRef.getDiagnostics().setSuppressAllDiagnostics(Suppress);
}
- Update = SemaRef.BuildBinOp(S, Loc, (Subtract ? BO_Sub : BO_Add),
- NewStart.get(), Update.get());
- if (!Update.isUsable())
- return ExprError();
- Update = SemaRef.PerformImplicitConversion(
- Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true);
- if (!Update.isUsable())
- return ExprError();
+ // Second attempt: try to build 'VarRef = Start (+|-) Iter * Step'.
+ if (!Update.isUsable() || !UpdateVal.isUsable()) {
+ Update = SemaRef.BuildBinOp(S, Loc, Subtract ? BO_Sub : BO_Add,
+ NewStart.get(), SavedUpdate.get());
+ if (!Update.isUsable())
+ return ExprError();
+
+ if (!SemaRef.Context.hasSameType(Update.get()->getType(),
+ VarRef.get()->getType())) {
+ Update = SemaRef.PerformImplicitConversion(
+ Update.get(), VarRef.get()->getType(), Sema::AA_Converting, true);
+ if (!Update.isUsable())
+ return ExprError();
+ }
- Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get());
+ Update = SemaRef.BuildBinOp(S, Loc, BO_Assign, VarRef.get(), Update.get());
+ }
return Update;
}
@@ -3736,6 +4881,49 @@ static bool FitsInto(unsigned Bits, bool Signed, Expr *E, Sema &SemaRef) {
return false;
}
+/// Build preinits statement for the given declarations.
+static Stmt *buildPreInits(ASTContext &Context,
+ SmallVectorImpl<Decl *> &PreInits) {
+ if (!PreInits.empty()) {
+ return new (Context) DeclStmt(
+ DeclGroupRef::Create(Context, PreInits.begin(), PreInits.size()),
+ SourceLocation(), SourceLocation());
+ }
+ return nullptr;
+}
+
+/// Build preinits statement for the given declarations.
+static Stmt *buildPreInits(ASTContext &Context,
+ llvm::MapVector<Expr *, DeclRefExpr *> &Captures) {
+ if (!Captures.empty()) {
+ SmallVector<Decl *, 16> PreInits;
+ for (auto &Pair : Captures)
+ PreInits.push_back(Pair.second->getDecl());
+ return buildPreInits(Context, PreInits);
+ }
+ return nullptr;
+}
+
+/// Build postupdate expression for the given list of postupdates expressions.
+static Expr *buildPostUpdate(Sema &S, ArrayRef<Expr *> PostUpdates) {
+ Expr *PostUpdate = nullptr;
+ if (!PostUpdates.empty()) {
+ for (auto *E : PostUpdates) {
+ Expr *ConvE = S.BuildCStyleCastExpr(
+ E->getExprLoc(),
+ S.Context.getTrivialTypeSourceInfo(S.Context.VoidTy),
+ E->getExprLoc(), E)
+ .get();
+ PostUpdate = PostUpdate
+ ? S.CreateBuiltinBinOp(ConvE->getExprLoc(), BO_Comma,
+ PostUpdate, ConvE)
+ .get()
+ : ConvE;
+ }
+ }
+ return PostUpdate;
+}
+
/// \brief Called on a for stmt to check itself and nested loops (if any).
/// \return Returns 0 if one of the collapsed stmts is not canonical for loop,
/// number of collapsed loops otherwise.
@@ -3743,7 +4931,7 @@ static unsigned
CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Expr *OrderedLoopCountExpr, Stmt *AStmt, Sema &SemaRef,
DSAStackTy &DSA,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA,
OMPLoopDirective::HelperExprs &Built) {
unsigned NestedLoopCount = 1;
if (CollapseLoopCountExpr) {
@@ -3769,6 +4957,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
}
// This is helper routine for loop directives (e.g., 'for', 'simd',
// 'for simd', etc.).
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
SmallVector<LoopIterationSpace, 4> IterSpaces;
IterSpaces.resize(NestedLoopCount);
Stmt *CurStmt = AStmt->IgnoreContainers(/* IgnoreCaptured */ true);
@@ -3776,7 +4965,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
if (CheckOpenMPIterationSpace(DKind, CurStmt, SemaRef, DSA, Cnt,
NestedLoopCount, CollapseLoopCountExpr,
OrderedLoopCountExpr, VarsWithImplicitDSA,
- IterSpaces[Cnt]))
+ IterSpaces[Cnt], Captures))
return 0;
// Move on to the next nested for loop, or to the loop body.
// OpenMP [2.8.1, simd construct, Restrictions]
@@ -3877,6 +5066,15 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
LastIteration32.get()->getType()->hasSignedIntegerRepresentation(),
LastIteration64.get(), SemaRef)))
LastIteration = LastIteration32;
+ QualType VType = LastIteration.get()->getType();
+ QualType RealVType = VType;
+ QualType StrideVType = VType;
+ if (isOpenMPTaskLoopDirective(DKind)) {
+ VType =
+ SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/0);
+ StrideVType =
+ SemaRef.Context.getIntTypeForBitwidth(/*DestWidth=*/64, /*Signed=*/1);
+ }
if (!LastIteration.isUsable())
return 0;
@@ -3898,19 +5096,13 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
LastIteration.get()->isIntegerConstantExpr(Result, SemaRef.Context);
ExprResult CalcLastIteration;
if (!IsConstant) {
- SourceLocation SaveLoc;
- VarDecl *SaveVar =
- buildVarDecl(SemaRef, SaveLoc, LastIteration.get()->getType(),
- ".omp.last.iteration");
- ExprResult SaveRef = buildDeclRefExpr(
- SemaRef, SaveVar, LastIteration.get()->getType(), SaveLoc);
- CalcLastIteration = SemaRef.BuildBinOp(CurScope, SaveLoc, BO_Assign,
- SaveRef.get(), LastIteration.get());
+ ExprResult SaveRef =
+ tryBuildCapture(SemaRef, LastIteration.get(), Captures);
LastIteration = SaveRef;
// Prepare SaveRef + 1.
NumIterations = SemaRef.BuildBinOp(
- CurScope, SaveLoc, BO_Add, SaveRef.get(),
+ CurScope, SourceLocation(), BO_Add, SaveRef.get(),
SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get());
if (!NumIterations.isUsable())
return 0;
@@ -3918,9 +5110,8 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
SourceLocation InitLoc = IterSpaces[0].InitSrcRange.getBegin();
- QualType VType = LastIteration.get()->getType();
// Build variables passed into runtime, nesessary for worksharing directives.
- ExprResult LB, UB, IL, ST, EUB;
+ ExprResult LB, UB, IL, ST, EUB, PrevLB, PrevUB;
if (isOpenMPWorksharingDirective(DKind) || isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind)) {
// Lower bound variable, initialized with zero.
@@ -3947,8 +5138,9 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
/*DirectInit*/ false, /*TypeMayContainAuto*/ false);
// Stride variable returned by runtime (we initialize it to 1 by default).
- VarDecl *STDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.stride");
- ST = buildDeclRefExpr(SemaRef, STDecl, VType, InitLoc);
+ VarDecl *STDecl =
+ buildVarDecl(SemaRef, InitLoc, StrideVType, ".omp.stride");
+ ST = buildDeclRefExpr(SemaRef, STDecl, StrideVType, InitLoc);
SemaRef.AddInitializerToDecl(
STDecl, SemaRef.ActOnIntegerConstant(InitLoc, 1).get(),
/*DirectInit*/ false, /*TypeMayContainAuto*/ false);
@@ -3962,14 +5154,39 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
EUB = SemaRef.BuildBinOp(CurScope, InitLoc, BO_Assign, UB.get(),
CondOp.get());
EUB = SemaRef.ActOnFinishFullExpr(EUB.get());
+
+ // If we have a combined directive that combines 'distribute', 'for' or
+ // 'simd' we need to be able to access the bounds of the schedule of the
+ // enclosing region. E.g. in 'distribute parallel for' the bounds obtained
+ // by scheduling 'distribute' have to be passed to the schedule of 'for'.
+ if (isOpenMPLoopBoundSharingDirective(DKind)) {
+ auto *CD = cast<CapturedStmt>(AStmt)->getCapturedDecl();
+
+ // We expect to have at least 2 more parameters than the 'parallel'
+ // directive does - the lower and upper bounds of the previous schedule.
+ assert(CD->getNumParams() >= 4 &&
+ "Unexpected number of parameters in loop combined directive");
+
+ // Set the proper type for the bounds given what we learned from the
+ // enclosed loops.
+ auto *PrevLBDecl = CD->getParam(/*PrevLB=*/2);
+ auto *PrevUBDecl = CD->getParam(/*PrevUB=*/3);
+
+ // Previous lower and upper bounds are obtained from the region
+ // parameters.
+ PrevLB =
+ buildDeclRefExpr(SemaRef, PrevLBDecl, PrevLBDecl->getType(), InitLoc);
+ PrevUB =
+ buildDeclRefExpr(SemaRef, PrevUBDecl, PrevUBDecl->getType(), InitLoc);
+ }
}
// Build the iteration variable and its initialization before loop.
ExprResult IV;
ExprResult Init;
{
- VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, VType, ".omp.iv");
- IV = buildDeclRefExpr(SemaRef, IVDecl, VType, InitLoc);
+ VarDecl *IVDecl = buildVarDecl(SemaRef, InitLoc, RealVType, ".omp.iv");
+ IV = buildDeclRefExpr(SemaRef, IVDecl, RealVType, InitLoc);
Expr *RHS = (isOpenMPWorksharingDirective(DKind) ||
isOpenMPTaskLoopDirective(DKind) ||
isOpenMPDistributeDirective(DKind))
@@ -4033,6 +5250,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.Inits.resize(NestedLoopCount);
Built.Updates.resize(NestedLoopCount);
Built.Finals.resize(NestedLoopCount);
+ SmallVector<Expr *, 4> LoopMultipliers;
{
ExprResult Div;
// Go from inner nested loop to outer.
@@ -4060,19 +5278,19 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
}
// Build update: IS.CounterVar(Private) = IS.Start + Iter * IS.Step
- auto *CounterVar = buildDeclRefExpr(
- SemaRef, cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl()),
- IS.CounterVar->getType(), IS.CounterVar->getExprLoc(),
- /*RefersToCapture=*/true);
+ auto *VD = cast<VarDecl>(cast<DeclRefExpr>(IS.CounterVar)->getDecl());
+ auto *CounterVar = buildDeclRefExpr(SemaRef, VD, IS.CounterVar->getType(),
+ IS.CounterVar->getExprLoc(),
+ /*RefersToCapture=*/true);
ExprResult Init = BuildCounterInit(SemaRef, CurScope, UpdLoc, CounterVar,
- IS.CounterInit);
+ IS.CounterInit, Captures);
if (!Init.isUsable()) {
HasErrors = true;
break;
}
- ExprResult Update =
- BuildCounterUpdate(SemaRef, CurScope, UpdLoc, CounterVar,
- IS.CounterInit, Iter, IS.CounterStep, IS.Subtract);
+ ExprResult Update = BuildCounterUpdate(
+ SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit, Iter,
+ IS.CounterStep, IS.Subtract, &Captures);
if (!Update.isUsable()) {
HasErrors = true;
break;
@@ -4081,7 +5299,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Build final: IS.CounterVar = IS.Start + IS.NumIters * IS.Step
ExprResult Final = BuildCounterUpdate(
SemaRef, CurScope, UpdLoc, CounterVar, IS.CounterInit,
- IS.NumIterations, IS.CounterStep, IS.Subtract);
+ IS.NumIterations, IS.CounterStep, IS.Subtract, &Captures);
if (!Final.isUsable()) {
HasErrors = true;
break;
@@ -4097,11 +5315,12 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
// Add parentheses (for debugging purposes only).
if (Div.isUsable())
- Div = SemaRef.ActOnParenExpr(UpdLoc, UpdLoc, Div.get());
+ Div = tryBuildCapture(SemaRef, Div.get(), Captures);
if (!Div.isUsable()) {
HasErrors = true;
break;
}
+ LoopMultipliers.push_back(Div.get());
}
if (!Update.isUsable() || !Final.isUsable()) {
HasErrors = true;
@@ -4126,6 +5345,7 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.CalcLastIteration =
SemaRef.ActOnFinishFullExpr(CalcLastIteration.get()).get();
Built.PreCond = PreCond.get();
+ Built.PreInits = buildPreInits(C, Captures);
Built.Cond = Cond.get();
Built.Init = Init.get();
Built.Inc = Inc.get();
@@ -4136,6 +5356,56 @@ CheckOpenMPLoop(OpenMPDirectiveKind DKind, Expr *CollapseLoopCountExpr,
Built.EUB = EUB.get();
Built.NLB = NextLB.get();
Built.NUB = NextUB.get();
+ Built.PrevLB = PrevLB.get();
+ Built.PrevUB = PrevUB.get();
+
+ Expr *CounterVal = SemaRef.DefaultLvalueConversion(IV.get()).get();
+ // Fill data for doacross depend clauses.
+ for (auto Pair : DSA.getDoacrossDependClauses()) {
+ if (Pair.first->getDependencyKind() == OMPC_DEPEND_source)
+ Pair.first->setCounterValue(CounterVal);
+ else {
+ if (NestedLoopCount != Pair.second.size() ||
+ NestedLoopCount != LoopMultipliers.size() + 1) {
+ // Erroneous case - clause has some problems.
+ Pair.first->setCounterValue(CounterVal);
+ continue;
+ }
+ assert(Pair.first->getDependencyKind() == OMPC_DEPEND_sink);
+ auto I = Pair.second.rbegin();
+ auto IS = IterSpaces.rbegin();
+ auto ILM = LoopMultipliers.rbegin();
+ Expr *UpCounterVal = CounterVal;
+ Expr *Multiplier = nullptr;
+ for (int Cnt = NestedLoopCount - 1; Cnt >= 0; --Cnt) {
+ if (I->first) {
+ assert(IS->CounterStep);
+ Expr *NormalizedOffset =
+ SemaRef
+ .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Div,
+ I->first, IS->CounterStep)
+ .get();
+ if (Multiplier) {
+ NormalizedOffset =
+ SemaRef
+ .BuildBinOp(CurScope, I->first->getExprLoc(), BO_Mul,
+ NormalizedOffset, Multiplier)
+ .get();
+ }
+ assert(I->second == OO_Plus || I->second == OO_Minus);
+ BinaryOperatorKind BOK = (I->second == OO_Plus) ? BO_Add : BO_Sub;
+ UpCounterVal =
+ SemaRef.BuildBinOp(CurScope, I->first->getExprLoc(), BOK,
+ UpCounterVal, NormalizedOffset).get();
+ }
+ Multiplier = *ILM;
+ ++I;
+ ++IS;
+ ++ILM;
+ }
+ Pair.first->setCounterValue(UpCounterVal);
+ }
+ }
return NestedLoopCount;
}
@@ -4156,26 +5426,44 @@ static Expr *getOrderedNumberExpr(ArrayRef<OMPClause *> Clauses) {
return nullptr;
}
-static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen,
- const Expr *Safelen) {
- llvm::APSInt SimdlenRes, SafelenRes;
- if (Simdlen->isValueDependent() || Simdlen->isTypeDependent() ||
- Simdlen->isInstantiationDependent() ||
- Simdlen->containsUnexpandedParameterPack())
- return false;
- if (Safelen->isValueDependent() || Safelen->isTypeDependent() ||
- Safelen->isInstantiationDependent() ||
- Safelen->containsUnexpandedParameterPack())
- return false;
- Simdlen->EvaluateAsInt(SimdlenRes, S.Context);
- Safelen->EvaluateAsInt(SafelenRes, S.Context);
- // OpenMP 4.1 [2.8.1, simd Construct, Restrictions]
- // If both simdlen and safelen clauses are specified, the value of the simdlen
- // parameter must be less than or equal to the value of the safelen parameter.
- if (SimdlenRes > SafelenRes) {
- S.Diag(Simdlen->getExprLoc(), diag::err_omp_wrong_simdlen_safelen_values)
- << Simdlen->getSourceRange() << Safelen->getSourceRange();
- return true;
+static bool checkSimdlenSafelenSpecified(Sema &S,
+ const ArrayRef<OMPClause *> Clauses) {
+ OMPSafelenClause *Safelen = nullptr;
+ OMPSimdlenClause *Simdlen = nullptr;
+
+ for (auto *Clause : Clauses) {
+ if (Clause->getClauseKind() == OMPC_safelen)
+ Safelen = cast<OMPSafelenClause>(Clause);
+ else if (Clause->getClauseKind() == OMPC_simdlen)
+ Simdlen = cast<OMPSimdlenClause>(Clause);
+ if (Safelen && Simdlen)
+ break;
+ }
+
+ if (Simdlen && Safelen) {
+ llvm::APSInt SimdlenRes, SafelenRes;
+ auto SimdlenLength = Simdlen->getSimdlen();
+ auto SafelenLength = Safelen->getSafelen();
+ if (SimdlenLength->isValueDependent() || SimdlenLength->isTypeDependent() ||
+ SimdlenLength->isInstantiationDependent() ||
+ SimdlenLength->containsUnexpandedParameterPack())
+ return false;
+ if (SafelenLength->isValueDependent() || SafelenLength->isTypeDependent() ||
+ SafelenLength->isInstantiationDependent() ||
+ SafelenLength->containsUnexpandedParameterPack())
+ return false;
+ SimdlenLength->EvaluateAsInt(SimdlenRes, S.Context);
+ SafelenLength->EvaluateAsInt(SafelenRes, S.Context);
+ // OpenMP 4.5 [2.8.1, simd Construct, Restrictions]
+ // If both simdlen and safelen clauses are specified, the value of the
+ // simdlen parameter must be less than or equal to the value of the safelen
+ // parameter.
+ if (SimdlenRes > SafelenRes) {
+ S.Diag(SimdlenLength->getExprLoc(),
+ diag::err_omp_wrong_simdlen_safelen_values)
+ << SimdlenLength->getSourceRange() << SafelenLength->getSourceRange();
+ return true;
+ }
}
return false;
}
@@ -4183,7 +5471,7 @@ static bool checkSimdlenSafelenValues(Sema &S, const Expr *Simdlen,
StmtResult Sema::ActOnOpenMPSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -4205,27 +5493,13 @@ StmtResult Sema::ActOnOpenMPSimdDirective(
for (auto C : Clauses) {
if (auto LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope))
+ B.NumIterations, *this, CurScope,
+ DSAStack))
return StmtError();
}
}
- // OpenMP 4.1 [2.8.1, simd Construct, Restrictions]
- // If both simdlen and safelen clauses are specified, the value of the simdlen
- // parameter must be less than or equal to the value of the safelen parameter.
- OMPSafelenClause *Safelen = nullptr;
- OMPSimdlenClause *Simdlen = nullptr;
- for (auto *Clause : Clauses) {
- if (Clause->getClauseKind() == OMPC_safelen)
- Safelen = cast<OMPSafelenClause>(Clause);
- else if (Clause->getClauseKind() == OMPC_simdlen)
- Simdlen = cast<OMPSimdlenClause>(Clause);
- if (Safelen && Simdlen)
- break;
- }
- if (Simdlen && Safelen &&
- checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(),
- Safelen->getSafelen()))
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
getCurFunction()->setHasBranchProtectedScope();
@@ -4236,7 +5510,7 @@ StmtResult Sema::ActOnOpenMPSimdDirective(
StmtResult Sema::ActOnOpenMPForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -4258,7 +5532,8 @@ StmtResult Sema::ActOnOpenMPForDirective(
for (auto C : Clauses) {
if (auto LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope))
+ B.NumIterations, *this, CurScope,
+ DSAStack))
return StmtError();
}
}
@@ -4271,7 +5546,7 @@ StmtResult Sema::ActOnOpenMPForDirective(
StmtResult Sema::ActOnOpenMPForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -4294,27 +5569,13 @@ StmtResult Sema::ActOnOpenMPForSimdDirective(
for (auto C : Clauses) {
if (auto LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope))
+ B.NumIterations, *this, CurScope,
+ DSAStack))
return StmtError();
}
}
- // OpenMP 4.1 [2.8.1, simd Construct, Restrictions]
- // If both simdlen and safelen clauses are specified, the value of the simdlen
- // parameter must be less than or equal to the value of the safelen parameter.
- OMPSafelenClause *Safelen = nullptr;
- OMPSimdlenClause *Simdlen = nullptr;
- for (auto *Clause : Clauses) {
- if (Clause->getClauseKind() == OMPC_safelen)
- Safelen = cast<OMPSafelenClause>(Clause);
- else if (Clause->getClauseKind() == OMPC_simdlen)
- Simdlen = cast<OMPSimdlenClause>(Clause);
- if (Safelen && Simdlen)
- break;
- }
- if (Simdlen && Safelen &&
- checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(),
- Safelen->getSafelen()))
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
getCurFunction()->setHasBranchProtectedScope();
@@ -4480,7 +5741,7 @@ StmtResult Sema::ActOnOpenMPCriticalDirective(
StmtResult Sema::ActOnOpenMPParallelForDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -4510,7 +5771,8 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
for (auto C : Clauses) {
if (auto LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope))
+ B.NumIterations, *this, CurScope,
+ DSAStack))
return StmtError();
}
}
@@ -4524,7 +5786,7 @@ StmtResult Sema::ActOnOpenMPParallelForDirective(
StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -4551,27 +5813,13 @@ StmtResult Sema::ActOnOpenMPParallelForSimdDirective(
for (auto C : Clauses) {
if (auto LC = dyn_cast<OMPLinearClause>(C))
if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
- B.NumIterations, *this, CurScope))
+ B.NumIterations, *this, CurScope,
+ DSAStack))
return StmtError();
}
}
- // OpenMP 4.1 [2.8.1, simd Construct, Restrictions]
- // If both simdlen and safelen clauses are specified, the value of the simdlen
- // parameter must be less than or equal to the value of the safelen parameter.
- OMPSafelenClause *Safelen = nullptr;
- OMPSimdlenClause *Simdlen = nullptr;
- for (auto *Clause : Clauses) {
- if (Clause->getClauseKind() == OMPC_safelen)
- Safelen = cast<OMPSafelenClause>(Clause);
- else if (Clause->getClauseKind() == OMPC_simdlen)
- Simdlen = cast<OMPSimdlenClause>(Clause);
- if (Safelen && Simdlen)
- break;
- }
- if (Simdlen && Safelen &&
- checkSimdlenSafelenValues(*this, Simdlen->getSimdlen(),
- Safelen->getSafelen()))
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
return StmtError();
getCurFunction()->setHasBranchProtectedScope();
@@ -5453,6 +6701,9 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
}
assert(I != CS->body_end() && "Not found statement");
S = *I;
+ } else {
+ auto *OED = dyn_cast<OMPExecutableDirective>(S);
+ OMPTeamsFound = OED && isOpenMPTeamsDirective(OED->getDirectiveKind());
}
if (!OMPTeamsFound) {
Diag(StartLoc, diag::err_omp_target_contains_not_only_teams);
@@ -5469,6 +6720,84 @@ StmtResult Sema::ActOnOpenMPTargetDirective(ArrayRef<OMPClause *> Clauses,
return OMPTargetDirective::Create(Context, StartLoc, EndLoc, Clauses, AStmt);
}
+StmtResult
+Sema::ActOnOpenMPTargetParallelDirective(ArrayRef<OMPClause *> Clauses,
+ Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ getCurFunction()->setHasBranchProtectedScope();
+
+ return OMPTargetParallelDirective::Create(Context, StartLoc, EndLoc, Clauses,
+ AStmt);
+}
+
+StmtResult Sema::ActOnOpenMPTargetParallelForDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_target_parallel_for, getCollapseNumberExpr(Clauses),
+ getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp target parallel for loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPTargetParallelForDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt,
+ B, DSAStack->isCancelRegion());
+}
+
+/// \brief Check for existence of a map clause in the list of clauses.
+static bool HasMapClause(ArrayRef<OMPClause *> Clauses) {
+ for (ArrayRef<OMPClause *>::iterator I = Clauses.begin(), E = Clauses.end();
+ I != E; ++I) {
+ if (*I != nullptr && (*I)->getClauseKind() == OMPC_map) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt,
SourceLocation StartLoc,
@@ -5478,12 +6807,66 @@ StmtResult Sema::ActOnOpenMPTargetDataDirective(ArrayRef<OMPClause *> Clauses,
assert(isa<CapturedStmt>(AStmt) && "Captured statement expected");
+ // OpenMP [2.10.1, Restrictions, p. 97]
+ // At least one map clause must appear on the directive.
+ if (!HasMapClause(Clauses)) {
+ Diag(StartLoc, diag::err_omp_no_map_for_directive) <<
+ getOpenMPDirectiveName(OMPD_target_data);
+ return StmtError();
+ }
+
getCurFunction()->setHasBranchProtectedScope();
return OMPTargetDataDirective::Create(Context, StartLoc, EndLoc, Clauses,
AStmt);
}
+StmtResult
+Sema::ActOnOpenMPTargetEnterDataDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.10.2, Restrictions, p. 99]
+ // At least one map clause must appear on the directive.
+ if (!HasMapClause(Clauses)) {
+ Diag(StartLoc, diag::err_omp_no_map_for_directive)
+ << getOpenMPDirectiveName(OMPD_target_enter_data);
+ return StmtError();
+ }
+
+ return OMPTargetEnterDataDirective::Create(Context, StartLoc, EndLoc,
+ Clauses);
+}
+
+StmtResult
+Sema::ActOnOpenMPTargetExitDataDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ // OpenMP [2.10.3, Restrictions, p. 102]
+ // At least one map clause must appear on the directive.
+ if (!HasMapClause(Clauses)) {
+ Diag(StartLoc, diag::err_omp_no_map_for_directive)
+ << getOpenMPDirectiveName(OMPD_target_exit_data);
+ return StmtError();
+ }
+
+ return OMPTargetExitDataDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
+StmtResult Sema::ActOnOpenMPTargetUpdateDirective(ArrayRef<OMPClause *> Clauses,
+ SourceLocation StartLoc,
+ SourceLocation EndLoc) {
+ bool seenMotionClause = false;
+ for (auto *C : Clauses) {
+ if (C->getClauseKind() == OMPC_to || C->getClauseKind() == OMPC_from)
+ seenMotionClause = true;
+ }
+ if (!seenMotionClause) {
+ Diag(StartLoc, diag::err_omp_at_least_one_motion_clause_required);
+ return StmtError();
+ }
+ return OMPTargetUpdateDirective::Create(Context, StartLoc, EndLoc, Clauses);
+}
+
StmtResult Sema::ActOnOpenMPTeamsDirective(ArrayRef<OMPClause *> Clauses,
Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc) {
@@ -5575,7 +6958,7 @@ static bool checkGrainsizeNumTasksClauses(Sema &S,
StmtResult Sema::ActOnOpenMPTaskLoopDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -5607,7 +6990,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopDirective(
StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -5625,6 +7008,17 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
assert((CurContext->isDependentContext() || B.builtAll()) &&
"omp for loop exprs were not built");
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+
// OpenMP, [2.9.2 taskloop Construct, Restrictions]
// The grainsize clause and num_tasks clause are mutually exclusive and may
// not appear on the same taskloop directive.
@@ -5639,7 +7033,7 @@ StmtResult Sema::ActOnOpenMPTaskLoopSimdDirective(
StmtResult Sema::ActOnOpenMPDistributeDirective(
ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
SourceLocation EndLoc,
- llvm::DenseMap<VarDecl *, Expr *> &VarsWithImplicitDSA) {
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
if (!AStmt)
return StmtError();
@@ -5662,6 +7056,157 @@ StmtResult Sema::ActOnOpenMPDistributeDirective(
NestedLoopCount, Clauses, AStmt, B);
}
+StmtResult Sema::ActOnOpenMPDistributeParallelForDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = CheckOpenMPLoop(
+ OMPD_distribute_parallel_for, getCollapseNumberExpr(Clauses),
+ nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPDistributeParallelForDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPDistributeParallelForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = CheckOpenMPLoop(
+ OMPD_distribute_parallel_for_simd, getCollapseNumberExpr(Clauses),
+ nullptr /*ordered not a clause on distribute*/, AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPDistributeParallelForSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPDistributeSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount =
+ CheckOpenMPLoop(OMPD_distribute_simd, getCollapseNumberExpr(Clauses),
+ nullptr /*ordered not a clause on distribute*/, AStmt,
+ *this, *DSAStack, VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp for loop exprs were not built");
+
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPDistributeSimdDirective::Create(Context, StartLoc, EndLoc,
+ NestedLoopCount, Clauses, AStmt, B);
+}
+
+StmtResult Sema::ActOnOpenMPTargetParallelForSimdDirective(
+ ArrayRef<OMPClause *> Clauses, Stmt *AStmt, SourceLocation StartLoc,
+ SourceLocation EndLoc,
+ llvm::DenseMap<ValueDecl *, Expr *> &VarsWithImplicitDSA) {
+ if (!AStmt)
+ return StmtError();
+
+ CapturedStmt *CS = cast<CapturedStmt>(AStmt);
+ // 1.2.2 OpenMP Language Terminology
+ // Structured block - An executable statement with a single entry at the
+ // top and a single exit at the bottom.
+ // The point of exit cannot be a branch out of the structured block.
+ // longjmp() and throw() must not violate the entry/exit criteria.
+ CS->getCapturedDecl()->setNothrow();
+
+ OMPLoopDirective::HelperExprs B;
+ // In presence of clause 'collapse' or 'ordered' with number of loops, it will
+ // define the nested loops number.
+ unsigned NestedLoopCount = CheckOpenMPLoop(
+ OMPD_target_parallel_for_simd, getCollapseNumberExpr(Clauses),
+ getOrderedNumberExpr(Clauses), AStmt, *this, *DSAStack,
+ VarsWithImplicitDSA, B);
+ if (NestedLoopCount == 0)
+ return StmtError();
+
+ assert((CurContext->isDependentContext() || B.builtAll()) &&
+ "omp target parallel for simd loop exprs were not built");
+
+ if (!CurContext->isDependentContext()) {
+ // Finalize the clauses that need pre-built expressions for CodeGen.
+ for (auto C : Clauses) {
+ if (auto LC = dyn_cast<OMPLinearClause>(C))
+ if (FinishOpenMPLinearClause(*LC, cast<DeclRefExpr>(B.IterationVarRef),
+ B.NumIterations, *this, CurScope,
+ DSAStack))
+ return StmtError();
+ }
+ }
+ if (checkSimdlenSafelenSpecified(*this, Clauses))
+ return StmtError();
+
+ getCurFunction()->setHasBranchProtectedScope();
+ return OMPTargetParallelForSimdDirective::Create(
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+}
+
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -5735,7 +7280,14 @@ OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,
case OMPC_simd:
case OMPC_map:
case OMPC_nogroup:
+ case OMPC_dist_schedule:
+ case OMPC_defaultmap:
case OMPC_unknown:
+ case OMPC_uniform:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -5751,12 +7303,11 @@ OMPClause *Sema::ActOnOpenMPIfClause(OpenMPDirectiveKind NameModifier,
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
- ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(),
- Condition->getExprLoc(), Condition);
+ ExprResult Val = CheckBooleanCondition(StartLoc, Condition);
if (Val.isInvalid())
return nullptr;
- ValExpr = Val.get();
+ ValExpr = MakeFullExpr(Val.get()).get();
}
return new (Context) OMPIfClause(NameModifier, ValExpr, StartLoc, LParenLoc,
@@ -5771,12 +7322,11 @@ OMPClause *Sema::ActOnOpenMPFinalClause(Expr *Condition,
if (!Condition->isValueDependent() && !Condition->isTypeDependent() &&
!Condition->isInstantiationDependent() &&
!Condition->containsUnexpandedParameterPack()) {
- ExprResult Val = ActOnBooleanCondition(DSAStack->getCurScope(),
- Condition->getExprLoc(), Condition);
+ ExprResult Val = CheckBooleanCondition(StartLoc, Condition);
if (Val.isInvalid())
return nullptr;
- ValExpr = Val.get();
+ ValExpr = MakeFullExpr(Val.get()).get();
}
return new (Context) OMPFinalClause(ValExpr, StartLoc, LParenLoc, EndLoc);
@@ -6018,7 +7568,14 @@ OMPClause *Sema::ActOnOpenMPSimpleClause(
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
+ case OMPC_dist_schedule:
+ case OMPC_defaultmap:
case OMPC_unknown:
+ case OMPC_uniform:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -6116,6 +7673,19 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
Expr, StartLoc, LParenLoc, ArgumentLoc.back(),
DelimLoc, EndLoc);
break;
+ case OMPC_dist_schedule:
+ Res = ActOnOpenMPDistScheduleClause(
+ static_cast<OpenMPDistScheduleClauseKind>(Argument.back()), Expr,
+ StartLoc, LParenLoc, ArgumentLoc.back(), DelimLoc, EndLoc);
+ break;
+ case OMPC_defaultmap:
+ enum { Modifier, DefaultmapKind };
+ Res = ActOnOpenMPDefaultmapClause(
+ static_cast<OpenMPDefaultmapClauseModifier>(Argument[Modifier]),
+ static_cast<OpenMPDefaultmapClauseKind>(Argument[DefaultmapKind]),
+ StartLoc, LParenLoc, ArgumentLoc[Modifier],
+ ArgumentLoc[DefaultmapKind], EndLoc);
+ break;
case OMPC_final:
case OMPC_num_threads:
case OMPC_safelen:
@@ -6156,6 +7726,11 @@ OMPClause *Sema::ActOnOpenMPSingleExprWithArgClause(
case OMPC_num_tasks:
case OMPC_hint:
case OMPC_unknown:
+ case OMPC_uniform:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -6230,7 +7805,7 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
return nullptr;
}
Expr *ValExpr = ChunkSize;
- Expr *HelperValExpr = nullptr;
+ Stmt *HelperValStmt = nullptr;
if (ChunkSize) {
if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
!ChunkSize->isInstantiationDependent() &&
@@ -6253,20 +7828,18 @@ OMPClause *Sema::ActOnOpenMPScheduleClause(
<< "schedule" << 1 << ChunkSize->getSourceRange();
return nullptr;
}
- } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective())) {
- auto *ImpVar = buildVarDecl(*this, ChunkSize->getExprLoc(),
- ChunkSize->getType(), ".chunk.");
- auto *ImpVarRef = buildDeclRefExpr(*this, ImpVar, ChunkSize->getType(),
- ChunkSize->getExprLoc(),
- /*RefersToCapture=*/true);
- HelperValExpr = ImpVarRef;
+ } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) &&
+ !CurContext->isDependentContext()) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
}
}
}
return new (Context)
OMPScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc, Kind,
- ValExpr, HelperValExpr, M1, M1Loc, M2, M2Loc);
+ ValExpr, HelperValStmt, M1, M1Loc, M2, M2Loc);
}
OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
@@ -6339,7 +7912,14 @@ OMPClause *Sema::ActOnOpenMPClause(OpenMPClauseKind Kind,
case OMPC_grainsize:
case OMPC_num_tasks:
case OMPC_hint:
+ case OMPC_dist_schedule:
+ case OMPC_defaultmap:
case OMPC_unknown:
+ case OMPC_uniform:
+ case OMPC_to:
+ case OMPC_from:
+ case OMPC_use_device_ptr:
+ case OMPC_is_device_ptr:
llvm_unreachable("Clause is not allowed.");
}
return Res;
@@ -6406,8 +7986,9 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation ColonLoc,
SourceLocation EndLoc, CXXScopeSpec &ReductionIdScopeSpec,
const DeclarationNameInfo &ReductionId, OpenMPDependClauseKind DepKind,
- OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier,
- OpenMPMapClauseKind MapType, SourceLocation DepLinMapLoc) {
+ OpenMPLinearClauseKind LinKind, OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
+ SourceLocation DepLinMapLoc) {
OMPClause *Res = nullptr;
switch (Kind) {
case OMPC_private:
@@ -6448,8 +8029,21 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
StartLoc, LParenLoc, EndLoc);
break;
case OMPC_map:
- Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, DepLinMapLoc, ColonLoc,
- VarList, StartLoc, LParenLoc, EndLoc);
+ Res = ActOnOpenMPMapClause(MapTypeModifier, MapType, IsMapTypeImplicit,
+ DepLinMapLoc, ColonLoc, VarList, StartLoc,
+ LParenLoc, EndLoc);
+ break;
+ case OMPC_to:
+ Res = ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_from:
+ Res = ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_use_device_ptr:
+ Res = ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
+ break;
+ case OMPC_is_device_ptr:
+ Res = ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc, EndLoc);
break;
case OMPC_if:
case OMPC_final:
@@ -6480,12 +8074,93 @@ OMPClause *Sema::ActOnOpenMPVarListClause(
case OMPC_nogroup:
case OMPC_num_tasks:
case OMPC_hint:
+ case OMPC_dist_schedule:
+ case OMPC_defaultmap:
case OMPC_unknown:
+ case OMPC_uniform:
llvm_unreachable("Clause is not allowed.");
}
return Res;
}
+ExprResult Sema::getOpenMPCapturedExpr(VarDecl *Capture, ExprValueKind VK,
+ ExprObjectKind OK, SourceLocation Loc) {
+ ExprResult Res = BuildDeclRefExpr(
+ Capture, Capture->getType().getNonReferenceType(), VK_LValue, Loc);
+ if (!Res.isUsable())
+ return ExprError();
+ if (OK == OK_Ordinary && !getLangOpts().CPlusPlus) {
+ Res = CreateBuiltinUnaryOp(Loc, UO_Deref, Res.get());
+ if (!Res.isUsable())
+ return ExprError();
+ }
+ if (VK != VK_LValue && Res.get()->isGLValue()) {
+ Res = DefaultLvalueConversion(Res.get());
+ if (!Res.isUsable())
+ return ExprError();
+ }
+ return Res;
+}
+
+static std::pair<ValueDecl *, bool>
+getPrivateItem(Sema &S, Expr *&RefExpr, SourceLocation &ELoc,
+ SourceRange &ERange, bool AllowArraySection = false) {
+ if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
+ RefExpr->containsUnexpandedParameterPack())
+ return std::make_pair(nullptr, true);
+
+ // OpenMP [3.1, C/C++]
+ // A list item is a variable name.
+ // OpenMP [2.9.3.3, Restrictions, p.1]
+ // A variable that is part of another variable (as an array or
+ // structure element) cannot appear in a private clause.
+ RefExpr = RefExpr->IgnoreParens();
+ enum {
+ NoArrayExpr = -1,
+ ArraySubscript = 0,
+ OMPArraySection = 1
+ } IsArrayExpr = NoArrayExpr;
+ if (AllowArraySection) {
+ if (auto *ASE = dyn_cast_or_null<ArraySubscriptExpr>(RefExpr)) {
+ auto *Base = ASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = ArraySubscript;
+ } else if (auto *OASE = dyn_cast_or_null<OMPArraySectionExpr>(RefExpr)) {
+ auto *Base = OASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
+ Base = TempOASE->getBase()->IgnoreParenImpCasts();
+ while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
+ Base = TempASE->getBase()->IgnoreParenImpCasts();
+ RefExpr = Base;
+ IsArrayExpr = OMPArraySection;
+ }
+ }
+ ELoc = RefExpr->getExprLoc();
+ ERange = RefExpr->getSourceRange();
+ RefExpr = RefExpr->IgnoreParenImpCasts();
+ auto *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
+ auto *ME = dyn_cast_or_null<MemberExpr>(RefExpr);
+ if ((!DE || !isa<VarDecl>(DE->getDecl())) &&
+ (S.getCurrentThisType().isNull() || !ME ||
+ !isa<CXXThisExpr>(ME->getBase()->IgnoreParenImpCasts()) ||
+ !isa<FieldDecl>(ME->getMemberDecl()))) {
+ if (IsArrayExpr != NoArrayExpr)
+ S.Diag(ELoc, diag::err_omp_expected_base_var_name) << IsArrayExpr
+ << ERange;
+ else {
+ S.Diag(ELoc,
+ AllowArraySection
+ ? diag::err_omp_expected_var_name_member_expr_or_array_item
+ : diag::err_omp_expected_var_name_member_expr)
+ << (S.getCurrentThisType().isNull() ? 0 : 1) << ERange;
+ }
+ return std::make_pair(nullptr, false);
+ }
+ return std::make_pair(DE ? DE->getDecl() : ME->getMemberDecl(), false);
+}
+
OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SourceLocation StartLoc,
SourceLocation LParenLoc,
@@ -6494,42 +8169,27 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 8> PrivateCopies;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP private clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
PrivateCopies.push_back(nullptr);
- continue;
}
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.9.3.3, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- Decl *D = DE->getDecl();
- VarDecl *VD = cast<VarDecl>(D);
- QualType Type = VD->getType();
- if (Type->isDependentType() || Type->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
- PrivateCopies.push_back(nullptr);
- continue;
- }
+ QualType Type = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
- if (RequireCompleteType(ELoc, Type,
- diag::err_omp_private_incomplete_type)) {
+ if (RequireCompleteType(ELoc, Type, diag::err_omp_private_incomplete_type))
continue;
- }
Type = Type.getNonReferenceType();
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -6539,28 +8199,45 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_private) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_private);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
// Variably modified types are not supported for tasks.
if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
- DSAStack->getCurrentDirective() == OMPD_task) {
+ isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) {
Diag(ELoc, diag::err_omp_variably_modified_type_not_supported)
<< getOpenMPClauseName(OMPC_private) << Type
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
bool IsDecl =
+ !VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
continue;
}
+ // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct
+ if (DSAStack->getCurrentDirective() == OMPD_target) {
+ if (DSAStack->checkMappableExprComponentListsForDecl(
+ VD, /* CurrentRegionOnly = */ true,
+ [&](OMPClauseMappableExprCommon::MappableExprComponentListRef)
+ -> bool { return true; })) {
+ Diag(ELoc, diag::err_omp_variable_in_map_and_dsa)
+ << getOpenMPClauseName(OMPC_private)
+ << getOpenMPDirectiveName(DSAStack->getCurrentDirective());
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
+ continue;
+ }
+ }
+
// OpenMP [2.9.3.3, Restrictions, C/C++, p.1]
// A variable of class type (or array thereof) that appears in a private
// clause requires an accessible, unambiguous default constructor for the
@@ -6571,16 +8248,21 @@ OMPClause *Sema::ActOnOpenMPPrivateClause(ArrayRef<Expr *> VarList,
// IdResolver, so the code in the OpenMP region uses original variable for
// proper diagnostics.
Type = Type.getUnqualifiedType();
- auto VDPrivate = buildVarDecl(*this, DE->getExprLoc(), Type, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
ActOnUninitializedDecl(VDPrivate, /*TypeMayContainAuto=*/false);
if (VDPrivate->isInvalidDecl())
continue;
auto VDPrivateRefExpr = buildDeclRefExpr(
- *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc());
-
- DSAStack->addDSA(VD, DE, OMPC_private);
- Vars.push_back(DE);
+ *this, VDPrivate, RefExpr->getType().getUnqualifiedType(), ELoc);
+
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext())
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_private, Ref);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
}
@@ -6621,51 +8303,37 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> PrivateCopies;
SmallVector<Expr *, 8> Inits;
+ SmallVector<Decl *, 4> ExprCaptures;
bool IsImplicitClause =
StartLoc.isInvalid() && LParenLoc.isInvalid() && EndLoc.isInvalid();
auto ImplicitClauseLoc = DSAStack->getConstructLoc();
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP firstprivate clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
PrivateCopies.push_back(nullptr);
Inits.push_back(nullptr);
- continue;
}
-
- SourceLocation ELoc =
- IsImplicitClause ? ImplicitClauseLoc : RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.9.3.3, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- Decl *D = DE->getDecl();
- VarDecl *VD = cast<VarDecl>(D);
- QualType Type = VD->getType();
- if (Type->isDependentType() || Type->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
- PrivateCopies.push_back(nullptr);
- Inits.push_back(nullptr);
- continue;
- }
+ ELoc = IsImplicitClause ? ImplicitClauseLoc : ELoc;
+ QualType Type = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
// type or a reference type.
if (RequireCompleteType(ELoc, Type,
- diag::err_omp_firstprivate_incomplete_type)) {
+ diag::err_omp_firstprivate_incomplete_type))
continue;
- }
Type = Type.getNonReferenceType();
// OpenMP [2.9.3.4, Restrictions, C/C++, p.1]
@@ -6675,8 +8343,10 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
auto ElemType = Context.getBaseElementType(Type).getNonReferenceType();
// If an implicit firstprivate variable found it was checked already.
+ DSAStackTy::DSAVarData TopDVar;
if (!IsImplicitClause) {
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
+ TopDVar = DVar;
bool IsConstant = ElemType.isConstant(Context);
// OpenMP [2.4.13, Data-sharing Attribute Clauses]
// A list item that specifies a given variable may not appear in more
@@ -6687,7 +8357,7 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
@@ -6702,12 +8372,12 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// in a Construct, C/C++, p.2]
// Variables with const-qualified type having no mutable member may be
// listed in a firstprivate clause, even if they are static data members.
- if (!(IsConstant || VD->isStaticDataMember()) && !DVar.RefExpr &&
+ if (!(IsConstant || (VD && VD->isStaticDataMember())) && !DVar.RefExpr &&
DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_firstprivate);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
@@ -6719,14 +8389,14 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// to any of the parallel regions arising from the parallel construct.
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(VD, true);
+ DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared &&
(isOpenMPParallelDirective(DVar.DKind) ||
DVar.DKind == OMPD_unknown)) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_firstprivate)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
@@ -6741,20 +8411,20 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// construct must not appear in a firstprivate clause in a task construct
// encountered during execution of any of the worksharing regions arising
// from the worksharing construct.
- if (CurrDir == OMPD_task) {
- DVar =
- DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPParallelDirective(K) ||
- isOpenMPWorksharingDirective(K);
- },
- false);
+ if (isOpenMPTaskingDirective(CurrDir)) {
+ DVar = DSAStack->hasInnermostDSA(
+ D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPParallelDirective(K) ||
+ isOpenMPWorksharingDirective(K);
+ },
+ false);
if (DVar.CKind == OMPC_reduction &&
(isOpenMPParallelDirective(DVar.DKind) ||
isOpenMPWorksharingDirective(DVar.DKind))) {
Diag(ELoc, diag::err_omp_parallel_reduction_in_task_firstprivate)
<< getOpenMPDirectiveName(DVar.DKind);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
@@ -6773,31 +8443,48 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// A list item may appear in a firstprivate or lastprivate clause but not
// both.
if (CurrDir == OMPD_distribute) {
- DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_private),
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
+ DVar = DSAStack->hasInnermostDSA(
+ D, [](OpenMPClauseKind C) -> bool { return C == OMPC_private; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPTeamsDirective(K);
+ },
+ false);
if (DVar.CKind == OMPC_private && isOpenMPTeamsDirective(DVar.DKind)) {
Diag(ELoc, diag::err_omp_firstprivate_distribute_private_teams);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
- DVar = DSAStack->hasInnermostDSA(VD, MatchesAnyClause(OMPC_reduction),
- [](OpenMPDirectiveKind K) -> bool {
- return isOpenMPTeamsDirective(K);
- },
- false);
+ DVar = DSAStack->hasInnermostDSA(
+ D, [](OpenMPClauseKind C) -> bool { return C == OMPC_reduction; },
+ [](OpenMPDirectiveKind K) -> bool {
+ return isOpenMPTeamsDirective(K);
+ },
+ false);
if (DVar.CKind == OMPC_reduction &&
isOpenMPTeamsDirective(DVar.DKind)) {
Diag(ELoc, diag::err_omp_firstprivate_distribute_in_teams_reduction);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
- DVar = DSAStack->getTopDSA(VD, false);
+ DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind == OMPC_lastprivate) {
Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
+ continue;
+ }
+ }
+ // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct
+ if (CurrDir == OMPD_target) {
+ if (DSAStack->checkMappableExprComponentListsForDecl(
+ VD, /* CurrentRegionOnly = */ true,
+ [&](OMPClauseMappableExprCommon::MappableExprComponentListRef)
+ -> bool { return true; })) {
+ Diag(ELoc, diag::err_omp_variable_in_map_and_dsa)
+ << getOpenMPClauseName(OMPC_firstprivate)
+ << getOpenMPDirectiveName(DSAStack->getCurrentDirective());
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
@@ -6805,21 +8492,22 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// Variably modified types are not supported for tasks.
if (!Type->isAnyPointerType() && Type->isVariablyModifiedType() &&
- DSAStack->getCurrentDirective() == OMPD_task) {
+ isOpenMPTaskingDirective(DSAStack->getCurrentDirective())) {
Diag(ELoc, diag::err_omp_variably_modified_type_not_supported)
<< getOpenMPClauseName(OMPC_firstprivate) << Type
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
bool IsDecl =
+ !VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
continue;
}
Type = Type.getUnqualifiedType();
- auto VDPrivate = buildVarDecl(*this, ELoc, Type, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ auto VDPrivate = buildVarDecl(*this, ELoc, Type, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
// Generate helper private variable and initialize it with the value of the
// original variable. The address of the original variable is replaced by
// the address of the new private variable in the CodeGen. This new variable
@@ -6830,11 +8518,11 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// original array element in CodeGen.
if (Type->isArrayType()) {
auto VDInit =
- buildVarDecl(*this, DE->getExprLoc(), ElemType, VD->getName());
+ buildVarDecl(*this, RefExpr->getExprLoc(), ElemType, D->getName());
VDInitRefExpr = buildDeclRefExpr(*this, VDInit, ElemType, ELoc);
auto Init = DefaultLvalueConversion(VDInitRefExpr).get();
ElemType = ElemType.getUnqualifiedType();
- auto *VDInitTemp = buildVarDecl(*this, DE->getLocStart(), ElemType,
+ auto *VDInitTemp = buildVarDecl(*this, RefExpr->getExprLoc(), ElemType,
".firstprivate.temp");
InitializedEntity Entity =
InitializedEntity::InitializeVariable(VDInitTemp);
@@ -6849,26 +8537,39 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
// Remove temp variable declaration.
Context.Deallocate(VDInitTemp);
} else {
- auto *VDInit =
- buildVarDecl(*this, DE->getLocStart(), Type, ".firstprivate.temp");
- VDInitRefExpr =
- buildDeclRefExpr(*this, VDInit, DE->getType(), DE->getExprLoc());
+ auto *VDInit = buildVarDecl(*this, RefExpr->getExprLoc(), Type,
+ ".firstprivate.temp");
+ VDInitRefExpr = buildDeclRefExpr(*this, VDInit, RefExpr->getType(),
+ RefExpr->getExprLoc());
AddInitializerToDecl(VDPrivate,
DefaultLvalueConversion(VDInitRefExpr).get(),
/*DirectInit=*/false, /*TypeMayContainAuto=*/false);
}
if (VDPrivate->isInvalidDecl()) {
if (IsImplicitClause) {
- Diag(DE->getExprLoc(),
+ Diag(RefExpr->getExprLoc(),
diag::note_omp_task_predetermined_firstprivate_here);
}
continue;
}
CurContext->addDecl(VDPrivate);
auto VDPrivateRefExpr = buildDeclRefExpr(
- *this, VDPrivate, DE->getType().getUnqualifiedType(), DE->getExprLoc());
- DSAStack->addDSA(VD, DE, OMPC_firstprivate);
- Vars.push_back(DE);
+ *this, VDPrivate, RefExpr->getType().getUnqualifiedType(),
+ RefExpr->getExprLoc());
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext()) {
+ if (TopDVar.CKind == OMPC_lastprivate)
+ Ref = TopDVar.PrivateCopy;
+ else {
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ if (!IsOpenMPCapturedDecl(D))
+ ExprCaptures.push_back(Ref->getDecl());
+ }
+ }
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_firstprivate, Ref);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
PrivateCopies.push_back(VDPrivateRefExpr);
Inits.push_back(VDInitRefExpr);
}
@@ -6877,7 +8578,8 @@ OMPClause *Sema::ActOnOpenMPFirstprivateClause(ArrayRef<Expr *> VarList,
return nullptr;
return OMPFirstprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- Vars, PrivateCopies, Inits);
+ Vars, PrivateCopies, Inits,
+ buildPreInits(Context, ExprCaptures));
}
OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
@@ -6888,48 +8590,34 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 8> SrcExprs;
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
+ SmallVector<Decl *, 4> ExprCaptures;
+ SmallVector<Expr *, 4> ExprPostUpdates;
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
- continue;
}
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.14.3.5, Restrictions, p.1]
- // A variable that is part of another variable (as an array or structure
- // element) cannot appear in a lastprivate clause.
- DeclRefExpr *DE = dyn_cast_or_null<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- Decl *D = DE->getDecl();
- VarDecl *VD = cast<VarDecl>(D);
- QualType Type = VD->getType();
- if (Type->isDependentType() || Type->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
- SrcExprs.push_back(nullptr);
- DstExprs.push_back(nullptr);
- AssignmentOps.push_back(nullptr);
- continue;
- }
+ QualType Type = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.3.5, Restrictions, C/C++, p.2]
// A variable that appears in a lastprivate clause must not have an
// incomplete type or a reference type.
if (RequireCompleteType(ELoc, Type,
- diag::err_omp_lastprivate_incomplete_type)) {
+ diag::err_omp_lastprivate_incomplete_type))
continue;
- }
Type = Type.getNonReferenceType();
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
@@ -6937,14 +8625,14 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
// Variables with the predetermined data-sharing attributes may not be
// listed in data-sharing attributes clauses, except for the cases
// listed below.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_lastprivate &&
DVar.CKind != OMPC_firstprivate &&
(DVar.CKind != OMPC_private || DVar.RefExpr != nullptr)) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_lastprivate);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
@@ -6958,15 +8646,28 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
DSAStackTy::DSAVarData TopDVar = DVar;
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(VD, true);
+ DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_lastprivate)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
+
+ // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
+ // A list item may appear in a firstprivate or lastprivate clause but not
+ // both.
+ if (CurrDir == OMPD_distribute) {
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
+ if (DVar.CKind == OMPC_firstprivate) {
+ Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
+ continue;
+ }
+ }
+
// OpenMP [2.14.3.5, Restrictions, C++, p.1,2]
// A variable of class type (or array thereof) that appears in a
// lastprivate clause requires an accessible, unambiguous default
@@ -6976,42 +8677,54 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
// lastprivate clause requires an accessible, unambiguous copy assignment
// operator for the class type.
Type = Context.getBaseElementType(Type).getNonReferenceType();
- auto *SrcVD = buildVarDecl(*this, DE->getLocStart(),
+ auto *SrcVD = buildVarDecl(*this, ERange.getBegin(),
Type.getUnqualifiedType(), ".lastprivate.src",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *PseudoSrcExpr = buildDeclRefExpr(
- *this, SrcVD, Type.getUnqualifiedType(), DE->getExprLoc());
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *PseudoSrcExpr =
+ buildDeclRefExpr(*this, SrcVD, Type.getUnqualifiedType(), ELoc);
auto *DstVD =
- buildVarDecl(*this, DE->getLocStart(), Type, ".lastprivate.dst",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *PseudoDstExpr =
- buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc());
+ buildVarDecl(*this, ERange.getBegin(), Type, ".lastprivate.dst",
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *PseudoDstExpr = buildDeclRefExpr(*this, DstVD, Type, ELoc);
// For arrays generate assignment operation for single element and replace
// it by the original array element in CodeGen.
- auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ auto AssignmentOp = BuildBinOp(/*S=*/nullptr, ELoc, BO_Assign,
PseudoDstExpr, PseudoSrcExpr);
if (AssignmentOp.isInvalid())
continue;
- AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc,
/*DiscardedValue=*/true);
if (AssignmentOp.isInvalid())
continue;
- // OpenMP 4.5 [2.10.8, Distribute Construct, p.3]
- // A list item may appear in a firstprivate or lastprivate clause but not
- // both.
- if (CurrDir == OMPD_distribute) {
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
- if (DVar.CKind == OMPC_firstprivate) {
- Diag(ELoc, diag::err_omp_firstprivate_and_lastprivate_in_distribute);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
- continue;
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext()) {
+ if (TopDVar.CKind == OMPC_firstprivate)
+ Ref = TopDVar.PrivateCopy;
+ else {
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ if (!IsOpenMPCapturedDecl(D))
+ ExprCaptures.push_back(Ref->getDecl());
+ }
+ if (TopDVar.CKind == OMPC_firstprivate ||
+ (!IsOpenMPCapturedDecl(D) &&
+ Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>())) {
+ ExprResult RefRes = DefaultLvalueConversion(Ref);
+ if (!RefRes.isUsable())
+ continue;
+ ExprResult PostUpdateRes =
+ BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign, SimpleRefExpr,
+ RefRes.get());
+ if (!PostUpdateRes.isUsable())
+ continue;
+ ExprPostUpdates.push_back(
+ IgnoredValueConversions(PostUpdateRes.get()).get());
}
}
-
- if (TopDVar.CKind != OMPC_firstprivate)
- DSAStack->addDSA(VD, DE, OMPC_lastprivate);
- Vars.push_back(DE);
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_lastprivate, Ref);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
SrcExprs.push_back(PseudoSrcExpr);
DstExprs.push_back(PseudoDstExpr);
AssignmentOps.push_back(AssignmentOp.get());
@@ -7021,7 +8734,9 @@ OMPClause *Sema::ActOnOpenMPLastprivateClause(ArrayRef<Expr *> VarList,
return nullptr;
return OMPLastprivateClause::Create(Context, StartLoc, LParenLoc, EndLoc,
- Vars, SrcExprs, DstExprs, AssignmentOps);
+ Vars, SrcExprs, DstExprs, AssignmentOps,
+ buildPreInits(Context, ExprCaptures),
+ buildPostUpdate(*this, ExprPostUpdates));
}
OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
@@ -7030,35 +8745,20 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
SourceLocation EndLoc) {
SmallVector<Expr *, 8> Vars;
for (auto &RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP shared clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ assert(RefExpr && "NULL expr in OpenMP lastprivate clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
- continue;
- }
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.14.3.2, Restrictions, p.1]
- // A variable that is part of another variable (as an array or structure
- // element) cannot appear in a shared unless it is a static data member
- // of a C++ class.
- DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
- continue;
}
- Decl *D = DE->getDecl();
- VarDecl *VD = cast<VarDecl>(D);
-
- QualType Type = VD->getType();
- if (Type->isDependentType() || Type->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
@@ -7066,17 +8766,22 @@ OMPClause *Sema::ActOnOpenMPSharedClause(ArrayRef<Expr *> VarList,
// listed below. For these exceptions only, listing a predetermined
// variable in a data-sharing attribute clause is allowed and overrides
// the variable's predetermined data-sharing attributes.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_shared &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
- DSAStack->addDSA(VD, DE, OMPC_shared);
- Vars.push_back(DE);
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && IsOpenMPCapturedDecl(D) && !CurContext->isDependentContext())
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_shared, Ref);
+ Vars.push_back((VD || !Ref || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
}
if (Vars.empty())
@@ -7097,8 +8802,9 @@ public:
return false;
if (DVar.CKind != OMPC_unknown)
return true;
- DSAStackTy::DSAVarData DVarPrivate =
- Stack->hasDSA(VD, isOpenMPPrivate, MatchesAlways(), false);
+ DSAStackTy::DSAVarData DVarPrivate = Stack->hasDSA(
+ VD, isOpenMPPrivate, [](OpenMPDirectiveKind) -> bool { return true; },
+ false);
if (DVarPrivate.CKind != OMPC_unknown)
return true;
return false;
@@ -7116,16 +8822,137 @@ public:
};
} // namespace
+namespace {
+// Transform MemberExpression for specified FieldDecl of current class to
+// DeclRefExpr to specified OMPCapturedExprDecl.
+class TransformExprToCaptures : public TreeTransform<TransformExprToCaptures> {
+ typedef TreeTransform<TransformExprToCaptures> BaseTransform;
+ ValueDecl *Field;
+ DeclRefExpr *CapturedExpr;
+
+public:
+ TransformExprToCaptures(Sema &SemaRef, ValueDecl *FieldDecl)
+ : BaseTransform(SemaRef), Field(FieldDecl), CapturedExpr(nullptr) {}
+
+ ExprResult TransformMemberExpr(MemberExpr *E) {
+ if (isa<CXXThisExpr>(E->getBase()->IgnoreParenImpCasts()) &&
+ E->getMemberDecl() == Field) {
+ CapturedExpr = buildCapture(SemaRef, Field, E, /*WithInit=*/false);
+ return CapturedExpr;
+ }
+ return BaseTransform::TransformMemberExpr(E);
+ }
+ DeclRefExpr *getCapturedExpr() { return CapturedExpr; }
+};
+} // namespace
+
+template <typename T>
+static T filterLookupForUDR(SmallVectorImpl<UnresolvedSet<8>> &Lookups,
+ const llvm::function_ref<T(ValueDecl *)> &Gen) {
+ for (auto &Set : Lookups) {
+ for (auto *D : Set) {
+ if (auto Res = Gen(cast<ValueDecl>(D)))
+ return Res;
+ }
+ }
+ return T();
+}
+
+static ExprResult
+buildDeclareReductionRef(Sema &SemaRef, SourceLocation Loc, SourceRange Range,
+ Scope *S, CXXScopeSpec &ReductionIdScopeSpec,
+ const DeclarationNameInfo &ReductionId, QualType Ty,
+ CXXCastPath &BasePath, Expr *UnresolvedReduction) {
+ if (ReductionIdScopeSpec.isInvalid())
+ return ExprError();
+ SmallVector<UnresolvedSet<8>, 4> Lookups;
+ if (S) {
+ LookupResult Lookup(SemaRef, ReductionId, Sema::LookupOMPReductionName);
+ Lookup.suppressDiagnostics();
+ while (S && SemaRef.LookupParsedName(Lookup, S, &ReductionIdScopeSpec)) {
+ auto *D = Lookup.getRepresentativeDecl();
+ do {
+ S = S->getParent();
+ } while (S && !S->isDeclScope(D));
+ if (S)
+ S = S->getParent();
+ Lookups.push_back(UnresolvedSet<8>());
+ Lookups.back().append(Lookup.begin(), Lookup.end());
+ Lookup.clear();
+ }
+ } else if (auto *ULE =
+ cast_or_null<UnresolvedLookupExpr>(UnresolvedReduction)) {
+ Lookups.push_back(UnresolvedSet<8>());
+ Decl *PrevD = nullptr;
+ for(auto *D : ULE->decls()) {
+ if (D == PrevD)
+ Lookups.push_back(UnresolvedSet<8>());
+ else if (auto *DRD = cast<OMPDeclareReductionDecl>(D))
+ Lookups.back().addDecl(DRD);
+ PrevD = D;
+ }
+ }
+ if (Ty->isDependentType() || Ty->isInstantiationDependentType() ||
+ Ty->containsUnexpandedParameterPack() ||
+ filterLookupForUDR<bool>(Lookups, [](ValueDecl *D) -> bool {
+ return !D->isInvalidDecl() &&
+ (D->getType()->isDependentType() ||
+ D->getType()->isInstantiationDependentType() ||
+ D->getType()->containsUnexpandedParameterPack());
+ })) {
+ UnresolvedSet<8> ResSet;
+ for (auto &Set : Lookups) {
+ ResSet.append(Set.begin(), Set.end());
+ // The last item marks the end of all declarations at the specified scope.
+ ResSet.addDecl(Set[Set.size() - 1]);
+ }
+ return UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context), ReductionId,
+ /*ADL=*/true, /*Overloaded=*/true, ResSet.begin(), ResSet.end());
+ }
+ if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ Lookups, [&SemaRef, Ty](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.Context.hasSameType(D->getType(), Ty))
+ return D;
+ return nullptr;
+ }))
+ return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+ if (auto *VD = filterLookupForUDR<ValueDecl *>(
+ Lookups, [&SemaRef, Ty, Loc](ValueDecl *D) -> ValueDecl * {
+ if (!D->isInvalidDecl() &&
+ SemaRef.IsDerivedFrom(Loc, Ty, D->getType()) &&
+ !Ty.isMoreQualifiedThan(D->getType()))
+ return D;
+ return nullptr;
+ })) {
+ CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
+ /*DetectVirtual=*/false);
+ if (SemaRef.IsDerivedFrom(Loc, Ty, VD->getType(), Paths)) {
+ if (!Paths.isAmbiguous(SemaRef.Context.getCanonicalType(
+ VD->getType().getUnqualifiedType()))) {
+ if (SemaRef.CheckBaseClassAccess(Loc, VD->getType(), Ty, Paths.front(),
+ /*DiagID=*/0) !=
+ Sema::AR_inaccessible) {
+ SemaRef.BuildBasePathArray(Paths, BasePath);
+ return SemaRef.BuildDeclRefExpr(VD, Ty, VK_LValue, Loc);
+ }
+ }
+ }
+ }
+ if (ReductionIdScopeSpec.isSet()) {
+ SemaRef.Diag(Loc, diag::err_omp_not_resolved_reduction_identifier) << Range;
+ return ExprError();
+ }
+ return ExprEmpty();
+}
+
OMPClause *Sema::ActOnOpenMPReductionClause(
ArrayRef<Expr *> VarList, SourceLocation StartLoc, SourceLocation LParenLoc,
SourceLocation ColonLoc, SourceLocation EndLoc,
- CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId) {
- // TODO: Allow scope specification search when 'declare reduction' is
- // supported.
- assert(ReductionIdScopeSpec.isEmpty() &&
- "No support for scoped reduction identifiers yet.");
-
+ CXXScopeSpec &ReductionIdScopeSpec, const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
auto DN = ReductionId.getName();
auto OOK = DN.getCXXOverloadedOperator();
BinaryOperatorKind BOK = BO_Comma;
@@ -7209,48 +9036,21 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
break;
}
SourceRange ReductionIdRange;
- if (ReductionIdScopeSpec.isValid()) {
+ if (ReductionIdScopeSpec.isValid())
ReductionIdRange.setBegin(ReductionIdScopeSpec.getBeginLoc());
- }
ReductionIdRange.setEnd(ReductionId.getEndLoc());
- if (BOK == BO_Comma) {
- // Not allowed reduction identifier is found.
- Diag(ReductionId.getLocStart(), diag::err_omp_unknown_reduction_identifier)
- << ReductionIdRange;
- return nullptr;
- }
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> Privates;
SmallVector<Expr *, 8> LHSs;
SmallVector<Expr *, 8> RHSs;
SmallVector<Expr *, 8> ReductionOps;
+ SmallVector<Decl *, 4> ExprCaptures;
+ SmallVector<Expr *, 4> ExprPostUpdates;
+ auto IR = UnresolvedReductions.begin(), ER = UnresolvedReductions.end();
+ bool FirstIter = true;
for (auto RefExpr : VarList) {
assert(RefExpr && "nullptr expr in OpenMP reduction clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
- ReductionOps.push_back(nullptr);
- continue;
- }
-
- if (RefExpr->isTypeDependent() || RefExpr->isValueDependent() ||
- RefExpr->isInstantiationDependent() ||
- RefExpr->containsUnexpandedParameterPack()) {
- // It will be analyzed later.
- Vars.push_back(RefExpr);
- Privates.push_back(nullptr);
- LHSs.push_back(nullptr);
- RHSs.push_back(nullptr);
- ReductionOps.push_back(nullptr);
- continue;
- }
-
- auto ELoc = RefExpr->getExprLoc();
- auto ERange = RefExpr->getSourceRange();
// OpenMP [2.1, C/C++]
// A list item is a variable or array section, subject to the restrictions
// specified in Section 2.4 on page 42 and in each of the sections
@@ -7258,52 +9058,53 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// OpenMP [2.14.3.3, Restrictions, p.1]
// A variable that is part of another variable (as an array or
// structure element) cannot appear in a private clause.
- auto *DE = dyn_cast<DeclRefExpr>(RefExpr);
- auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr);
- if (!ASE && !OASE && (!DE || !isa<VarDecl>(DE->getDecl()))) {
- Diag(ELoc, diag::err_omp_expected_var_name_or_array_item) << ERange;
- continue;
+ if (!FirstIter && IR != ER)
+ ++IR;
+ FirstIter = false;
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/true);
+ if (Res.second) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ Privates.push_back(nullptr);
+ LHSs.push_back(nullptr);
+ RHSs.push_back(nullptr);
+ // Try to find 'declare reduction' corresponding construct before using
+ // builtin/overloaded operators.
+ QualType Type = Context.DependentTy;
+ CXXCastPath BasePath;
+ ExprResult DeclareReductionRef = buildDeclareReductionRef(
+ *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
+ if (CurContext->isDependentContext() &&
+ (DeclareReductionRef.isUnset() ||
+ isa<UnresolvedLookupExpr>(DeclareReductionRef.get())))
+ ReductionOps.push_back(DeclareReductionRef.get());
+ else
+ ReductionOps.push_back(nullptr);
}
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
QualType Type;
- VarDecl *VD = nullptr;
- if (DE) {
- auto D = DE->getDecl();
- VD = cast<VarDecl>(D);
- Type = VD->getType();
- } else if (ASE) {
- Type = ASE->getType();
- auto *Base = ASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = dyn_cast<DeclRefExpr>(Base);
- if (DE)
- VD = dyn_cast<VarDecl>(DE->getDecl());
- if (!VD) {
- Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
- << 0 << Base->getSourceRange();
- continue;
- }
- } else if (OASE) {
+ auto *ASE = dyn_cast<ArraySubscriptExpr>(RefExpr->IgnoreParens());
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(RefExpr->IgnoreParens());
+ if (ASE)
+ Type = ASE->getType().getNonReferenceType();
+ else if (OASE) {
auto BaseType = OMPArraySectionExpr::getBaseOriginalType(OASE->getBase());
if (auto *ATy = BaseType->getAsArrayTypeUnsafe())
Type = ATy->getElementType();
else
Type = BaseType->getPointeeType();
- auto *Base = OASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempOASE = dyn_cast<OMPArraySectionExpr>(Base))
- Base = TempOASE->getBase()->IgnoreParenImpCasts();
- while (auto *TempASE = dyn_cast<ArraySubscriptExpr>(Base))
- Base = TempASE->getBase()->IgnoreParenImpCasts();
- DE = dyn_cast<DeclRefExpr>(Base);
- if (DE)
- VD = dyn_cast<VarDecl>(DE->getDecl());
- if (!VD) {
- Diag(Base->getExprLoc(), diag::err_omp_expected_base_var_name)
- << 1 << Base->getSourceRange();
- continue;
- }
- }
+ Type = Type.getNonReferenceType();
+ } else
+ Type = Context.getBaseElementType(D->getType().getNonReferenceType());
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.9.3.3, Restrictions, C/C++, p.3]
// A variable that appears in a private clause must not have an incomplete
@@ -7312,39 +9113,27 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
diag::err_omp_reduction_incomplete_type))
continue;
// OpenMP [2.14.3.6, reduction clause, Restrictions]
- // Arrays may not appear in a reduction clause.
- if (Type.getNonReferenceType()->isArrayType()) {
- Diag(ELoc, diag::err_omp_reduction_type_array) << Type << ERange;
- if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- }
- continue;
- }
- // OpenMP [2.14.3.6, reduction clause, Restrictions]
// A list item that appears in a reduction clause must not be
// const-qualified.
if (Type.getNonReferenceType().isConstant(Context)) {
Diag(ELoc, diag::err_omp_const_reduction_list_item)
<< getOpenMPClauseName(OMPC_reduction) << Type << ERange;
if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
}
continue;
}
// OpenMP [2.9.3.6, Restrictions, C/C++, p.4]
// If a list-item is a reference type then it must bind to the same object
// for all threads of the team.
- if (!ASE && !OASE) {
+ if (!ASE && !OASE && VD) {
VarDecl *VDDef = VD->getDefinition();
- if (Type->isReferenceType() && VDDef) {
+ if (VD->getType()->isReferenceType() && VDDef) {
DSARefChecker Check(DSAStack);
if (Check.Visit(VDDef->getInit())) {
Diag(ELoc, diag::err_omp_reduction_ref_type_arg) << ERange;
@@ -7353,40 +9142,7 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
}
}
}
- // OpenMP [2.14.3.6, reduction clause, Restrictions]
- // The type of a list item that appears in a reduction clause must be valid
- // for the reduction-identifier. For a max or min reduction in C, the type
- // of the list item must be an allowed arithmetic data type: char, int,
- // float, double, or _Bool, possibly modified with long, short, signed, or
- // unsigned. For a max or min reduction in C++, the type of the list item
- // must be an allowed arithmetic data type: char, wchar_t, int, float,
- // double, or bool, possibly modified with long, short, signed, or unsigned.
- if ((BOK == BO_GT || BOK == BO_LT) &&
- !(Type->isScalarType() ||
- (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
- Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
- << getLangOpts().CPlusPlus;
- if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- }
- continue;
- }
- if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
- !getLangOpts().CPlusPlus && Type->isFloatingType()) {
- Diag(ELoc, diag::err_omp_clause_floating_type_arg);
- if (!ASE && !OASE) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- }
- continue;
- }
+
// OpenMP [2.14.1.1, Data-sharing Attribute Rules for Variables Referenced
// in a Construct]
// Variables with the predetermined data-sharing attributes may not be
@@ -7399,18 +9155,17 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
// but a list item can appear only once in the reduction clauses for that
// directive.
DSAStackTy::DSAVarData DVar;
- DVar = DSAStack->getTopDSA(VD, false);
+ DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind == OMPC_reduction) {
Diag(ELoc, diag::err_omp_once_referenced)
<< getOpenMPClauseName(OMPC_reduction);
- if (DVar.RefExpr) {
+ if (DVar.RefExpr)
Diag(DVar.RefExpr->getExprLoc(), diag::note_omp_referenced);
- }
} else if (DVar.CKind != OMPC_unknown) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_reduction);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
@@ -7421,24 +9176,91 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
OpenMPDirectiveKind CurrDir = DSAStack->getCurrentDirective();
if (isOpenMPWorksharingDirective(CurrDir) &&
!isOpenMPParallelDirective(CurrDir)) {
- DVar = DSAStack->getImplicitDSA(VD, true);
+ DVar = DSAStack->getImplicitDSA(D, true);
if (DVar.CKind != OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_reduction)
<< getOpenMPClauseName(OMPC_shared);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
+ continue;
+ }
+ }
+
+ // Try to find 'declare reduction' corresponding construct before using
+ // builtin/overloaded operators.
+ CXXCastPath BasePath;
+ ExprResult DeclareReductionRef = buildDeclareReductionRef(
+ *this, ELoc, ERange, DSAStack->getCurScope(), ReductionIdScopeSpec,
+ ReductionId, Type, BasePath, IR == ER ? nullptr : *IR);
+ if (DeclareReductionRef.isInvalid())
+ continue;
+ if (CurContext->isDependentContext() &&
+ (DeclareReductionRef.isUnset() ||
+ isa<UnresolvedLookupExpr>(DeclareReductionRef.get()))) {
+ Vars.push_back(RefExpr);
+ Privates.push_back(nullptr);
+ LHSs.push_back(nullptr);
+ RHSs.push_back(nullptr);
+ ReductionOps.push_back(DeclareReductionRef.get());
+ continue;
+ }
+ if (BOK == BO_Comma && DeclareReductionRef.isUnset()) {
+ // Not allowed reduction identifier is found.
+ Diag(ReductionId.getLocStart(),
+ diag::err_omp_unknown_reduction_identifier)
+ << Type << ReductionIdRange;
+ continue;
+ }
+
+ // OpenMP [2.14.3.6, reduction clause, Restrictions]
+ // The type of a list item that appears in a reduction clause must be valid
+ // for the reduction-identifier. For a max or min reduction in C, the type
+ // of the list item must be an allowed arithmetic data type: char, int,
+ // float, double, or _Bool, possibly modified with long, short, signed, or
+ // unsigned. For a max or min reduction in C++, the type of the list item
+ // must be an allowed arithmetic data type: char, wchar_t, int, float,
+ // double, or bool, possibly modified with long, short, signed, or unsigned.
+ if (DeclareReductionRef.isUnset()) {
+ if ((BOK == BO_GT || BOK == BO_LT) &&
+ !(Type->isScalarType() ||
+ (getLangOpts().CPlusPlus && Type->isArithmeticType()))) {
+ Diag(ELoc, diag::err_omp_clause_not_arithmetic_type_arg)
+ << getLangOpts().CPlusPlus;
+ if (!ASE && !OASE) {
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ continue;
+ }
+ if ((BOK == BO_OrAssign || BOK == BO_AndAssign || BOK == BO_XorAssign) &&
+ !getLangOpts().CPlusPlus && Type->isFloatingType()) {
+ Diag(ELoc, diag::err_omp_clause_floating_type_arg);
+ if (!ASE && !OASE) {
+ bool IsDecl = !VD ||
+ VD->isThisDeclarationADefinition(Context) ==
+ VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
continue;
}
}
Type = Type.getNonLValueExprType(Context).getUnqualifiedType();
auto *LHSVD = buildVarDecl(*this, ELoc, Type, ".reduction.lhs",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *RHSVD = buildVarDecl(*this, ELoc, Type, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *RHSVD = buildVarDecl(*this, ELoc, Type, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
auto PrivateTy = Type;
- if (OASE) {
- // For array sections only:
+ if (OASE ||
+ (!ASE &&
+ D->getType().getNonReferenceType()->isVariablyModifiedType())) {
+ // For arays/array sections only:
// Create pseudo array type for private copy. The size for this array will
// be generated during codegen.
// For array subscripts or single variables Private Ty is the same as Type
@@ -7447,162 +9269,227 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
Type, new (Context) OpaqueValueExpr(SourceLocation(),
Context.getSizeType(), VK_RValue),
ArrayType::Normal, /*IndexTypeQuals=*/0, SourceRange());
- }
+ } else if (!ASE && !OASE &&
+ Context.getAsArrayType(D->getType().getNonReferenceType()))
+ PrivateTy = D->getType().getNonReferenceType();
// Private copy.
- auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ auto *PrivateVD = buildVarDecl(*this, ELoc, PrivateTy, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
// Add initializer for private variable.
Expr *Init = nullptr;
- switch (BOK) {
- case BO_Add:
- case BO_Xor:
- case BO_Or:
- case BO_LOr:
- // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
- if (Type->isScalarType() || Type->isAnyComplexType()) {
- Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
- }
- break;
- case BO_Mul:
- case BO_LAnd:
- if (Type->isScalarType() || Type->isAnyComplexType()) {
- // '*' and '&&' reduction ops - initializer is '1'.
- Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
- }
- break;
- case BO_And: {
- // '&' reduction op - initializer is '~0'.
- QualType OrigType = Type;
- if (auto *ComplexTy = OrigType->getAs<ComplexType>()) {
- Type = ComplexTy->getElementType();
- }
- if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue =
- llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
- /*isIEEE=*/true);
- Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
- Type, ELoc);
- } else if (Type->isScalarType()) {
- auto Size = Context.getTypeSize(Type);
- QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
- llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
- Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
+ auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
+ if (DeclareReductionRef.isUsable()) {
+ auto *DRDRef = DeclareReductionRef.getAs<DeclRefExpr>();
+ auto *DRD = cast<OMPDeclareReductionDecl>(DRDRef->getDecl());
+ if (DRD->getInitializer()) {
+ Init = DRDRef;
+ RHSVD->setInit(DRDRef);
+ RHSVD->setInitStyle(VarDecl::CallInit);
}
- if (Init && OrigType->isAnyComplexType()) {
- // Init = 0xFFFF + 0xFFFFi;
- auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
- Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ } else {
+ switch (BOK) {
+ case BO_Add:
+ case BO_Xor:
+ case BO_Or:
+ case BO_LOr:
+ // '+', '-', '^', '|', '||' reduction ops - initializer is '0'.
+ if (Type->isScalarType() || Type->isAnyComplexType())
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/0).get();
+ break;
+ case BO_Mul:
+ case BO_LAnd:
+ if (Type->isScalarType() || Type->isAnyComplexType()) {
+ // '*' and '&&' reduction ops - initializer is '1'.
+ Init = ActOnIntegerConstant(ELoc, /*Val=*/1).get();
+ }
+ break;
+ case BO_And: {
+ // '&' reduction op - initializer is '~0'.
+ QualType OrigType = Type;
+ if (auto *ComplexTy = OrigType->getAs<ComplexType>())
+ Type = ComplexTy->getElementType();
+ if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue =
+ llvm::APFloat::getAllOnesValue(Context.getTypeSize(Type),
+ /*isIEEE=*/true);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
+ } else if (Type->isScalarType()) {
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy = Context.getIntTypeForBitwidth(Size, /*Signed=*/0);
+ llvm::APInt InitValue = llvm::APInt::getAllOnesValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ }
+ if (Init && OrigType->isAnyComplexType()) {
+ // Init = 0xFFFF + 0xFFFFi;
+ auto *Im = new (Context) ImaginaryLiteral(Init, OrigType);
+ Init = CreateBuiltinBinOp(ELoc, BO_Add, Init, Im).get();
+ }
+ Type = OrigType;
+ break;
}
- Type = OrigType;
- break;
- }
- case BO_LT:
- case BO_GT: {
- // 'min' reduction op - initializer is 'Largest representable number in
- // the reduction list item type'.
- // 'max' reduction op - initializer is 'Least representable number in
- // the reduction list item type'.
- if (Type->isIntegerType() || Type->isPointerType()) {
- bool IsSigned = Type->hasSignedIntegerRepresentation();
- auto Size = Context.getTypeSize(Type);
- QualType IntTy =
- Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
- llvm::APInt InitValue =
- (BOK != BO_LT)
- ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
- : llvm::APInt::getMinValue(Size)
- : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
- : llvm::APInt::getMaxValue(Size);
- Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
- if (Type->isPointerType()) {
- // Cast to pointer type.
- auto CastExpr = BuildCStyleCastExpr(
- SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
- SourceLocation(), Init);
- if (CastExpr.isInvalid())
- continue;
- Init = CastExpr.get();
+ case BO_LT:
+ case BO_GT: {
+ // 'min' reduction op - initializer is 'Largest representable number in
+ // the reduction list item type'.
+ // 'max' reduction op - initializer is 'Least representable number in
+ // the reduction list item type'.
+ if (Type->isIntegerType() || Type->isPointerType()) {
+ bool IsSigned = Type->hasSignedIntegerRepresentation();
+ auto Size = Context.getTypeSize(Type);
+ QualType IntTy =
+ Context.getIntTypeForBitwidth(Size, /*Signed=*/IsSigned);
+ llvm::APInt InitValue =
+ (BOK != BO_LT)
+ ? IsSigned ? llvm::APInt::getSignedMinValue(Size)
+ : llvm::APInt::getMinValue(Size)
+ : IsSigned ? llvm::APInt::getSignedMaxValue(Size)
+ : llvm::APInt::getMaxValue(Size);
+ Init = IntegerLiteral::Create(Context, InitValue, IntTy, ELoc);
+ if (Type->isPointerType()) {
+ // Cast to pointer type.
+ auto CastExpr = BuildCStyleCastExpr(
+ SourceLocation(), Context.getTrivialTypeSourceInfo(Type, ELoc),
+ SourceLocation(), Init);
+ if (CastExpr.isInvalid())
+ continue;
+ Init = CastExpr.get();
+ }
+ } else if (Type->isRealFloatingType()) {
+ llvm::APFloat InitValue = llvm::APFloat::getLargest(
+ Context.getFloatTypeSemantics(Type), BOK != BO_LT);
+ Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
+ Type, ELoc);
}
- } else if (Type->isRealFloatingType()) {
- llvm::APFloat InitValue = llvm::APFloat::getLargest(
- Context.getFloatTypeSemantics(Type), BOK != BO_LT);
- Init = FloatingLiteral::Create(Context, InitValue, /*isexact=*/true,
- Type, ELoc);
+ break;
+ }
+ case BO_PtrMemD:
+ case BO_PtrMemI:
+ case BO_MulAssign:
+ case BO_Div:
+ case BO_Rem:
+ case BO_Sub:
+ case BO_Shl:
+ case BO_Shr:
+ case BO_LE:
+ case BO_GE:
+ case BO_EQ:
+ case BO_NE:
+ case BO_AndAssign:
+ case BO_XorAssign:
+ case BO_OrAssign:
+ case BO_Assign:
+ case BO_AddAssign:
+ case BO_SubAssign:
+ case BO_DivAssign:
+ case BO_RemAssign:
+ case BO_ShlAssign:
+ case BO_ShrAssign:
+ case BO_Comma:
+ llvm_unreachable("Unexpected reduction operation");
}
- break;
}
- case BO_PtrMemD:
- case BO_PtrMemI:
- case BO_MulAssign:
- case BO_Div:
- case BO_Rem:
- case BO_Sub:
- case BO_Shl:
- case BO_Shr:
- case BO_LE:
- case BO_GE:
- case BO_EQ:
- case BO_NE:
- case BO_AndAssign:
- case BO_XorAssign:
- case BO_OrAssign:
- case BO_Assign:
- case BO_AddAssign:
- case BO_SubAssign:
- case BO_DivAssign:
- case BO_RemAssign:
- case BO_ShlAssign:
- case BO_ShrAssign:
- case BO_Comma:
- llvm_unreachable("Unexpected reduction operation");
- }
- if (Init) {
+ if (Init && DeclareReductionRef.isUnset()) {
AddInitializerToDecl(RHSVD, Init, /*DirectInit=*/false,
/*TypeMayContainAuto=*/false);
- } else
+ } else if (!Init)
ActOnUninitializedDecl(RHSVD, /*TypeMayContainAuto=*/false);
- if (!RHSVD->hasInit()) {
+ if (RHSVD->isInvalidDecl())
+ continue;
+ if (!RHSVD->hasInit() && DeclareReductionRef.isUnset()) {
Diag(ELoc, diag::err_omp_reduction_id_not_compatible) << Type
<< ReductionIdRange;
- if (VD) {
- bool IsDecl = VD->isThisDeclarationADefinition(Context) ==
- VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- }
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
continue;
}
// Store initializer for single element in private copy. Will be used during
// codegen.
PrivateVD->setInit(RHSVD->getInit());
PrivateVD->setInitStyle(RHSVD->getInitStyle());
- auto *LHSDRE = buildDeclRefExpr(*this, LHSVD, Type, ELoc);
- auto *RHSDRE = buildDeclRefExpr(*this, RHSVD, Type, ELoc);
auto *PrivateDRE = buildDeclRefExpr(*this, PrivateVD, PrivateTy, ELoc);
- ExprResult ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(), BOK,
- LHSDRE, RHSDRE);
- if (ReductionOp.isUsable()) {
- if (BOK != BO_LT && BOK != BO_GT) {
- ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ReductionOp.get());
- } else {
- auto *ConditionalOp = new (Context) ConditionalOperator(
- ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
- RHSDRE, Type, VK_LValue, OK_Ordinary);
- ReductionOp =
- BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
- BO_Assign, LHSDRE, ConditionalOp);
+ ExprResult ReductionOp;
+ if (DeclareReductionRef.isUsable()) {
+ QualType RedTy = DeclareReductionRef.get()->getType();
+ QualType PtrRedTy = Context.getPointerType(RedTy);
+ ExprResult LHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, LHSDRE);
+ ExprResult RHS = CreateBuiltinUnaryOp(ELoc, UO_AddrOf, RHSDRE);
+ if (!BasePath.empty()) {
+ LHS = DefaultLvalueConversion(LHS.get());
+ RHS = DefaultLvalueConversion(RHS.get());
+ LHS = ImplicitCastExpr::Create(Context, PtrRedTy,
+ CK_UncheckedDerivedToBase, LHS.get(),
+ &BasePath, LHS.get()->getValueKind());
+ RHS = ImplicitCastExpr::Create(Context, PtrRedTy,
+ CK_UncheckedDerivedToBase, RHS.get(),
+ &BasePath, RHS.get()->getValueKind());
}
- ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ FunctionProtoType::ExtProtoInfo EPI;
+ QualType Params[] = {PtrRedTy, PtrRedTy};
+ QualType FnTy = Context.getFunctionType(Context.VoidTy, Params, EPI);
+ auto *OVE = new (Context) OpaqueValueExpr(
+ ELoc, Context.getPointerType(FnTy), VK_RValue, OK_Ordinary,
+ DefaultLvalueConversion(DeclareReductionRef.get()).get());
+ Expr *Args[] = {LHS.get(), RHS.get()};
+ ReductionOp = new (Context)
+ CallExpr(Context, OVE, Args, Context.VoidTy, VK_RValue, ELoc);
+ } else {
+ ReductionOp = BuildBinOp(DSAStack->getCurScope(),
+ ReductionId.getLocStart(), BOK, LHSDRE, RHSDRE);
+ if (ReductionOp.isUsable()) {
+ if (BOK != BO_LT && BOK != BO_GT) {
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ReductionOp.get());
+ } else {
+ auto *ConditionalOp = new (Context) ConditionalOperator(
+ ReductionOp.get(), SourceLocation(), LHSDRE, SourceLocation(),
+ RHSDRE, Type, VK_LValue, OK_Ordinary);
+ ReductionOp =
+ BuildBinOp(DSAStack->getCurScope(), ReductionId.getLocStart(),
+ BO_Assign, LHSDRE, ConditionalOp);
+ }
+ ReductionOp = ActOnFinishFullExpr(ReductionOp.get());
+ }
+ if (ReductionOp.isInvalid())
+ continue;
}
- if (ReductionOp.isInvalid())
- continue;
- DSAStack->addDSA(VD, DE, OMPC_reduction);
- Vars.push_back(RefExpr);
+ DeclRefExpr *Ref = nullptr;
+ Expr *VarsExpr = RefExpr->IgnoreParens();
+ if (!VD && !CurContext->isDependentContext()) {
+ if (ASE || OASE) {
+ TransformExprToCaptures RebuildToCapture(*this, D);
+ VarsExpr =
+ RebuildToCapture.TransformExpr(RefExpr->IgnoreParens()).get();
+ Ref = RebuildToCapture.getCapturedExpr();
+ } else {
+ VarsExpr = Ref =
+ buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ }
+ if (!IsOpenMPCapturedDecl(D)) {
+ ExprCaptures.push_back(Ref->getDecl());
+ if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
+ ExprResult RefRes = DefaultLvalueConversion(Ref);
+ if (!RefRes.isUsable())
+ continue;
+ ExprResult PostUpdateRes =
+ BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
+ SimpleRefExpr, RefRes.get());
+ if (!PostUpdateRes.isUsable())
+ continue;
+ ExprPostUpdates.push_back(
+ IgnoredValueConversions(PostUpdateRes.get()).get());
+ }
+ }
+ }
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_reduction, Ref);
+ Vars.push_back(VarsExpr);
Privates.push_back(PrivateDRE);
LHSs.push_back(LHSDRE);
RHSs.push_back(RHSDRE);
@@ -7615,7 +9502,67 @@ OMPClause *Sema::ActOnOpenMPReductionClause(
return OMPReductionClause::Create(
Context, StartLoc, LParenLoc, ColonLoc, EndLoc, Vars,
ReductionIdScopeSpec.getWithLocInContext(Context), ReductionId, Privates,
- LHSs, RHSs, ReductionOps);
+ LHSs, RHSs, ReductionOps, buildPreInits(Context, ExprCaptures),
+ buildPostUpdate(*this, ExprPostUpdates));
+}
+
+bool Sema::CheckOpenMPLinearModifier(OpenMPLinearClauseKind LinKind,
+ SourceLocation LinLoc) {
+ if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
+ LinKind == OMPC_LINEAR_unknown) {
+ Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+ return true;
+ }
+ return false;
+}
+
+bool Sema::CheckOpenMPLinearDecl(ValueDecl *D, SourceLocation ELoc,
+ OpenMPLinearClauseKind LinKind,
+ QualType Type) {
+ auto *VD = dyn_cast_or_null<VarDecl>(D);
+ // A variable must not have an incomplete type or a reference type.
+ if (RequireCompleteType(ELoc, Type, diag::err_omp_linear_incomplete_type))
+ return true;
+ if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
+ !Type->isReferenceType()) {
+ Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
+ << Type << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
+ return true;
+ }
+ Type = Type.getNonReferenceType();
+
+ // A list item must not be const-qualified.
+ if (Type.isConstant(Context)) {
+ Diag(ELoc, diag::err_omp_const_variable)
+ << getOpenMPClauseName(OMPC_linear);
+ if (D) {
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ return true;
+ }
+
+ // A list item must be of integral or pointer type.
+ Type = Type.getUnqualifiedType().getCanonicalType();
+ const auto *Ty = Type.getTypePtrOrNull();
+ if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
+ !Ty->isPointerType())) {
+ Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << Type;
+ if (D) {
+ bool IsDecl =
+ !VD ||
+ VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
+ Diag(D->getLocation(),
+ IsDecl ? diag::note_previous_decl : diag::note_defined_here)
+ << D;
+ }
+ return true;
+ }
+ return false;
}
OMPClause *Sema::ActOnOpenMPLinearClause(
@@ -7625,121 +9572,84 @@ OMPClause *Sema::ActOnOpenMPLinearClause(
SmallVector<Expr *, 8> Vars;
SmallVector<Expr *, 8> Privates;
SmallVector<Expr *, 8> Inits;
- if ((!LangOpts.CPlusPlus && LinKind != OMPC_LINEAR_val) ||
- LinKind == OMPC_LINEAR_unknown) {
- Diag(LinLoc, diag::err_omp_wrong_linear_modifier) << LangOpts.CPlusPlus;
+ SmallVector<Decl *, 4> ExprCaptures;
+ SmallVector<Expr *, 4> ExprPostUpdates;
+ if (CheckOpenMPLinearModifier(LinKind, LinLoc))
LinKind = OMPC_LINEAR_val;
- }
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP linear clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
Privates.push_back(nullptr);
Inits.push_back(nullptr);
- continue;
}
-
- // OpenMP [2.14.3.7, linear clause]
- // A list item that appears in a linear clause is subject to the private
- // clause semantics described in Section 2.14.3.3 on page 159 except as
- // noted. In addition, the value of the new list item on each iteration
- // of the associated loop(s) corresponds to the value of the original
- // list item before entering the construct plus the logical number of
- // the iteration times linear-step.
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.14.3.3, Restrictions, p.1]
- // A variable that is part of another variable (as an array or
- // structure element) cannot appear in a private clause.
- DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- VarDecl *VD = cast<VarDecl>(DE->getDecl());
+ QualType Type = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.3.7, linear clause]
// A list-item cannot appear in more than one linear clause.
// A list-item that appears in a linear clause cannot appear in any
// other data-sharing attribute clause.
- DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(VD, false);
+ DSAStackTy::DSAVarData DVar = DSAStack->getTopDSA(D, false);
if (DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa) << getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_linear);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
- continue;
- }
-
- QualType QType = VD->getType();
- if (QType->isDependentType() || QType->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
- Privates.push_back(nullptr);
- Inits.push_back(nullptr);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
- // A variable must not have an incomplete type or a reference type.
- if (RequireCompleteType(ELoc, QType,
- diag::err_omp_linear_incomplete_type)) {
- continue;
- }
- if ((LinKind == OMPC_LINEAR_uval || LinKind == OMPC_LINEAR_ref) &&
- !QType->isReferenceType()) {
- Diag(ELoc, diag::err_omp_wrong_linear_modifier_non_reference)
- << QType << getOpenMPSimpleClauseTypeName(OMPC_linear, LinKind);
+ if (CheckOpenMPLinearDecl(D, ELoc, LinKind, Type))
continue;
- }
- QType = QType.getNonReferenceType();
-
- // A list item must not be const-qualified.
- if (QType.isConstant(Context)) {
- Diag(ELoc, diag::err_omp_const_variable)
- << getOpenMPClauseName(OMPC_linear);
- bool IsDecl =
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- continue;
- }
-
- // A list item must be of integral or pointer type.
- QType = QType.getUnqualifiedType().getCanonicalType();
- const Type *Ty = QType.getTypePtrOrNull();
- if (!Ty || (!Ty->isDependentType() && !Ty->isIntegralType(Context) &&
- !Ty->isPointerType())) {
- Diag(ELoc, diag::err_omp_linear_expected_int_or_ptr) << QType;
- bool IsDecl =
- VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
- IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
- continue;
- }
+ Type = Type.getNonReferenceType().getUnqualifiedType().getCanonicalType();
// Build private copy of original var.
- auto *Private = buildVarDecl(*this, ELoc, QType, VD->getName(),
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *PrivateRef = buildDeclRefExpr(
- *this, Private, DE->getType().getUnqualifiedType(), DE->getExprLoc());
+ auto *Private = buildVarDecl(*this, ELoc, Type, D->getName(),
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *PrivateRef = buildDeclRefExpr(*this, Private, Type, ELoc);
// Build var to save initial value.
- VarDecl *Init = buildVarDecl(*this, ELoc, QType, ".linear.start");
+ VarDecl *Init = buildVarDecl(*this, ELoc, Type, ".linear.start");
Expr *InitExpr;
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && !CurContext->isDependentContext()) {
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false);
+ if (!IsOpenMPCapturedDecl(D)) {
+ ExprCaptures.push_back(Ref->getDecl());
+ if (Ref->getDecl()->hasAttr<OMPCaptureNoInitAttr>()) {
+ ExprResult RefRes = DefaultLvalueConversion(Ref);
+ if (!RefRes.isUsable())
+ continue;
+ ExprResult PostUpdateRes =
+ BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
+ SimpleRefExpr, RefRes.get());
+ if (!PostUpdateRes.isUsable())
+ continue;
+ ExprPostUpdates.push_back(
+ IgnoredValueConversions(PostUpdateRes.get()).get());
+ }
+ }
+ }
if (LinKind == OMPC_LINEAR_uval)
- InitExpr = VD->getInit();
+ InitExpr = VD ? VD->getInit() : SimpleRefExpr;
else
- InitExpr = DE;
+ InitExpr = VD ? SimpleRefExpr : Ref;
AddInitializerToDecl(Init, DefaultLvalueConversion(InitExpr).get(),
- /*DirectInit*/ false, /*TypeMayContainAuto*/ false);
- auto InitRef = buildDeclRefExpr(
- *this, Init, DE->getType().getUnqualifiedType(), DE->getExprLoc());
- DSAStack->addDSA(VD, DE, OMPC_linear);
- Vars.push_back(DE);
+ /*DirectInit=*/false, /*TypeMayContainAuto=*/false);
+ auto InitRef = buildDeclRefExpr(*this, Init, Type, ELoc);
+
+ DSAStack->addDSA(D, RefExpr->IgnoreParens(), OMPC_linear, Ref);
+ Vars.push_back((VD || CurContext->isDependentContext())
+ ? RefExpr->IgnoreParens()
+ : Ref);
Privates.push_back(PrivateRef);
Inits.push_back(InitRef);
}
@@ -7783,12 +9693,14 @@ OMPClause *Sema::ActOnOpenMPLinearClause(
return OMPLinearClause::Create(Context, StartLoc, LParenLoc, LinKind, LinLoc,
ColonLoc, EndLoc, Vars, Privates, Inits,
- StepExpr, CalcStepExpr);
+ StepExpr, CalcStepExpr,
+ buildPreInits(Context, ExprCaptures),
+ buildPostUpdate(*this, ExprPostUpdates));
}
static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
Expr *NumIterations, Sema &SemaRef,
- Scope *S) {
+ Scope *S, DSAStackTy *Stack) {
// Walk the vars and build update/final expressions for the CodeGen.
SmallVector<Expr *, 8> Updates;
SmallVector<Expr *, 8> Finals;
@@ -7798,17 +9710,35 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
// If linear-step is not specified it is assumed to be 1.
if (Step == nullptr)
Step = SemaRef.ActOnIntegerConstant(SourceLocation(), 1).get();
- else if (CalcStep)
+ else if (CalcStep) {
Step = cast<BinaryOperator>(CalcStep)->getLHS();
+ }
bool HasErrors = false;
auto CurInit = Clause.inits().begin();
auto CurPrivate = Clause.privates().begin();
auto LinKind = Clause.getModifier();
for (auto &RefExpr : Clause.varlists()) {
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(SemaRef, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false);
+ ValueDecl *D = Res.first;
+ if (Res.second || !D) {
+ Updates.push_back(nullptr);
+ Finals.push_back(nullptr);
+ HasErrors = true;
+ continue;
+ }
+ if (auto *CED = dyn_cast<OMPCapturedExprDecl>(D)) {
+ D = cast<MemberExpr>(CED->getInit()->IgnoreParenImpCasts())
+ ->getMemberDecl();
+ }
+ auto &&Info = Stack->isLoopControlVariable(D);
Expr *InitExpr = *CurInit;
// Build privatized reference to the current linear var.
- auto DE = cast<DeclRefExpr>(RefExpr);
+ auto DE = cast<DeclRefExpr>(SimpleRefExpr);
Expr *CapturedRef;
if (LinKind == OMPC_LINEAR_uval)
CapturedRef = cast<VarDecl>(DE->getDecl())->getInit();
@@ -7819,18 +9749,27 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
/*RefersToCapture=*/true);
// Build update: Var = InitExpr + IV * Step
- ExprResult Update =
- BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
- InitExpr, IV, Step, /* Subtract */ false);
+ ExprResult Update;
+ if (!Info.first) {
+ Update =
+ BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), *CurPrivate,
+ InitExpr, IV, Step, /* Subtract */ false);
+ } else
+ Update = *CurPrivate;
Update = SemaRef.ActOnFinishFullExpr(Update.get(), DE->getLocStart(),
/*DiscardedValue=*/true);
// Build final: Var = InitExpr + NumIterations * Step
- ExprResult Final =
- BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
- InitExpr, NumIterations, Step, /* Subtract */ false);
+ ExprResult Final;
+ if (!Info.first) {
+ Final = BuildCounterUpdate(SemaRef, S, RefExpr->getExprLoc(), CapturedRef,
+ InitExpr, NumIterations, Step,
+ /* Subtract */ false);
+ } else
+ Final = *CurPrivate;
Final = SemaRef.ActOnFinishFullExpr(Final.get(), DE->getLocStart(),
/*DiscardedValue=*/true);
+
if (!Update.isUsable() || !Final.isUsable()) {
Updates.push_back(nullptr);
Finals.push_back(nullptr);
@@ -7839,7 +9778,8 @@ static bool FinishOpenMPLinearClause(OMPLinearClause &Clause, DeclRefExpr *IV,
Updates.push_back(Update.get());
Finals.push_back(Final.get());
}
- ++CurInit, ++CurPrivate;
+ ++CurInit;
+ ++CurPrivate;
}
Clause.setUpdates(Updates);
Clause.setFinals(Finals);
@@ -7852,52 +9792,55 @@ OMPClause *Sema::ActOnOpenMPAlignedClause(
SmallVector<Expr *, 8> Vars;
for (auto &RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP aligned clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ assert(RefExpr && "NULL expr in OpenMP linear clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
- continue;
}
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- VarDecl *VD = cast<VarDecl>(DE->getDecl());
+ QualType QType = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.8.1, simd construct, Restrictions]
// The type of list items appearing in the aligned clause must be
// array, pointer, reference to array, or reference to pointer.
- QualType QType = VD->getType();
QType = QType.getNonReferenceType().getUnqualifiedType().getCanonicalType();
const Type *Ty = QType.getTypePtrOrNull();
- if (!Ty || (!Ty->isDependentType() && !Ty->isArrayType() &&
- !Ty->isPointerType())) {
+ if (!Ty || (!Ty->isArrayType() && !Ty->isPointerType())) {
Diag(ELoc, diag::err_omp_aligned_expected_array_or_ptr)
- << QType << getLangOpts().CPlusPlus << RefExpr->getSourceRange();
+ << QType << getLangOpts().CPlusPlus << ERange;
bool IsDecl =
+ !VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
continue;
}
// OpenMP [2.8.1, simd construct, Restrictions]
// A list-item cannot appear in more than one aligned clause.
- if (DeclRefExpr *PrevRef = DSAStack->addUniqueAligned(VD, DE)) {
- Diag(ELoc, diag::err_omp_aligned_twice) << RefExpr->getSourceRange();
+ if (Expr *PrevRef = DSAStack->addUniqueAligned(D, SimpleRefExpr)) {
+ Diag(ELoc, diag::err_omp_aligned_twice) << 0 << ERange;
Diag(PrevRef->getExprLoc(), diag::note_omp_explicit_dsa)
<< getOpenMPClauseName(OMPC_aligned);
continue;
}
- Vars.push_back(DE);
+ DeclRefExpr *Ref = nullptr;
+ if (!VD && IsOpenMPCapturedDecl(D))
+ Ref = buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/true);
+ Vars.push_back(DefaultFunctionArrayConversion(
+ (VD || !Ref) ? RefExpr->IgnoreParens() : Ref)
+ .get());
}
// OpenMP [2.8.1, simd construct, Description]
@@ -7945,7 +9888,8 @@ OMPClause *Sema::ActOnOpenMPCopyinClause(ArrayRef<Expr *> VarList,
// A list item that appears in a copyin clause must be threadprivate.
DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ Diag(ELoc, diag::err_omp_expected_var_name_member_expr)
+ << 0 << RefExpr->getSourceRange();
continue;
}
@@ -8020,51 +9964,37 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
SmallVector<Expr *, 8> DstExprs;
SmallVector<Expr *, 8> AssignmentOps;
for (auto &RefExpr : VarList) {
- assert(RefExpr && "NULL expr in OpenMP copyprivate clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
+ assert(RefExpr && "NULL expr in OpenMP linear clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange,
+ /*AllowArraySection=*/false);
+ if (Res.second) {
// It will be analyzed later.
Vars.push_back(RefExpr);
SrcExprs.push_back(nullptr);
DstExprs.push_back(nullptr);
AssignmentOps.push_back(nullptr);
- continue;
}
-
- SourceLocation ELoc = RefExpr->getExprLoc();
- // OpenMP [2.1, C/C++]
- // A list item is a variable name.
- // OpenMP [2.14.4.1, Restrictions, p.1]
- // A list item that appears in a copyin clause must be threadprivate.
- DeclRefExpr *DE = dyn_cast<DeclRefExpr>(RefExpr);
- if (!DE || !isa<VarDecl>(DE->getDecl())) {
- Diag(ELoc, diag::err_omp_expected_var_name) << RefExpr->getSourceRange();
+ ValueDecl *D = Res.first;
+ if (!D)
continue;
- }
- Decl *D = DE->getDecl();
- VarDecl *VD = cast<VarDecl>(D);
-
- QualType Type = VD->getType();
- if (Type->isDependentType() || Type->isInstantiationDependentType()) {
- // It will be analyzed later.
- Vars.push_back(DE);
- SrcExprs.push_back(nullptr);
- DstExprs.push_back(nullptr);
- AssignmentOps.push_back(nullptr);
- continue;
- }
+ QualType Type = D->getType();
+ auto *VD = dyn_cast<VarDecl>(D);
// OpenMP [2.14.4.2, Restrictions, p.2]
// A list item that appears in a copyprivate clause may not appear in a
// private or firstprivate clause on the single construct.
- if (!DSAStack->isThreadPrivate(VD)) {
- auto DVar = DSAStack->getTopDSA(VD, false);
+ if (!VD || !DSAStack->isThreadPrivate(VD)) {
+ auto DVar = DSAStack->getTopDSA(D, false);
if (DVar.CKind != OMPC_unknown && DVar.CKind != OMPC_copyprivate &&
DVar.RefExpr) {
Diag(ELoc, diag::err_omp_wrong_dsa)
<< getOpenMPClauseName(DVar.CKind)
<< getOpenMPClauseName(OMPC_copyprivate);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
@@ -8072,12 +10002,12 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
// All list items that appear in a copyprivate clause must be either
// threadprivate or private in the enclosing context.
if (DVar.CKind == OMPC_unknown) {
- DVar = DSAStack->getImplicitDSA(VD, false);
+ DVar = DSAStack->getImplicitDSA(D, false);
if (DVar.CKind == OMPC_shared) {
Diag(ELoc, diag::err_omp_required_access)
<< getOpenMPClauseName(OMPC_copyprivate)
<< "threadprivate or private in the enclosing context";
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ ReportOriginalDSA(*this, DSAStack, D, DVar);
continue;
}
}
@@ -8089,10 +10019,11 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
<< getOpenMPClauseName(OMPC_copyprivate) << Type
<< getOpenMPDirectiveName(DSAStack->getCurrentDirective());
bool IsDecl =
+ !VD ||
VD->isThisDeclarationADefinition(Context) == VarDecl::DeclarationOnly;
- Diag(VD->getLocation(),
+ Diag(D->getLocation(),
IsDecl ? diag::note_previous_decl : diag::note_defined_here)
- << VD;
+ << D;
continue;
}
@@ -8103,27 +10034,29 @@ OMPClause *Sema::ActOnOpenMPCopyprivateClause(ArrayRef<Expr *> VarList,
Type = Context.getBaseElementType(Type.getNonReferenceType())
.getUnqualifiedType();
auto *SrcVD =
- buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.src",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
- auto *PseudoSrcExpr =
- buildDeclRefExpr(*this, SrcVD, Type, DE->getExprLoc());
+ buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.src",
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
+ auto *PseudoSrcExpr = buildDeclRefExpr(*this, SrcVD, Type, ELoc);
auto *DstVD =
- buildVarDecl(*this, DE->getLocStart(), Type, ".copyprivate.dst",
- VD->hasAttrs() ? &VD->getAttrs() : nullptr);
+ buildVarDecl(*this, RefExpr->getLocStart(), Type, ".copyprivate.dst",
+ D->hasAttrs() ? &D->getAttrs() : nullptr);
auto *PseudoDstExpr =
- buildDeclRefExpr(*this, DstVD, Type, DE->getExprLoc());
- auto AssignmentOp = BuildBinOp(/*S=*/nullptr, DE->getExprLoc(), BO_Assign,
+ buildDeclRefExpr(*this, DstVD, Type, ELoc);
+ auto AssignmentOp = BuildBinOp(DSAStack->getCurScope(), ELoc, BO_Assign,
PseudoDstExpr, PseudoSrcExpr);
if (AssignmentOp.isInvalid())
continue;
- AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), DE->getExprLoc(),
+ AssignmentOp = ActOnFinishFullExpr(AssignmentOp.get(), ELoc,
/*DiscardedValue=*/true);
if (AssignmentOp.isInvalid())
continue;
// No need to mark vars as copyprivate, they are already threadprivate or
// implicitly private.
- Vars.push_back(DE);
+ assert(VD || IsOpenMPCapturedDecl(D));
+ Vars.push_back(
+ VD ? RefExpr->IgnoreParens()
+ : buildCapture(*this, D, SimpleRefExpr, /*WithInit=*/false));
SrcExprs.push_back(PseudoSrcExpr);
DstExprs.push_back(PseudoDstExpr);
AssignmentOps.push_back(AssignmentOp.get());
@@ -8168,6 +10101,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
return nullptr;
}
SmallVector<Expr *, 8> Vars;
+ DSAStackTy::OperatorOffsetTy OpsOffs;
llvm::APSInt DepCounter(/*BitWidth=*/32);
llvm::APSInt TotalDepCount(/*BitWidth=*/32);
if (DepKind == OMPC_DEPEND_sink) {
@@ -8180,8 +10114,7 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
DSAStack->getParentOrderedRegionParam()) {
for (auto &RefExpr : VarList) {
assert(RefExpr && "NULL expr in OpenMP shared clause.");
- if (isa<DependentScopeDeclRefExpr>(RefExpr) ||
- (DepKind == OMPC_DEPEND_sink && CurContext->isDependentContext())) {
+ if (isa<DependentScopeDeclRefExpr>(RefExpr)) {
// It will be analyzed later.
Vars.push_back(RefExpr);
continue;
@@ -8203,61 +10136,66 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
// directive, xi denotes the loop iteration variable of the i-th nested
// loop associated with the loop directive, and di is a constant
// non-negative integer.
+ if (CurContext->isDependentContext()) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ continue;
+ }
SimpleExpr = SimpleExpr->IgnoreImplicit();
- auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
- if (!DE) {
- OverloadedOperatorKind OOK = OO_None;
- SourceLocation OOLoc;
- Expr *LHS, *RHS;
- if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
- OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
- OOLoc = BO->getOperatorLoc();
- LHS = BO->getLHS()->IgnoreParenImpCasts();
- RHS = BO->getRHS()->IgnoreParenImpCasts();
- } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
- OOK = OCE->getOperator();
- OOLoc = OCE->getOperatorLoc();
- LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
- RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
- } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
- OOK = MCE->getMethodDecl()
- ->getNameInfo()
- .getName()
- .getCXXOverloadedOperator();
- OOLoc = MCE->getCallee()->getExprLoc();
- LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
- RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
- } else {
- Diag(ELoc, diag::err_omp_depend_sink_wrong_expr);
- continue;
- }
- DE = dyn_cast<DeclRefExpr>(LHS);
- if (!DE) {
- Diag(LHS->getExprLoc(),
- diag::err_omp_depend_sink_expected_loop_iteration)
- << DSAStack->getParentLoopControlVariable(
- DepCounter.getZExtValue());
- continue;
- }
- if (OOK != OO_Plus && OOK != OO_Minus) {
- Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
- continue;
- }
- ExprResult Res = VerifyPositiveIntegerConstantInClause(
+ OverloadedOperatorKind OOK = OO_None;
+ SourceLocation OOLoc;
+ Expr *LHS = SimpleExpr;
+ Expr *RHS = nullptr;
+ if (auto *BO = dyn_cast<BinaryOperator>(SimpleExpr)) {
+ OOK = BinaryOperator::getOverloadedOperator(BO->getOpcode());
+ OOLoc = BO->getOperatorLoc();
+ LHS = BO->getLHS()->IgnoreParenImpCasts();
+ RHS = BO->getRHS()->IgnoreParenImpCasts();
+ } else if (auto *OCE = dyn_cast<CXXOperatorCallExpr>(SimpleExpr)) {
+ OOK = OCE->getOperator();
+ OOLoc = OCE->getOperatorLoc();
+ LHS = OCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ RHS = OCE->getArg(/*Arg=*/1)->IgnoreParenImpCasts();
+ } else if (auto *MCE = dyn_cast<CXXMemberCallExpr>(SimpleExpr)) {
+ OOK = MCE->getMethodDecl()
+ ->getNameInfo()
+ .getName()
+ .getCXXOverloadedOperator();
+ OOLoc = MCE->getCallee()->getExprLoc();
+ LHS = MCE->getImplicitObjectArgument()->IgnoreParenImpCasts();
+ RHS = MCE->getArg(/*Arg=*/0)->IgnoreParenImpCasts();
+ }
+ SourceLocation ELoc;
+ SourceRange ERange;
+ auto Res = getPrivateItem(*this, LHS, ELoc, ERange,
+ /*AllowArraySection=*/false);
+ if (Res.second) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ if (OOK != OO_Plus && OOK != OO_Minus && (RHS || OOK != OO_None)) {
+ Diag(OOLoc, diag::err_omp_depend_sink_expected_plus_minus);
+ continue;
+ }
+ if (RHS) {
+ ExprResult RHSRes = VerifyPositiveIntegerConstantInClause(
RHS, OMPC_depend, /*StrictlyPositive=*/false);
- if (Res.isInvalid())
+ if (RHSRes.isInvalid())
continue;
}
- auto *VD = dyn_cast<VarDecl>(DE->getDecl());
if (!CurContext->isDependentContext() &&
DSAStack->getParentOrderedRegionParam() &&
- (!VD || DepCounter != DSAStack->isParentLoopControlVariable(VD))) {
- Diag(DE->getExprLoc(),
- diag::err_omp_depend_sink_expected_loop_iteration)
+ DepCounter != DSAStack->isParentLoopControlVariable(D).first) {
+ Diag(ELoc, diag::err_omp_depend_sink_expected_loop_iteration)
<< DSAStack->getParentLoopControlVariable(
- DepCounter.getZExtValue());
+ DepCounter.getZExtValue());
continue;
}
+ OpsOffs.push_back({RHS, OOK});
} else {
// OpenMP [2.11.1.1, Restrictions, p.3]
// A variable that is part of another variable (such as a field of a
@@ -8268,14 +10206,17 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
if (!RefExpr->IgnoreParenImpCasts()->isLValue() ||
(!ASE && !DE && !OASE) || (DE && !isa<VarDecl>(DE->getDecl())) ||
- (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
- !ASE->getBase()->getType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
- << RefExpr->getSourceRange();
+ (ASE &&
+ !ASE->getBase()
+ ->getType()
+ .getNonReferenceType()
+ ->isPointerType() &&
+ !ASE->getBase()->getType().getNonReferenceType()->isArrayType())) {
+ Diag(ELoc, diag::err_omp_expected_var_name_member_expr_or_array_item)
+ << 0 << RefExpr->getSourceRange();
continue;
}
}
-
Vars.push_back(RefExpr->IgnoreParenImpCasts());
}
@@ -8289,9 +10230,11 @@ Sema::ActOnOpenMPDependClause(OpenMPDependClauseKind DepKind,
Vars.empty())
return nullptr;
}
-
- return OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc, DepKind,
- DepLoc, ColonLoc, Vars);
+ auto *C = OMPDependClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ DepKind, DepLoc, ColonLoc, Vars);
+ if (DepKind == OMPC_DEPEND_sink || DepKind == OMPC_DEPEND_source)
+ DSAStack->addDoacrossDependClause(C, OpsOffs);
+ return C;
}
OMPClause *Sema::ActOnOpenMPDeviceClause(Expr *Device, SourceLocation StartLoc,
@@ -8366,125 +10309,950 @@ static bool CheckTypeMappable(SourceLocation SL, SourceRange SR, Sema &SemaRef,
return true;
}
-OMPClause *Sema::ActOnOpenMPMapClause(
- OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType,
- SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
- SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation EndLoc) {
- SmallVector<Expr *, 4> Vars;
+/// \brief Return true if it can be proven that the provided array expression
+/// (array section or array subscript) does NOT specify the whole size of the
+/// array whose base type is \a BaseQTy.
+static bool CheckArrayExpressionDoesNotReferToWholeSize(Sema &SemaRef,
+ const Expr *E,
+ QualType BaseQTy) {
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
+
+ // If this is an array subscript, it refers to the whole size if the size of
+ // the dimension is constant and equals 1. Also, an array section assumes the
+ // format of an array subscript if no colon is used.
+ if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid())) {
+ if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
+ return ATy->getSize().getSExtValue() != 1;
+ // Size can't be evaluated statically.
+ return false;
+ }
- for (auto &RE : VarList) {
- assert(RE && "Null expr in omp map");
- if (isa<DependentScopeDeclRefExpr>(RE)) {
- // It will be analyzed later.
- Vars.push_back(RE);
+ assert(OASE && "Expecting array section if not an array subscript.");
+ auto *LowerBound = OASE->getLowerBound();
+ auto *Length = OASE->getLength();
+
+ // If there is a lower bound that does not evaluates to zero, we are not
+ // convering the whole dimension.
+ if (LowerBound) {
+ llvm::APSInt ConstLowerBound;
+ if (!LowerBound->EvaluateAsInt(ConstLowerBound, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+ if (ConstLowerBound.getSExtValue())
+ return true;
+ }
+
+ // If we don't have a length we covering the whole dimension.
+ if (!Length)
+ return false;
+
+ // If the base is a pointer, we don't have a way to get the size of the
+ // pointee.
+ if (BaseQTy->isPointerType())
+ return false;
+
+ // We can only check if the length is the same as the size of the dimension
+ // if we have a constant array.
+ auto *CATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr());
+ if (!CATy)
+ return false;
+
+ llvm::APSInt ConstLength;
+ if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+
+ return CATy->getSize().getSExtValue() != ConstLength.getSExtValue();
+}
+
+// Return true if it can be proven that the provided array expression (array
+// section or array subscript) does NOT specify a single element of the array
+// whose base type is \a BaseQTy.
+static bool CheckArrayExpressionDoesNotReferToUnitySize(Sema &SemaRef,
+ const Expr *E,
+ QualType BaseQTy) {
+ auto *OASE = dyn_cast<OMPArraySectionExpr>(E);
+
+ // An array subscript always refer to a single element. Also, an array section
+ // assumes the format of an array subscript if no colon is used.
+ if (isa<ArraySubscriptExpr>(E) || (OASE && OASE->getColonLoc().isInvalid()))
+ return false;
+
+ assert(OASE && "Expecting array section if not an array subscript.");
+ auto *Length = OASE->getLength();
+
+ // If we don't have a length we have to check if the array has unitary size
+ // for this dimension. Also, we should always expect a length if the base type
+ // is pointer.
+ if (!Length) {
+ if (auto *ATy = dyn_cast<ConstantArrayType>(BaseQTy.getTypePtr()))
+ return ATy->getSize().getSExtValue() != 1;
+ // We cannot assume anything.
+ return false;
+ }
+
+ // Check if the length evaluates to 1.
+ llvm::APSInt ConstLength;
+ if (!Length->EvaluateAsInt(ConstLength, SemaRef.getASTContext()))
+ return false; // Can't get the integer value as a constant.
+
+ return ConstLength.getSExtValue() != 1;
+}
+
+// Return the expression of the base of the mappable expression or null if it
+// cannot be determined and do all the necessary checks to see if the expression
+// is valid as a standalone mappable expression. In the process, record all the
+// components of the expression.
+static Expr *CheckMapClauseExpressionBase(
+ Sema &SemaRef, Expr *E,
+ OMPClauseMappableExprCommon::MappableExprComponentList &CurComponents,
+ OpenMPClauseKind CKind) {
+ SourceLocation ELoc = E->getExprLoc();
+ SourceRange ERange = E->getSourceRange();
+
+ // The base of elements of list in a map clause have to be either:
+ // - a reference to variable or field.
+ // - a member expression.
+ // - an array expression.
+ //
+ // E.g. if we have the expression 'r.S.Arr[:12]', we want to retrieve the
+ // reference to 'r'.
+ //
+ // If we have:
+ //
+ // struct SS {
+ // Bla S;
+ // foo() {
+ // #pragma omp target map (S.Arr[:12]);
+ // }
+ // }
+ //
+ // We want to retrieve the member expression 'this->S';
+
+ Expr *RelevantExpr = nullptr;
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.2]
+ // If a list item is an array section, it must specify contiguous storage.
+ //
+ // For this restriction it is sufficient that we make sure only references
+ // to variables or fields and array expressions, and that no array sections
+ // exist except in the rightmost expression (unless they cover the whole
+ // dimension of the array). E.g. these would be invalid:
+ //
+ // r.ArrS[3:5].Arr[6:7]
+ //
+ // r.ArrS[3:5].x
+ //
+ // but these would be valid:
+ // r.ArrS[3].Arr[6:7]
+ //
+ // r.ArrS[3].x
+
+ bool AllowUnitySizeArraySection = true;
+ bool AllowWholeSizeArraySection = true;
+
+ while (!RelevantExpr) {
+ E = E->IgnoreParenImpCasts();
+
+ if (auto *CurE = dyn_cast<DeclRefExpr>(E)) {
+ if (!isa<VarDecl>(CurE->getDecl()))
+ break;
+
+ RelevantExpr = CurE;
+
+ // If we got a reference to a declaration, we should not expect any array
+ // section before that.
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
+
+ // Record the component.
+ CurComponents.push_back(OMPClauseMappableExprCommon::MappableComponent(
+ CurE, CurE->getDecl()));
+ continue;
+ }
+
+ if (auto *CurE = dyn_cast<MemberExpr>(E)) {
+ auto *BaseE = CurE->getBase()->IgnoreParenImpCasts();
+
+ if (isa<CXXThisExpr>(BaseE))
+ // We found a base expression: this->Val.
+ RelevantExpr = CurE;
+ else
+ E = BaseE;
+
+ if (!isa<FieldDecl>(CurE->getMemberDecl())) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_access_to_data_field)
+ << CurE->getSourceRange();
+ break;
+ }
+
+ auto *FD = cast<FieldDecl>(CurE->getMemberDecl());
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.3]
+ // A bit-field cannot appear in a map clause.
+ //
+ if (FD->isBitField()) {
+ SemaRef.Diag(ELoc, diag::err_omp_bit_fields_forbidden_in_clause)
+ << CurE->getSourceRange() << getOpenMPClauseName(CKind);
+ break;
+ }
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ QualType CurType = BaseE->getType().getNonReferenceType();
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.2]
+ // A list item cannot be a variable that is a member of a structure with
+ // a union type.
+ //
+ if (auto *RT = CurType->getAs<RecordType>())
+ if (RT->isUnionType()) {
+ SemaRef.Diag(ELoc, diag::err_omp_union_type_not_allowed)
+ << CurE->getSourceRange();
+ break;
+ }
+
+ // If we got a member expression, we should not expect any array section
+ // before that:
+ //
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.7]
+ // If a list item is an element of a structure, only the rightmost symbol
+ // of the variable reference can be an array section.
+ //
+ AllowUnitySizeArraySection = false;
+ AllowWholeSizeArraySection = false;
+
+ // Record the component.
+ CurComponents.push_back(
+ OMPClauseMappableExprCommon::MappableComponent(CurE, FD));
+ continue;
+ }
+
+ if (auto *CurE = dyn_cast<ArraySubscriptExpr>(E)) {
+ E = CurE->getBase()->IgnoreParenImpCasts();
+
+ if (!E->getType()->isAnyPointerType() && !E->getType()->isArrayType()) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << CurE->getSourceRange();
+ break;
+ }
+
+ // If we got an array subscript that express the whole dimension we
+ // can have any array expressions before. If it only expressing part of
+ // the dimension, we can only have unitary-size array expressions.
+ if (CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE,
+ E->getType()))
+ AllowWholeSizeArraySection = false;
+
+ // Record the component - we don't have any declaration associated.
+ CurComponents.push_back(
+ OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr));
+ continue;
+ }
+
+ if (auto *CurE = dyn_cast<OMPArraySectionExpr>(E)) {
+ E = CurE->getBase()->IgnoreParenImpCasts();
+
+ auto CurType =
+ OMPArraySectionExpr::getBaseOriginalType(E).getCanonicalType();
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ if (CurType->isReferenceType())
+ CurType = CurType->getPointeeType();
+
+ bool IsPointer = CurType->isAnyPointerType();
+
+ if (!IsPointer && !CurType->isArrayType()) {
+ SemaRef.Diag(ELoc, diag::err_omp_expected_base_var_name)
+ << 0 << CurE->getSourceRange();
+ break;
+ }
+
+ bool NotWhole =
+ CheckArrayExpressionDoesNotReferToWholeSize(SemaRef, CurE, CurType);
+ bool NotUnity =
+ CheckArrayExpressionDoesNotReferToUnitySize(SemaRef, CurE, CurType);
+
+ if (AllowWholeSizeArraySection && AllowUnitySizeArraySection) {
+ // Any array section is currently allowed.
+ //
+ // If this array section refers to the whole dimension we can still
+ // accept other array sections before this one, except if the base is a
+ // pointer. Otherwise, only unitary sections are accepted.
+ if (NotWhole || IsPointer)
+ AllowWholeSizeArraySection = false;
+ } else if ((AllowUnitySizeArraySection && NotUnity) ||
+ (AllowWholeSizeArraySection && NotWhole)) {
+ // A unity or whole array section is not allowed and that is not
+ // compatible with the properties of the current array section.
+ SemaRef.Diag(
+ ELoc, diag::err_array_section_does_not_specify_contiguous_storage)
+ << CurE->getSourceRange();
+ break;
+ }
+
+ // Record the component - we don't have any declaration associated.
+ CurComponents.push_back(
+ OMPClauseMappableExprCommon::MappableComponent(CurE, nullptr));
continue;
}
+
+ // If nothing else worked, this is not a valid map clause expression.
+ SemaRef.Diag(ELoc,
+ diag::err_omp_expected_named_var_member_or_array_expression)
+ << ERange;
+ break;
+ }
+
+ return RelevantExpr;
+}
+
+// Return true if expression E associated with value VD has conflicts with other
+// map information.
+static bool CheckMapConflicts(
+ Sema &SemaRef, DSAStackTy *DSAS, ValueDecl *VD, Expr *E,
+ bool CurrentRegionOnly,
+ OMPClauseMappableExprCommon::MappableExprComponentListRef CurComponents,
+ OpenMPClauseKind CKind) {
+ assert(VD && E);
+ SourceLocation ELoc = E->getExprLoc();
+ SourceRange ERange = E->getSourceRange();
+
+ // In order to easily check the conflicts we need to match each component of
+ // the expression under test with the components of the expressions that are
+ // already in the stack.
+
+ assert(!CurComponents.empty() && "Map clause expression with no components!");
+ assert(CurComponents.back().getAssociatedDeclaration() == VD &&
+ "Map clause expression with unexpected base!");
+
+ // Variables to help detecting enclosing problems in data environment nests.
+ bool IsEnclosedByDataEnvironmentExpr = false;
+ const Expr *EnclosingExpr = nullptr;
+
+ bool FoundError = DSAS->checkMappableExprComponentListsForDecl(
+ VD, CurrentRegionOnly,
+ [&](OMPClauseMappableExprCommon::MappableExprComponentListRef
+ StackComponents) -> bool {
+
+ assert(!StackComponents.empty() &&
+ "Map clause expression with no components!");
+ assert(StackComponents.back().getAssociatedDeclaration() == VD &&
+ "Map clause expression with unexpected base!");
+
+ // The whole expression in the stack.
+ auto *RE = StackComponents.front().getAssociatedExpression();
+
+ // Expressions must start from the same base. Here we detect at which
+ // point both expressions diverge from each other and see if we can
+ // detect if the memory referred to both expressions is contiguous and
+ // do not overlap.
+ auto CI = CurComponents.rbegin();
+ auto CE = CurComponents.rend();
+ auto SI = StackComponents.rbegin();
+ auto SE = StackComponents.rend();
+ for (; CI != CE && SI != SE; ++CI, ++SI) {
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.3]
+ // At most one list item can be an array item derived from a given
+ // variable in map clauses of the same construct.
+ if (CurrentRegionOnly &&
+ (isa<ArraySubscriptExpr>(CI->getAssociatedExpression()) ||
+ isa<OMPArraySectionExpr>(CI->getAssociatedExpression())) &&
+ (isa<ArraySubscriptExpr>(SI->getAssociatedExpression()) ||
+ isa<OMPArraySectionExpr>(SI->getAssociatedExpression()))) {
+ SemaRef.Diag(CI->getAssociatedExpression()->getExprLoc(),
+ diag::err_omp_multiple_array_items_in_map_clause)
+ << CI->getAssociatedExpression()->getSourceRange();
+ SemaRef.Diag(SI->getAssociatedExpression()->getExprLoc(),
+ diag::note_used_here)
+ << SI->getAssociatedExpression()->getSourceRange();
+ return true;
+ }
+
+ // Do both expressions have the same kind?
+ if (CI->getAssociatedExpression()->getStmtClass() !=
+ SI->getAssociatedExpression()->getStmtClass())
+ break;
+
+ // Are we dealing with different variables/fields?
+ if (CI->getAssociatedDeclaration() != SI->getAssociatedDeclaration())
+ break;
+ }
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
+ // List items of map clauses in the same construct must not share
+ // original storage.
+ //
+ // If the expressions are exactly the same or one is a subset of the
+ // other, it means they are sharing storage.
+ if (CI == CE && SI == SE) {
+ if (CurrentRegionOnly) {
+ if (CKind == OMPC_map)
+ SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange;
+ else {
+ assert(CKind == OMPC_to || CKind == OMPC_from);
+ SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update)
+ << ERange;
+ }
+ SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
+ << RE->getSourceRange();
+ return true;
+ } else {
+ // If we find the same expression in the enclosing data environment,
+ // that is legal.
+ IsEnclosedByDataEnvironmentExpr = true;
+ return false;
+ }
+ }
+
+ QualType DerivedType =
+ std::prev(CI)->getAssociatedDeclaration()->getType();
+ SourceLocation DerivedLoc =
+ std::prev(CI)->getAssociatedExpression()->getExprLoc();
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type
+ // will be considered to be T for all purposes of this clause.
+ DerivedType = DerivedType.getNonReferenceType();
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C/C++, p.1]
+ // A variable for which the type is pointer and an array section
+ // derived from that variable must not appear as list items of map
+ // clauses of the same construct.
+ //
+ // Also, cover one of the cases in:
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
+ // If any part of the original storage of a list item has corresponding
+ // storage in the device data environment, all of the original storage
+ // must have corresponding storage in the device data environment.
+ //
+ if (DerivedType->isAnyPointerType()) {
+ if (CI == CE || SI == SE) {
+ SemaRef.Diag(
+ DerivedLoc,
+ diag::err_omp_pointer_mapped_along_with_derived_section)
+ << DerivedLoc;
+ } else {
+ assert(CI != CE && SI != SE);
+ SemaRef.Diag(DerivedLoc, diag::err_omp_same_pointer_derreferenced)
+ << DerivedLoc;
+ }
+ SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
+ << RE->getSourceRange();
+ return true;
+ }
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.4]
+ // List items of map clauses in the same construct must not share
+ // original storage.
+ //
+ // An expression is a subset of the other.
+ if (CurrentRegionOnly && (CI == CE || SI == SE)) {
+ if (CKind == OMPC_map)
+ SemaRef.Diag(ELoc, diag::err_omp_map_shared_storage) << ERange;
+ else {
+ assert(CKind == OMPC_to || CKind == OMPC_from);
+ SemaRef.Diag(ELoc, diag::err_omp_once_referenced_in_target_update)
+ << ERange;
+ }
+ SemaRef.Diag(RE->getExprLoc(), diag::note_used_here)
+ << RE->getSourceRange();
+ return true;
+ }
+
+ // The current expression uses the same base as other expression in the
+ // data environment but does not contain it completely.
+ if (!CurrentRegionOnly && SI != SE)
+ EnclosingExpr = RE;
+
+ // The current expression is a subset of the expression in the data
+ // environment.
+ IsEnclosedByDataEnvironmentExpr |=
+ (!CurrentRegionOnly && CI != CE && SI == SE);
+
+ return false;
+ });
+
+ if (CurrentRegionOnly)
+ return FoundError;
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.5]
+ // If any part of the original storage of a list item has corresponding
+ // storage in the device data environment, all of the original storage must
+ // have corresponding storage in the device data environment.
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.6]
+ // If a list item is an element of a structure, and a different element of
+ // the structure has a corresponding list item in the device data environment
+ // prior to a task encountering the construct associated with the map clause,
+ // then the list item must also have a corresponding list item in the device
+ // data environment prior to the task encountering the construct.
+ //
+ if (EnclosingExpr && !IsEnclosedByDataEnvironmentExpr) {
+ SemaRef.Diag(ELoc,
+ diag::err_omp_original_storage_is_shared_and_does_not_contain)
+ << ERange;
+ SemaRef.Diag(EnclosingExpr->getExprLoc(), diag::note_used_here)
+ << EnclosingExpr->getSourceRange();
+ return true;
+ }
+
+ return FoundError;
+}
+
+namespace {
+// Utility struct that gathers all the related lists associated with a mappable
+// expression.
+struct MappableVarListInfo final {
+ // The list of expressions.
+ ArrayRef<Expr *> VarList;
+ // The list of processed expressions.
+ SmallVector<Expr *, 16> ProcessedVarList;
+ // The mappble components for each expression.
+ OMPClauseMappableExprCommon::MappableExprComponentLists VarComponents;
+ // The base declaration of the variable.
+ SmallVector<ValueDecl *, 16> VarBaseDeclarations;
+
+ MappableVarListInfo(ArrayRef<Expr *> VarList) : VarList(VarList) {
+ // We have a list of components and base declarations for each entry in the
+ // variable list.
+ VarComponents.reserve(VarList.size());
+ VarBaseDeclarations.reserve(VarList.size());
+ }
+};
+}
+
+// Check the validity of the provided variable list for the provided clause kind
+// \a CKind. In the check process the valid expressions, and mappable expression
+// components and variables are extracted and used to fill \a Vars,
+// \a ClauseComponents, and \a ClauseBaseDeclarations. \a MapType and
+// \a IsMapTypeImplicit are expected to be valid if the clause kind is 'map'.
+static void
+checkMappableExpressionList(Sema &SemaRef, DSAStackTy *DSAS,
+ OpenMPClauseKind CKind, MappableVarListInfo &MVLI,
+ SourceLocation StartLoc,
+ OpenMPMapClauseKind MapType = OMPC_MAP_unknown,
+ bool IsMapTypeImplicit = false) {
+ // We only expect mappable expressions in 'to', 'from', and 'map' clauses.
+ assert((CKind == OMPC_map || CKind == OMPC_to || CKind == OMPC_from) &&
+ "Unexpected clause kind with mappable expressions!");
+
+ // Keep track of the mappable components and base declarations in this clause.
+ // Each entry in the list is going to have a list of components associated. We
+ // record each set of the components so that we can build the clause later on.
+ // In the end we should have the same amount of declarations and component
+ // lists.
+
+ for (auto &RE : MVLI.VarList) {
+ assert(RE && "Null expr in omp to/from/map clause");
SourceLocation ELoc = RE->getExprLoc();
- // OpenMP [2.14.5, Restrictions]
- // A variable that is part of another variable (such as field of a
- // structure) but is not an array element or an array section cannot appear
- // in a map clause.
auto *VE = RE->IgnoreParenLValueCasts();
if (VE->isValueDependent() || VE->isTypeDependent() ||
VE->isInstantiationDependent() ||
VE->containsUnexpandedParameterPack()) {
- // It will be analyzed later.
- Vars.push_back(RE);
+ // We can only analyze this information once the missing information is
+ // resolved.
+ MVLI.ProcessedVarList.push_back(RE);
continue;
}
auto *SimpleExpr = RE->IgnoreParenCasts();
- auto *DE = dyn_cast<DeclRefExpr>(SimpleExpr);
- auto *ASE = dyn_cast<ArraySubscriptExpr>(SimpleExpr);
- auto *OASE = dyn_cast<OMPArraySectionExpr>(SimpleExpr);
-
- if (!RE->IgnoreParenImpCasts()->isLValue() ||
- (!OASE && !ASE && !DE) ||
- (DE && !isa<VarDecl>(DE->getDecl())) ||
- (ASE && !ASE->getBase()->getType()->isAnyPointerType() &&
- !ASE->getBase()->getType()->isArrayType())) {
- Diag(ELoc, diag::err_omp_expected_var_name_or_array_item)
- << RE->getSourceRange();
+
+ if (!RE->IgnoreParenImpCasts()->isLValue()) {
+ SemaRef.Diag(ELoc,
+ diag::err_omp_expected_named_var_member_or_array_expression)
+ << RE->getSourceRange();
continue;
}
- Decl *D = nullptr;
- if (DE) {
- D = DE->getDecl();
- } else if (ASE) {
- auto *B = ASE->getBase()->IgnoreParenCasts();
- D = dyn_cast<DeclRefExpr>(B)->getDecl();
- } else if (OASE) {
- auto *B = OASE->getBase();
- D = dyn_cast<DeclRefExpr>(B)->getDecl();
- }
- assert(D && "Null decl on map clause.");
- auto *VD = cast<VarDecl>(D);
+ OMPClauseMappableExprCommon::MappableExprComponentList CurComponents;
+ ValueDecl *CurDeclaration = nullptr;
- // OpenMP [2.14.5, Restrictions, p.8]
+ // Obtain the array or member expression bases if required. Also, fill the
+ // components array with all the components identified in the process.
+ auto *BE =
+ CheckMapClauseExpressionBase(SemaRef, SimpleExpr, CurComponents, CKind);
+ if (!BE)
+ continue;
+
+ assert(!CurComponents.empty() &&
+ "Invalid mappable expression information.");
+
+ // For the following checks, we rely on the base declaration which is
+ // expected to be associated with the last component. The declaration is
+ // expected to be a variable or a field (if 'this' is being mapped).
+ CurDeclaration = CurComponents.back().getAssociatedDeclaration();
+ assert(CurDeclaration && "Null decl on map clause.");
+ assert(
+ CurDeclaration->isCanonicalDecl() &&
+ "Expecting components to have associated only canonical declarations.");
+
+ auto *VD = dyn_cast<VarDecl>(CurDeclaration);
+ auto *FD = dyn_cast<FieldDecl>(CurDeclaration);
+
+ assert((VD || FD) && "Only variables or fields are expected here!");
+ (void)FD;
+
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.10]
// threadprivate variables cannot appear in a map clause.
- if (DSAStack->isThreadPrivate(VD)) {
- auto DVar = DSAStack->getTopDSA(VD, false);
- Diag(ELoc, diag::err_omp_threadprivate_in_map);
- ReportOriginalDSA(*this, DSAStack, VD, DVar);
+ // OpenMP 4.5 [2.10.5, target update Construct]
+ // threadprivate variables cannot appear in a from clause.
+ if (VD && DSAS->isThreadPrivate(VD)) {
+ auto DVar = DSAS->getTopDSA(VD, false);
+ SemaRef.Diag(ELoc, diag::err_omp_threadprivate_in_clause)
+ << getOpenMPClauseName(CKind);
+ ReportOriginalDSA(SemaRef, DSAS, VD, DVar);
continue;
}
- // OpenMP [2.14.5, Restrictions, p.2]
- // At most one list item can be an array item derived from a given variable
- // in map clauses of the same construct.
- // OpenMP [2.14.5, Restrictions, p.3]
- // List items of map clauses in the same construct must not share original
- // storage.
- // OpenMP [2.14.5, Restrictions, C/C++, p.2]
- // A variable for which the type is pointer, reference to array, or
- // reference to pointer and an array section derived from that variable
- // must not appear as list items of map clauses of the same construct.
- DSAStackTy::MapInfo MI = DSAStack->IsMappedInCurrentRegion(VD);
- if (MI.RefExpr) {
- Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc;
- Diag(MI.RefExpr->getExprLoc(), diag::note_used_here)
- << MI.RefExpr->getSourceRange();
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct.
+
+ // Check conflicts with other map clause expressions. We check the conflicts
+ // with the current construct separately from the enclosing data
+ // environment, because the restrictions are different. We only have to
+ // check conflicts across regions for the map clauses.
+ if (CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr,
+ /*CurrentRegionOnly=*/true, CurComponents, CKind))
+ break;
+ if (CKind == OMPC_map &&
+ CheckMapConflicts(SemaRef, DSAS, CurDeclaration, SimpleExpr,
+ /*CurrentRegionOnly=*/false, CurComponents, CKind))
+ break;
+
+ // OpenMP 4.5 [2.10.5, target update Construct]
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, C++, p.1]
+ // If the type of a list item is a reference to a type T then the type will
+ // be considered to be T for all purposes of this clause.
+ QualType Type = CurDeclaration->getType().getNonReferenceType();
+
+ // OpenMP 4.5 [2.10.5, target update Construct, Restrictions, p.4]
+ // A list item in a to or from clause must have a mappable type.
+ // OpenMP 4.5 [2.15.5.1, map Clause, Restrictions, p.9]
+ // A list item must have a mappable type.
+ if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), SemaRef,
+ DSAS, Type))
continue;
+
+ if (CKind == OMPC_map) {
+ // target enter data
+ // OpenMP [2.10.2, Restrictions, p. 99]
+ // A map-type must be specified in all map clauses and must be either
+ // to or alloc.
+ OpenMPDirectiveKind DKind = DSAS->getCurrentDirective();
+ if (DKind == OMPD_target_enter_data &&
+ !(MapType == OMPC_MAP_to || MapType == OMPC_MAP_alloc)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
+ << (IsMapTypeImplicit ? 1 : 0)
+ << getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
+ << getOpenMPDirectiveName(DKind);
+ continue;
+ }
+
+ // target exit_data
+ // OpenMP [2.10.3, Restrictions, p. 102]
+ // A map-type must be specified in all map clauses and must be either
+ // from, release, or delete.
+ if (DKind == OMPD_target_exit_data &&
+ !(MapType == OMPC_MAP_from || MapType == OMPC_MAP_release ||
+ MapType == OMPC_MAP_delete)) {
+ SemaRef.Diag(StartLoc, diag::err_omp_invalid_map_type_for_directive)
+ << (IsMapTypeImplicit ? 1 : 0)
+ << getOpenMPSimpleClauseTypeName(OMPC_map, MapType)
+ << getOpenMPDirectiveName(DKind);
+ continue;
+ }
+
+ // OpenMP 4.5 [2.15.5.1, Restrictions, p.3]
+ // A list item cannot appear in both a map clause and a data-sharing
+ // attribute clause on the same construct
+ if (DKind == OMPD_target && VD) {
+ auto DVar = DSAS->getTopDSA(VD, false);
+ if (isOpenMPPrivate(DVar.CKind)) {
+ SemaRef.Diag(ELoc, diag::err_omp_variable_in_map_and_dsa)
+ << getOpenMPClauseName(DVar.CKind)
+ << getOpenMPDirectiveName(DSAS->getCurrentDirective());
+ ReportOriginalDSA(SemaRef, DSAS, CurDeclaration, DVar);
+ continue;
+ }
+ }
}
- // OpenMP [2.14.5, Restrictions, C/C++, p.3,4]
- // A variable for which the type is pointer, reference to array, or
- // reference to pointer must not appear as a list item if the enclosing
- // device data environment already contains an array section derived from
- // that variable.
- // An array section derived from a variable for which the type is pointer,
- // reference to array, or reference to pointer must not appear as a list
- // item if the enclosing device data environment already contains that
- // variable.
- QualType Type = VD->getType();
- MI = DSAStack->getMapInfoForVar(VD);
- if (MI.RefExpr && (isa<DeclRefExpr>(MI.RefExpr->IgnoreParenLValueCasts()) !=
- isa<DeclRefExpr>(VE)) &&
- (Type->isPointerType() || Type->isReferenceType())) {
- Diag(ELoc, diag::err_omp_map_shared_storage) << ELoc;
- Diag(MI.RefExpr->getExprLoc(), diag::note_used_here)
- << MI.RefExpr->getSourceRange();
- continue;
+ // Save the current expression.
+ MVLI.ProcessedVarList.push_back(RE);
+
+ // Store the components in the stack so that they can be used to check
+ // against other clauses later on.
+ DSAS->addMappableExpressionComponents(CurDeclaration, CurComponents);
+
+ // Save the components and declaration to create the clause. For purposes of
+ // the clause creation, any component list that has has base 'this' uses
+ // null as base declaration.
+ MVLI.VarComponents.resize(MVLI.VarComponents.size() + 1);
+ MVLI.VarComponents.back().append(CurComponents.begin(),
+ CurComponents.end());
+ MVLI.VarBaseDeclarations.push_back(isa<MemberExpr>(BE) ? nullptr
+ : CurDeclaration);
+ }
+}
+
+OMPClause *
+Sema::ActOnOpenMPMapClause(OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
+ SourceLocation MapLoc, SourceLocation ColonLoc,
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ MappableVarListInfo MVLI(VarList);
+ checkMappableExpressionList(*this, DSAStack, OMPC_map, MVLI, StartLoc,
+ MapType, IsMapTypeImplicit);
+
+ // We need to produce a map clause even if we don't have variables so that
+ // other diagnostics related with non-existing map clauses are accurate.
+ return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents, MapTypeModifier, MapType,
+ IsMapTypeImplicit, MapLoc);
+}
+
+QualType Sema::ActOnOpenMPDeclareReductionType(SourceLocation TyLoc,
+ TypeResult ParsedType) {
+ assert(ParsedType.isUsable());
+
+ QualType ReductionType = GetTypeFromParser(ParsedType.get());
+ if (ReductionType.isNull())
+ return QualType();
+
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions, C\C++
+ // A type name in a declare reduction directive cannot be a function type, an
+ // array type, a reference type, or a type qualified with const, volatile or
+ // restrict.
+ if (ReductionType.hasQualifiers()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 0;
+ return QualType();
+ }
+
+ if (ReductionType->isFunctionType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 1;
+ return QualType();
+ }
+ if (ReductionType->isReferenceType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 2;
+ return QualType();
+ }
+ if (ReductionType->isArrayType()) {
+ Diag(TyLoc, diag::err_omp_reduction_wrong_type) << 3;
+ return QualType();
+ }
+ return ReductionType;
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveStart(
+ Scope *S, DeclContext *DC, DeclarationName Name,
+ ArrayRef<std::pair<QualType, SourceLocation>> ReductionTypes,
+ AccessSpecifier AS, Decl *PrevDeclInScope) {
+ SmallVector<Decl *, 8> Decls;
+ Decls.reserve(ReductionTypes.size());
+
+ LookupResult Lookup(*this, Name, SourceLocation(), LookupOMPReductionName,
+ ForRedeclaration);
+ // [OpenMP 4.0], 2.15 declare reduction Directive, Restrictions
+ // A reduction-identifier may not be re-declared in the current scope for the
+ // same type or for a type that is compatible according to the base language
+ // rules.
+ llvm::DenseMap<QualType, SourceLocation> PreviousRedeclTypes;
+ OMPDeclareReductionDecl *PrevDRD = nullptr;
+ bool InCompoundScope = true;
+ if (S != nullptr) {
+ // Find previous declaration with the same name not referenced in other
+ // declarations.
+ FunctionScopeInfo *ParentFn = getEnclosingFunction();
+ InCompoundScope =
+ (ParentFn != nullptr) && !ParentFn->CompoundScopes.empty();
+ LookupName(Lookup, S);
+ FilterLookupForScope(Lookup, DC, S, /*ConsiderLinkage=*/false,
+ /*AllowInlineNamespace=*/false);
+ llvm::DenseMap<OMPDeclareReductionDecl *, bool> UsedAsPrevious;
+ auto Filter = Lookup.makeFilter();
+ while (Filter.hasNext()) {
+ auto *PrevDecl = cast<OMPDeclareReductionDecl>(Filter.next());
+ if (InCompoundScope) {
+ auto I = UsedAsPrevious.find(PrevDecl);
+ if (I == UsedAsPrevious.end())
+ UsedAsPrevious[PrevDecl] = false;
+ if (auto *D = PrevDecl->getPrevDeclInScope())
+ UsedAsPrevious[D] = true;
+ }
+ PreviousRedeclTypes[PrevDecl->getType().getCanonicalType()] =
+ PrevDecl->getLocation();
+ }
+ Filter.done();
+ if (InCompoundScope) {
+ for (auto &PrevData : UsedAsPrevious) {
+ if (!PrevData.second) {
+ PrevDRD = PrevData.first;
+ break;
+ }
+ }
}
+ } else if (PrevDeclInScope != nullptr) {
+ auto *PrevDRDInScope = PrevDRD =
+ cast<OMPDeclareReductionDecl>(PrevDeclInScope);
+ do {
+ PreviousRedeclTypes[PrevDRDInScope->getType().getCanonicalType()] =
+ PrevDRDInScope->getLocation();
+ PrevDRDInScope = PrevDRDInScope->getPrevDeclInScope();
+ } while (PrevDRDInScope != nullptr);
+ }
+ for (auto &TyData : ReductionTypes) {
+ auto I = PreviousRedeclTypes.find(TyData.first.getCanonicalType());
+ bool Invalid = false;
+ if (I != PreviousRedeclTypes.end()) {
+ Diag(TyData.second, diag::err_omp_declare_reduction_redefinition)
+ << TyData.first;
+ Diag(I->second, diag::note_previous_definition);
+ Invalid = true;
+ }
+ PreviousRedeclTypes[TyData.first.getCanonicalType()] = TyData.second;
+ auto *DRD = OMPDeclareReductionDecl::Create(Context, DC, TyData.second,
+ Name, TyData.first, PrevDRD);
+ DC->addDecl(DRD);
+ DRD->setAccess(AS);
+ Decls.push_back(DRD);
+ if (Invalid)
+ DRD->setInvalidDecl();
+ else
+ PrevDRD = DRD;
+ }
- // OpenMP [2.14.5, Restrictions, C/C++, p.7]
- // A list item must have a mappable type.
- if (!CheckTypeMappable(VE->getExprLoc(), VE->getSourceRange(), *this,
- DSAStack, Type))
- continue;
+ return DeclGroupPtrTy::make(
+ DeclGroupRef::Create(Context, Decls.begin(), Decls.size()));
+}
+
+void Sema::ActOnOpenMPDeclareReductionCombinerStart(Scope *S, Decl *D) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+
+ // Enter new function scope.
+ PushFunctionScope();
+ getCurFunction()->setHasBranchProtectedScope();
+ getCurFunction()->setHasOMPDeclareReductionCombiner();
+
+ if (S != nullptr)
+ PushDeclContext(S, DRD);
+ else
+ CurContext = DRD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
- Vars.push_back(RE);
- MI.RefExpr = RE;
- DSAStack->addMapInfoForVar(VD, MI);
+ QualType ReductionType = DRD->getType();
+ // Create 'T* omp_parm;T omp_in;'. All references to 'omp_in' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_in'
+ // uses semantics of argument handles by value, but it should be passed by
+ // reference. C lang does not support references, so pass all parameters as
+ // pointers.
+ // Create 'T omp_in;' variable.
+ auto *OmpInParm =
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_in");
+ // Create 'T* omp_parm;T omp_out;'. All references to 'omp_out' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_out'
+ // uses semantics of argument handles by value, but it should be passed by
+ // reference. C lang does not support references, so pass all parameters as
+ // pointers.
+ // Create 'T omp_out;' variable.
+ auto *OmpOutParm =
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_out");
+ if (S != nullptr) {
+ PushOnScopeChains(OmpInParm, S);
+ PushOnScopeChains(OmpOutParm, S);
+ } else {
+ DRD->addDecl(OmpInParm);
+ DRD->addDecl(OmpOutParm);
}
- if (Vars.empty())
- return nullptr;
+}
+
+void Sema::ActOnOpenMPDeclareReductionCombinerEnd(Decl *D, Expr *Combiner) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
+
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (Combiner != nullptr)
+ DRD->setCombiner(Combiner);
+ else
+ DRD->setInvalidDecl();
+}
+
+void Sema::ActOnOpenMPDeclareReductionInitializerStart(Scope *S, Decl *D) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+
+ // Enter new function scope.
+ PushFunctionScope();
+ getCurFunction()->setHasBranchProtectedScope();
+
+ if (S != nullptr)
+ PushDeclContext(S, DRD);
+ else
+ CurContext = DRD;
+
+ PushExpressionEvaluationContext(PotentiallyEvaluated);
+
+ QualType ReductionType = DRD->getType();
+ // Create 'T* omp_parm;T omp_priv;'. All references to 'omp_priv' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_priv'
+ // uses semantics of argument handles by value, but it should be passed by
+ // reference. C lang does not support references, so pass all parameters as
+ // pointers.
+ // Create 'T omp_priv;' variable.
+ auto *OmpPrivParm =
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_priv");
+ // Create 'T* omp_parm;T omp_orig;'. All references to 'omp_orig' will
+ // be replaced by '*omp_parm' during codegen. This required because 'omp_orig'
+ // uses semantics of argument handles by value, but it should be passed by
+ // reference. C lang does not support references, so pass all parameters as
+ // pointers.
+ // Create 'T omp_orig;' variable.
+ auto *OmpOrigParm =
+ buildVarDecl(*this, D->getLocation(), ReductionType, "omp_orig");
+ if (S != nullptr) {
+ PushOnScopeChains(OmpPrivParm, S);
+ PushOnScopeChains(OmpOrigParm, S);
+ } else {
+ DRD->addDecl(OmpPrivParm);
+ DRD->addDecl(OmpOrigParm);
+ }
+}
+
+void Sema::ActOnOpenMPDeclareReductionInitializerEnd(Decl *D,
+ Expr *Initializer) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ DiscardCleanupsInEvaluationContext();
+ PopExpressionEvaluationContext();
- return OMPMapClause::Create(Context, StartLoc, LParenLoc, EndLoc, Vars,
- MapTypeModifier, MapType, MapLoc);
+ PopDeclContext();
+ PopFunctionScopeInfo();
+
+ if (Initializer != nullptr)
+ DRD->setInitializer(Initializer);
+ else
+ DRD->setInvalidDecl();
+}
+
+Sema::DeclGroupPtrTy Sema::ActOnOpenMPDeclareReductionDirectiveEnd(
+ Scope *S, DeclGroupPtrTy DeclReductions, bool IsValid) {
+ for (auto *D : DeclReductions.get()) {
+ if (IsValid) {
+ auto *DRD = cast<OMPDeclareReductionDecl>(D);
+ if (S != nullptr)
+ PushOnScopeChains(DRD, S, /*AddToContext=*/false);
+ } else
+ D->setInvalidDecl();
+ }
+ return DeclReductions;
}
OMPClause *Sema::ActOnOpenMPNumTeamsClause(Expr *NumTeams,
@@ -8578,3 +11346,377 @@ OMPClause *Sema::ActOnOpenMPHintClause(Expr *Hint, SourceLocation StartLoc,
OMPHintClause(HintExpr.get(), StartLoc, LParenLoc, EndLoc);
}
+OMPClause *Sema::ActOnOpenMPDistScheduleClause(
+ OpenMPDistScheduleClauseKind Kind, Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation KindLoc, SourceLocation CommaLoc,
+ SourceLocation EndLoc) {
+ if (Kind == OMPC_DIST_SCHEDULE_unknown) {
+ std::string Values;
+ Values += "'";
+ Values += getOpenMPSimpleClauseTypeName(OMPC_dist_schedule, 0);
+ Values += "'";
+ Diag(KindLoc, diag::err_omp_unexpected_clause_value)
+ << Values << getOpenMPClauseName(OMPC_dist_schedule);
+ return nullptr;
+ }
+ Expr *ValExpr = ChunkSize;
+ Stmt *HelperValStmt = nullptr;
+ if (ChunkSize) {
+ if (!ChunkSize->isValueDependent() && !ChunkSize->isTypeDependent() &&
+ !ChunkSize->isInstantiationDependent() &&
+ !ChunkSize->containsUnexpandedParameterPack()) {
+ SourceLocation ChunkSizeLoc = ChunkSize->getLocStart();
+ ExprResult Val =
+ PerformOpenMPImplicitIntegerConversion(ChunkSizeLoc, ChunkSize);
+ if (Val.isInvalid())
+ return nullptr;
+
+ ValExpr = Val.get();
+
+ // OpenMP [2.7.1, Restrictions]
+ // chunk_size must be a loop invariant integer expression with a positive
+ // value.
+ llvm::APSInt Result;
+ if (ValExpr->isIntegerConstantExpr(Result, Context)) {
+ if (Result.isSigned() && !Result.isStrictlyPositive()) {
+ Diag(ChunkSizeLoc, diag::err_omp_negative_expression_in_clause)
+ << "dist_schedule" << ChunkSize->getSourceRange();
+ return nullptr;
+ }
+ } else if (isParallelOrTaskRegion(DSAStack->getCurrentDirective()) &&
+ !CurContext->isDependentContext()) {
+ llvm::MapVector<Expr *, DeclRefExpr *> Captures;
+ ValExpr = tryBuildCapture(*this, ValExpr, Captures).get();
+ HelperValStmt = buildPreInits(Context, Captures);
+ }
+ }
+ }
+
+ return new (Context)
+ OMPDistScheduleClause(StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc,
+ Kind, ValExpr, HelperValStmt);
+}
+
+OMPClause *Sema::ActOnOpenMPDefaultmapClause(
+ OpenMPDefaultmapClauseModifier M, OpenMPDefaultmapClauseKind Kind,
+ SourceLocation StartLoc, SourceLocation LParenLoc, SourceLocation MLoc,
+ SourceLocation KindLoc, SourceLocation EndLoc) {
+ // OpenMP 4.5 only supports 'defaultmap(tofrom: scalar)'
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom ||
+ Kind != OMPC_DEFAULTMAP_scalar) {
+ std::string Value;
+ SourceLocation Loc;
+ Value += "'";
+ if (M != OMPC_DEFAULTMAP_MODIFIER_tofrom) {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_MODIFIER_tofrom);
+ Loc = MLoc;
+ } else {
+ Value += getOpenMPSimpleClauseTypeName(OMPC_defaultmap,
+ OMPC_DEFAULTMAP_scalar);
+ Loc = KindLoc;
+ }
+ Value += "'";
+ Diag(Loc, diag::err_omp_unexpected_clause_value)
+ << Value << getOpenMPClauseName(OMPC_defaultmap);
+ return nullptr;
+ }
+
+ return new (Context)
+ OMPDefaultmapClause(StartLoc, LParenLoc, MLoc, KindLoc, EndLoc, Kind, M);
+}
+
+bool Sema::ActOnStartOpenMPDeclareTargetDirective(SourceLocation Loc) {
+ DeclContext *CurLexicalContext = getCurLexicalContext();
+ if (!CurLexicalContext->isFileContext() &&
+ !CurLexicalContext->isExternCContext() &&
+ !CurLexicalContext->isExternCXXContext()) {
+ Diag(Loc, diag::err_omp_region_not_file_context);
+ return false;
+ }
+ if (IsInOpenMPDeclareTargetContext) {
+ Diag(Loc, diag::err_omp_enclosed_declare_target);
+ return false;
+ }
+
+ IsInOpenMPDeclareTargetContext = true;
+ return true;
+}
+
+void Sema::ActOnFinishOpenMPDeclareTargetDirective() {
+ assert(IsInOpenMPDeclareTargetContext &&
+ "Unexpected ActOnFinishOpenMPDeclareTargetDirective");
+
+ IsInOpenMPDeclareTargetContext = false;
+}
+
+void
+Sema::ActOnOpenMPDeclareTargetName(Scope *CurScope, CXXScopeSpec &ScopeSpec,
+ const DeclarationNameInfo &Id,
+ OMPDeclareTargetDeclAttr::MapTypeTy MT,
+ NamedDeclSetType &SameDirectiveDecls) {
+ LookupResult Lookup(*this, Id, LookupOrdinaryName);
+ LookupParsedName(Lookup, CurScope, &ScopeSpec, true);
+
+ if (Lookup.isAmbiguous())
+ return;
+ Lookup.suppressDiagnostics();
+
+ if (!Lookup.isSingleResult()) {
+ if (TypoCorrection Corrected =
+ CorrectTypo(Id, LookupOrdinaryName, CurScope, nullptr,
+ llvm::make_unique<VarOrFuncDeclFilterCCC>(*this),
+ CTK_ErrorRecovery)) {
+ diagnoseTypo(Corrected, PDiag(diag::err_undeclared_var_use_suggest)
+ << Id.getName());
+ checkDeclIsAllowedInOpenMPTarget(nullptr, Corrected.getCorrectionDecl());
+ return;
+ }
+
+ Diag(Id.getLoc(), diag::err_undeclared_var_use) << Id.getName();
+ return;
+ }
+
+ NamedDecl *ND = Lookup.getAsSingle<NamedDecl>();
+ if (isa<VarDecl>(ND) || isa<FunctionDecl>(ND)) {
+ if (!SameDirectiveDecls.insert(cast<NamedDecl>(ND->getCanonicalDecl())))
+ Diag(Id.getLoc(), diag::err_omp_declare_target_multiple) << Id.getName();
+
+ if (!ND->hasAttr<OMPDeclareTargetDeclAttr>()) {
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(Context, MT);
+ ND->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(ND, A);
+ checkDeclIsAllowedInOpenMPTarget(nullptr, ND);
+ } else if (ND->getAttr<OMPDeclareTargetDeclAttr>()->getMapType() != MT) {
+ Diag(Id.getLoc(), diag::err_omp_declare_target_to_and_link)
+ << Id.getName();
+ }
+ } else
+ Diag(Id.getLoc(), diag::err_omp_invalid_target_decl) << Id.getName();
+}
+
+static void checkDeclInTargetContext(SourceLocation SL, SourceRange SR,
+ Sema &SemaRef, Decl *D) {
+ if (!D)
+ return;
+ Decl *LD = nullptr;
+ if (isa<TagDecl>(D)) {
+ LD = cast<TagDecl>(D)->getDefinition();
+ } else if (isa<VarDecl>(D)) {
+ LD = cast<VarDecl>(D)->getDefinition();
+
+ // If this is an implicit variable that is legal and we do not need to do
+ // anything.
+ if (cast<VarDecl>(D)->isImplicit()) {
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To);
+ D->addAttr(A);
+ if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
+ return;
+ }
+
+ } else if (isa<FunctionDecl>(D)) {
+ const FunctionDecl *FD = nullptr;
+ if (cast<FunctionDecl>(D)->hasBody(FD))
+ LD = const_cast<FunctionDecl *>(FD);
+
+ // If the definition is associated with the current declaration in the
+ // target region (it can be e.g. a lambda) that is legal and we do not need
+ // to do anything else.
+ if (LD == D) {
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To);
+ D->addAttr(A);
+ if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
+ return;
+ }
+ }
+ if (!LD)
+ LD = D;
+ if (LD && !LD->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ (isa<VarDecl>(LD) || isa<FunctionDecl>(LD))) {
+ // Outlined declaration is not declared target.
+ if (LD->isOutOfLine()) {
+ SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+ SemaRef.Diag(SL, diag::note_used_here) << SR;
+ } else {
+ DeclContext *DC = LD->getDeclContext();
+ while (DC) {
+ if (isa<FunctionDecl>(DC) &&
+ cast<FunctionDecl>(DC)->hasAttr<OMPDeclareTargetDeclAttr>())
+ break;
+ DC = DC->getParent();
+ }
+ if (DC)
+ return;
+
+ // Is not declared in target context.
+ SemaRef.Diag(LD->getLocation(), diag::warn_omp_not_in_target_context);
+ SemaRef.Diag(SL, diag::note_used_here) << SR;
+ }
+ // Mark decl as declared target to prevent further diagnostic.
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ SemaRef.Context, OMPDeclareTargetDeclAttr::MT_To);
+ D->addAttr(A);
+ if (ASTMutationListener *ML = SemaRef.Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
+ }
+}
+
+static bool checkValueDeclInTarget(SourceLocation SL, SourceRange SR,
+ Sema &SemaRef, DSAStackTy *Stack,
+ ValueDecl *VD) {
+ if (VD->hasAttr<OMPDeclareTargetDeclAttr>())
+ return true;
+ if (!CheckTypeMappable(SL, SR, SemaRef, Stack, VD->getType()))
+ return false;
+ return true;
+}
+
+void Sema::checkDeclIsAllowedInOpenMPTarget(Expr *E, Decl *D) {
+ if (!D || D->isInvalidDecl())
+ return;
+ SourceRange SR = E ? E->getSourceRange() : D->getSourceRange();
+ SourceLocation SL = E ? E->getLocStart() : D->getLocation();
+ // 2.10.6: threadprivate variable cannot appear in a declare target directive.
+ if (VarDecl *VD = dyn_cast<VarDecl>(D)) {
+ if (DSAStack->isThreadPrivate(VD)) {
+ Diag(SL, diag::err_omp_threadprivate_in_target);
+ ReportOriginalDSA(*this, DSAStack, VD, DSAStack->getTopDSA(VD, false));
+ return;
+ }
+ }
+ if (ValueDecl *VD = dyn_cast<ValueDecl>(D)) {
+ // Problem if any with var declared with incomplete type will be reported
+ // as normal, so no need to check it here.
+ if ((E || !VD->getType()->isIncompleteType()) &&
+ !checkValueDeclInTarget(SL, SR, *this, DSAStack, VD)) {
+ // Mark decl as declared target to prevent further diagnostic.
+ if (isa<VarDecl>(VD) || isa<FunctionDecl>(VD)) {
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ Context, OMPDeclareTargetDeclAttr::MT_To);
+ VD->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(VD, A);
+ }
+ return;
+ }
+ }
+ if (!E) {
+ // Checking declaration inside declare target region.
+ if (!D->hasAttr<OMPDeclareTargetDeclAttr>() &&
+ (isa<VarDecl>(D) || isa<FunctionDecl>(D))) {
+ Attr *A = OMPDeclareTargetDeclAttr::CreateImplicit(
+ Context, OMPDeclareTargetDeclAttr::MT_To);
+ D->addAttr(A);
+ if (ASTMutationListener *ML = Context.getASTMutationListener())
+ ML->DeclarationMarkedOpenMPDeclareTarget(D, A);
+ }
+ return;
+ }
+ checkDeclInTargetContext(E->getExprLoc(), E->getSourceRange(), *this, D);
+}
+
+OMPClause *Sema::ActOnOpenMPToClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ MappableVarListInfo MVLI(VarList);
+ checkMappableExpressionList(*this, DSAStack, OMPC_to, MVLI, StartLoc);
+ if (MVLI.ProcessedVarList.empty())
+ return nullptr;
+
+ return OMPToClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
+OMPClause *Sema::ActOnOpenMPFromClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ MappableVarListInfo MVLI(VarList);
+ checkMappableExpressionList(*this, DSAStack, OMPC_from, MVLI, StartLoc);
+ if (MVLI.ProcessedVarList.empty())
+ return nullptr;
+
+ return OMPFromClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ MVLI.ProcessedVarList, MVLI.VarBaseDeclarations,
+ MVLI.VarComponents);
+}
+
+OMPClause *Sema::ActOnOpenMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ QualType Type = D->getType();
+ // item should be a pointer or reference to pointer
+ if (!Type.getNonReferenceType()->isPointerType()) {
+ Diag(ELoc, diag::err_omp_usedeviceptr_not_a_pointer)
+ << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+ Vars.push_back(RefExpr->IgnoreParens());
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPUseDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
+
+OMPClause *Sema::ActOnOpenMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ SmallVector<Expr *, 8> Vars;
+ for (auto &RefExpr : VarList) {
+ assert(RefExpr && "NULL expr in OpenMP use_device_ptr clause.");
+ SourceLocation ELoc;
+ SourceRange ERange;
+ Expr *SimpleRefExpr = RefExpr;
+ auto Res = getPrivateItem(*this, SimpleRefExpr, ELoc, ERange);
+ if (Res.second) {
+ // It will be analyzed later.
+ Vars.push_back(RefExpr);
+ }
+ ValueDecl *D = Res.first;
+ if (!D)
+ continue;
+
+ QualType Type = D->getType();
+ // item should be a pointer or array or reference to pointer or array
+ if (!Type.getNonReferenceType()->isPointerType() &&
+ !Type.getNonReferenceType()->isArrayType()) {
+ Diag(ELoc, diag::err_omp_argument_type_isdeviceptr)
+ << 0 << RefExpr->getSourceRange();
+ continue;
+ }
+ Vars.push_back(RefExpr->IgnoreParens());
+ }
+
+ if (Vars.empty())
+ return nullptr;
+
+ return OMPIsDevicePtrClause::Create(Context, StartLoc, LParenLoc, EndLoc,
+ Vars);
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
index d6a0ff7dc3d1..b025a397edca 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaOverload.cpp
@@ -39,8 +39,8 @@ using namespace clang;
using namespace sema;
static bool functionHasPassObjectSizeParams(const FunctionDecl *FD) {
- return std::any_of(FD->param_begin(), FD->param_end(),
- std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
+ return llvm::any_of(FD->parameters(),
+ std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
}
/// A convenience routine for creating a decayed reference to a function.
@@ -293,6 +293,13 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
// A narrowing conversion is an implicit conversion ...
QualType FromType = getToType(0);
QualType ToType = getToType(1);
+
+ // A conversion to an enumeration type is narrowing if the conversion to
+ // the underlying type is narrowing. This only arises for expressions of
+ // the form 'Enum{init}'.
+ if (auto *ET = ToType->getAs<EnumType>())
+ ToType = ET->getDecl()->getIntegerType();
+
switch (Second) {
// 'bool' is an integral type; dispatch to the right place to handle it.
case ICK_Boolean_Conversion:
@@ -433,7 +440,7 @@ StandardConversionSequence::getNarrowingKind(ASTContext &Ctx,
/// dump - Print this standard conversion sequence to standard
/// error. Useful for debugging overloading issues.
-void StandardConversionSequence::dump() const {
+LLVM_DUMP_METHOD void StandardConversionSequence::dump() const {
raw_ostream &OS = llvm::errs();
bool PrintedSomething = false;
if (First != ICK_Identity) {
@@ -985,7 +992,7 @@ Sema::CheckOverload(Scope *S, FunctionDecl *New, const LookupResult &Old,
}
bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
- bool UseUsingDeclRules) {
+ bool UseMemberUsingDeclRules, bool ConsiderCudaAttrs) {
// C++ [basic.start.main]p2: This function shall not be overloaded.
if (New->isMain())
return false;
@@ -1041,7 +1048,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
//
// However, we don't consider either of these when deciding whether
// a member introduced by a shadow declaration is hidden.
- if (!UseUsingDeclRules && NewTemplate &&
+ if (!UseMemberUsingDeclRules && NewTemplate &&
(!TemplateParameterListsAreEqual(NewTemplate->getTemplateParameters(),
OldTemplate->getTemplateParameters(),
false, TPL_TemplateMatch) ||
@@ -1061,7 +1068,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
if (OldMethod && NewMethod &&
!OldMethod->isStatic() && !NewMethod->isStatic()) {
if (OldMethod->getRefQualifier() != NewMethod->getRefQualifier()) {
- if (!UseUsingDeclRules &&
+ if (!UseMemberUsingDeclRules &&
(OldMethod->getRefQualifier() == RQ_None ||
NewMethod->getRefQualifier() == RQ_None)) {
// C++0x [over.load]p2:
@@ -1118,7 +1125,7 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
return true;
}
- if (getLangOpts().CUDA && getLangOpts().CUDATargetOverloads) {
+ if (getLangOpts().CUDA && ConsiderCudaAttrs) {
CUDAFunctionTarget NewTarget = IdentifyCUDATarget(New),
OldTarget = IdentifyCUDATarget(Old);
if (NewTarget == CFT_InvalidTarget || NewTarget == CFT_Global)
@@ -1129,7 +1136,10 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
// Don't allow mixing of HD with other kinds. This guarantees that
// we have only one viable function with this signature on any
// side of CUDA compilation .
- if ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice))
+ // __global__ functions can't be overloaded based on attribute
+ // difference because, like HD, they also exist on both sides.
+ if ((NewTarget == CFT_HostDevice) || (OldTarget == CFT_HostDevice) ||
+ (NewTarget == CFT_Global) || (OldTarget == CFT_Global))
return false;
// Allow overloading of functions with same signature, but
@@ -1147,7 +1157,16 @@ bool Sema::IsOverload(FunctionDecl *New, FunctionDecl *Old,
/// \returns true if \arg FD is unavailable and current context is inside
/// an available function, false otherwise.
bool Sema::isFunctionConsideredUnavailable(FunctionDecl *FD) {
- return FD->isUnavailable() && !cast<Decl>(CurContext)->isUnavailable();
+ if (!FD->isUnavailable())
+ return false;
+
+ // Walk up the context of the caller.
+ Decl *C = cast<Decl>(CurContext);
+ do {
+ if (C->isUnavailable())
+ return false;
+ } while ((C = cast_or_null<Decl>(C->getDeclContext())));
+ return true;
}
/// \brief Tries a user-defined conversion from From to ToType.
@@ -1199,11 +1218,13 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
S.IsDerivedFrom(From->getLocStart(), FromCanon, ToCanon))) {
// Turn this into a "standard" conversion sequence, so that it
// gets ranked with standard conversion sequences.
+ DeclAccessPair Found = ICS.UserDefined.FoundConversionFunction;
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(From->getType());
ICS.Standard.setAllToTypes(ToType);
ICS.Standard.CopyConstructor = Constructor;
+ ICS.Standard.FoundCopyConstructor = Found;
if (ToCanon != FromCanon)
ICS.Standard.Second = ICK_Derived_To_Base;
}
@@ -1217,7 +1238,7 @@ TryUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
for (OverloadCandidateSet::iterator Cand = Conversions.begin();
Cand != Conversions.end(); ++Cand)
if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
+ ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
break;
// Fall through.
@@ -1652,6 +1673,20 @@ static bool IsStandardConversion(Sema &S, Expr* From, QualType ToType,
SCS.Second = ICK_Complex_Real;
FromType = ToType.getUnqualifiedType();
} else if (FromType->isRealFloatingType() && ToType->isRealFloatingType()) {
+ // FIXME: disable conversions between long double and __float128 if
+ // their representation is different until there is back end support
+ // We of course allow this conversion if long double is really double.
+ if (&S.Context.getFloatTypeSemantics(FromType) !=
+ &S.Context.getFloatTypeSemantics(ToType)) {
+ bool Float128AndLongDouble = ((FromType == S.Context.Float128Ty &&
+ ToType == S.Context.LongDoubleTy) ||
+ (FromType == S.Context.LongDoubleTy &&
+ ToType == S.Context.Float128Ty));
+ if (Float128AndLongDouble &&
+ (&S.Context.getFloatTypeSemantics(S.Context.LongDoubleTy) !=
+ &llvm::APFloat::IEEEdouble))
+ return false;
+ }
// Floating point conversions (C++ 4.8).
SCS.Second = ICK_Floating_Conversion;
FromType = ToType.getUnqualifiedType();
@@ -1809,8 +1844,7 @@ bool Sema::IsIntegralPromotion(Expr *From, QualType FromType, QualType ToType) {
(FromType->isSignedIntegerType() ||
// We can promote any unsigned integer type whose size is
// less than int to an int.
- (!FromType->isSignedIntegerType() &&
- Context.getTypeSize(FromType) < Context.getTypeSize(ToType)))) {
+ Context.getTypeSize(FromType) < Context.getTypeSize(ToType))) {
return To->getKind() == BuiltinType::Int;
}
@@ -1955,7 +1989,8 @@ bool Sema::IsFloatingPointPromotion(QualType FromType, QualType ToType) {
if (!getLangOpts().CPlusPlus &&
(FromBuiltin->getKind() == BuiltinType::Float ||
FromBuiltin->getKind() == BuiltinType::Double) &&
- (ToBuiltin->getKind() == BuiltinType::LongDouble))
+ (ToBuiltin->getKind() == BuiltinType::LongDouble ||
+ ToBuiltin->getKind() == BuiltinType::Float128))
return true;
// Half can be promoted to float.
@@ -2538,9 +2573,8 @@ bool Sema::IsBlockPointerConversion(QualType FromType, QualType ToType,
// Argument types are too different. Abort.
return false;
}
- if (LangOpts.ObjCAutoRefCount &&
- !Context.FunctionTypesMatchOnNSConsumedAttrs(FromFunctionType,
- ToFunctionType))
+ if (!Context.doFunctionTypesMatchOnExtParameterInfos(FromFunctionType,
+ ToFunctionType))
return false;
ConvertedType = ToType;
@@ -2919,6 +2953,10 @@ Sema::IsQualificationConversion(QualType FromType, QualType ToType,
Qualifiers FromQuals = FromType.getQualifiers();
Qualifiers ToQuals = ToType.getQualifiers();
+
+ // Ignore __unaligned qualifier if this type is void.
+ if (ToType.getUnqualifiedType()->isVoidType())
+ FromQuals.removeUnaligned();
// Objective-C ARC:
// Check Objective-C lifetime conversions.
@@ -3015,39 +3053,26 @@ IsInitializerListConstructorConversion(Sema &S, Expr *From, QualType ToType,
UserDefinedConversionSequence &User,
OverloadCandidateSet &CandidateSet,
bool AllowExplicit) {
- DeclContext::lookup_result R = S.LookupConstructors(To);
- for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = nullptr;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
+ for (auto *D : S.LookupConstructors(To)) {
+ auto Info = getConstructorInfo(D);
+ if (!Info)
+ continue;
- bool Usable = !Constructor->isInvalidDecl() &&
- S.isInitListConstructor(Constructor) &&
- (AllowExplicit || !Constructor->isExplicit());
+ bool Usable = !Info.Constructor->isInvalidDecl() &&
+ S.isInitListConstructor(Info.Constructor) &&
+ (AllowExplicit || !Info.Constructor->isExplicit());
if (Usable) {
// If the first argument is (a reference to) the target type,
// suppress conversions.
- bool SuppressUserConversions =
- isFirstArgumentCompatibleWithType(S.Context, Constructor, ToType);
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ nullptr,
- From, CandidateSet,
- SuppressUserConversions);
+ bool SuppressUserConversions = isFirstArgumentCompatibleWithType(
+ S.Context, Info.Constructor, ToType);
+ if (Info.ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(Info.ConstructorTmpl, Info.FoundDecl,
+ /*ExplicitArgs*/ nullptr, From,
+ CandidateSet, SuppressUserConversions);
else
- S.AddOverloadCandidate(Constructor, FoundDecl,
- From, CandidateSet,
- SuppressUserConversions);
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl, From,
+ CandidateSet, SuppressUserConversions);
}
}
@@ -3147,27 +3172,17 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
ListInitializing = true;
}
- DeclContext::lookup_result R = S.LookupConstructors(ToRecordDecl);
- for (DeclContext::lookup_iterator Con = R.begin(), ConEnd = R.end();
- Con != ConEnd; ++Con) {
- NamedDecl *D = *Con;
- DeclAccessPair FoundDecl = DeclAccessPair::make(D, D->getAccess());
-
- // Find the constructor (which may be a template).
- CXXConstructorDecl *Constructor = nullptr;
- FunctionTemplateDecl *ConstructorTmpl
- = dyn_cast<FunctionTemplateDecl>(D);
- if (ConstructorTmpl)
- Constructor
- = cast<CXXConstructorDecl>(ConstructorTmpl->getTemplatedDecl());
- else
- Constructor = cast<CXXConstructorDecl>(D);
+ for (auto *D : S.LookupConstructors(ToRecordDecl)) {
+ auto Info = getConstructorInfo(D);
+ if (!Info)
+ continue;
- bool Usable = !Constructor->isInvalidDecl();
+ bool Usable = !Info.Constructor->isInvalidDecl();
if (ListInitializing)
- Usable = Usable && (AllowExplicit || !Constructor->isExplicit());
+ Usable = Usable && (AllowExplicit || !Info.Constructor->isExplicit());
else
- Usable = Usable &&Constructor->isConvertingConstructor(AllowExplicit);
+ Usable = Usable &&
+ Info.Constructor->isConvertingConstructor(AllowExplicit);
if (Usable) {
bool SuppressUserConversions = !ConstructorsOnly;
if (SuppressUserConversions && ListInitializing) {
@@ -3176,18 +3191,18 @@ IsUserDefinedConversion(Sema &S, Expr *From, QualType ToType,
// If the first argument is (a reference to) the target type,
// suppress conversions.
SuppressUserConversions = isFirstArgumentCompatibleWithType(
- S.Context, Constructor, ToType);
+ S.Context, Info.Constructor, ToType);
}
}
- if (ConstructorTmpl)
- S.AddTemplateOverloadCandidate(ConstructorTmpl, FoundDecl,
- /*ExplicitArgs*/ nullptr,
- llvm::makeArrayRef(Args, NumArgs),
- CandidateSet, SuppressUserConversions);
+ if (Info.ConstructorTmpl)
+ S.AddTemplateOverloadCandidate(
+ Info.ConstructorTmpl, Info.FoundDecl,
+ /*ExplicitArgs*/ nullptr, llvm::makeArrayRef(Args, NumArgs),
+ CandidateSet, SuppressUserConversions);
else
// Allow one user-defined conversion when user specifies a
// From->ToType conversion via an static cast (c-style, etc).
- S.AddOverloadCandidate(Constructor, FoundDecl,
+ S.AddOverloadCandidate(Info.Constructor, Info.FoundDecl,
llvm::makeArrayRef(Args, NumArgs),
CandidateSet, SuppressUserConversions);
}
@@ -4127,6 +4142,10 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,
T2Quals.removeObjCLifetime();
}
+ // MS compiler ignores __unaligned qualifier for references; do the same.
+ T1Quals.removeUnaligned();
+ T2Quals.removeUnaligned();
+
if (T1Quals == T2Quals)
return Ref_Compatible;
else if (T1Quals.compatiblyIncludes(T2Quals))
@@ -4248,7 +4267,7 @@ FindConversionForRefInit(Sema &S, ImplicitConversionSequence &ICS,
for (OverloadCandidateSet::iterator Cand = CandidateSet.begin();
Cand != CandidateSet.end(); ++Cand)
if (Cand->Viable)
- ICS.Ambiguous.addConversion(Cand->Function);
+ ICS.Ambiguous.addConversion(Cand->FoundDecl, Cand->Function);
return true;
case OR_No_Viable_Function:
@@ -4448,13 +4467,16 @@ TryReferenceInit(Sema &S, Expr *Init, QualType DeclType,
// initialization fails.
//
// Note that we only want to check address spaces and cvr-qualifiers here.
- // ObjC GC and lifetime qualifiers aren't important.
+ // ObjC GC, lifetime and unaligned qualifiers aren't important.
Qualifiers T1Quals = T1.getQualifiers();
Qualifiers T2Quals = T2.getQualifiers();
T1Quals.removeObjCGCAttr();
T1Quals.removeObjCLifetime();
T2Quals.removeObjCGCAttr();
T2Quals.removeObjCLifetime();
+ // MS compiler ignores __unaligned qualifier for references; do the same.
+ T1Quals.removeUnaligned();
+ T2Quals.removeUnaligned();
if (!T1Quals.compatiblyIncludes(T2Quals))
return ICS;
}
@@ -5838,12 +5860,12 @@ Sema::AddOverloadCandidate(FunctionDecl *Function,
}
}
-ObjCMethodDecl *Sema::SelectBestMethod(Selector Sel, MultiExprArg Args,
- bool IsInstance) {
- SmallVector<ObjCMethodDecl*, 4> Methods;
- if (!CollectMultipleMethodsInGlobalPool(Sel, Methods, IsInstance))
+ObjCMethodDecl *
+Sema::SelectBestMethod(Selector Sel, MultiExprArg Args, bool IsInstance,
+ SmallVectorImpl<ObjCMethodDecl *> &Methods) {
+ if (Methods.size() <= 1)
return nullptr;
-
+
for (unsigned b = 0, e = Methods.size(); b < e; b++) {
bool Match = true;
ObjCMethodDecl *Method = Methods[b];
@@ -5952,37 +5974,28 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
SFINAETrap Trap(*this);
SmallVector<Expr *, 16> ConvertedArgs;
bool InitializationFailed = false;
- bool ContainsValueDependentExpr = false;
// Convert the arguments.
- for (unsigned i = 0, e = Args.size(); i != e; ++i) {
- if (i == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
+ for (unsigned I = 0, E = Args.size(); I != E; ++I) {
+ ExprResult R;
+ if (I == 0 && !MissingImplicitThis && isa<CXXMethodDecl>(Function) &&
!cast<CXXMethodDecl>(Function)->isStatic() &&
!isa<CXXConstructorDecl>(Function)) {
CXXMethodDecl *Method = cast<CXXMethodDecl>(Function);
- ExprResult R =
- PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
- Method, Method);
- if (R.isInvalid()) {
- InitializationFailed = true;
- break;
- }
- ContainsValueDependentExpr |= R.get()->isValueDependent();
- ConvertedArgs.push_back(R.get());
+ R = PerformObjectArgumentInitialization(Args[0], /*Qualifier=*/nullptr,
+ Method, Method);
} else {
- ExprResult R =
- PerformCopyInitialization(InitializedEntity::InitializeParameter(
- Context,
- Function->getParamDecl(i)),
- SourceLocation(),
- Args[i]);
- if (R.isInvalid()) {
- InitializationFailed = true;
- break;
- }
- ContainsValueDependentExpr |= R.get()->isValueDependent();
- ConvertedArgs.push_back(R.get());
+ R = PerformCopyInitialization(InitializedEntity::InitializeParameter(
+ Context, Function->getParamDecl(I)),
+ SourceLocation(), Args[I]);
}
+
+ if (R.isInvalid()) {
+ InitializationFailed = true;
+ break;
+ }
+
+ ConvertedArgs.push_back(R.get());
}
if (InitializationFailed || Trap.hasErrorOccurred())
@@ -6002,7 +6015,6 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
InitializationFailed = true;
break;
}
- ContainsValueDependentExpr |= R.get()->isValueDependent();
ConvertedArgs.push_back(R.get());
}
@@ -6012,18 +6024,14 @@ EnableIfAttr *Sema::CheckEnableIf(FunctionDecl *Function, ArrayRef<Expr *> Args,
for (auto *EIA : EnableIfAttrs) {
APValue Result;
- if (EIA->getCond()->isValueDependent()) {
- // Don't even try now, we'll examine it after instantiation.
- continue;
- }
-
+ // FIXME: This doesn't consider value-dependent cases, because doing so is
+ // very difficult. Ideally, we should handle them more gracefully.
if (!EIA->getCond()->EvaluateWithSubstitution(
- Result, Context, Function, llvm::makeArrayRef(ConvertedArgs))) {
- if (!ContainsValueDependentExpr)
- return EIA;
- } else if (!Result.isInt() || !Result.getInt().getBoolValue()) {
+ Result, Context, Function, llvm::makeArrayRef(ConvertedArgs)))
+ return EIA;
+
+ if (!Result.isInt() || !Result.getInt().getBoolValue())
return EIA;
- }
}
return nullptr;
}
@@ -6814,7 +6822,8 @@ namespace {
/// enumeration types.
class BuiltinCandidateTypeSet {
/// TypeSet - A set of types.
- typedef llvm::SmallPtrSet<QualType, 8> TypeSet;
+ typedef llvm::SetVector<QualType, SmallVector<QualType, 8>,
+ llvm::SmallPtrSet<QualType, 8>> TypeSet;
/// PointerTypes - The set of pointer types that will be used in the
/// built-in candidates.
@@ -6913,7 +6922,7 @@ BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty,
const Qualifiers &VisibleQuals) {
// Insert this type.
- if (!PointerTypes.insert(Ty).second)
+ if (!PointerTypes.insert(Ty))
return false;
QualType PointeeTy;
@@ -6981,7 +6990,7 @@ bool
BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants(
QualType Ty) {
// Insert this type.
- if (!MemberPointerTypes.insert(Ty).second)
+ if (!MemberPointerTypes.insert(Ty))
return false;
const MemberPointerType *PointerTy = Ty->getAs<MemberPointerType>();
@@ -7187,13 +7196,13 @@ class BuiltinOperatorOverloadBuilder {
// provided via the getArithmeticType() method below.
// The "promoted arithmetic types" are the arithmetic
// types are that preserved by promotion (C++ [over.built]p2).
- static const unsigned FirstIntegralType = 3;
- static const unsigned LastIntegralType = 20;
- static const unsigned FirstPromotedIntegralType = 3,
- LastPromotedIntegralType = 11;
+ static const unsigned FirstIntegralType = 4;
+ static const unsigned LastIntegralType = 21;
+ static const unsigned FirstPromotedIntegralType = 4,
+ LastPromotedIntegralType = 12;
static const unsigned FirstPromotedArithmeticType = 0,
- LastPromotedArithmeticType = 11;
- static const unsigned NumArithmeticTypes = 20;
+ LastPromotedArithmeticType = 12;
+ static const unsigned NumArithmeticTypes = 21;
/// \brief Get the canonical type for a given arithmetic type index.
CanQualType getArithmeticType(unsigned index) {
@@ -7204,6 +7213,7 @@ class BuiltinOperatorOverloadBuilder {
&ASTContext::FloatTy,
&ASTContext::DoubleTy,
&ASTContext::LongDoubleTy,
+ &ASTContext::Float128Ty,
// Start of integral types.
&ASTContext::IntTy,
@@ -7246,7 +7256,7 @@ class BuiltinOperatorOverloadBuilder {
// (we could precompute SLL x UI for all known platforms, but it's
// better not to make any assumptions).
// We assume that int128 has a higher rank than long long on all platforms.
- enum PromotedType {
+ enum PromotedType : int8_t {
Dep=-1,
Flt, Dbl, LDbl, SI, SL, SLL, S128, UI, UL, ULL, U128
};
@@ -8476,16 +8486,31 @@ Sema::AddArgumentDependentLookupCandidates(DeclarationName Name,
}
}
-// Determines whether Cand1 is "better" in terms of its enable_if attrs than
-// Cand2 for overloading. This function assumes that all of the enable_if attrs
-// on Cand1 and Cand2 have conditions that evaluate to true.
-//
-// Cand1's set of enable_if attributes are said to be "better" than Cand2's iff
-// Cand1's first N enable_if attributes have precisely the same conditions as
-// Cand2's first N enable_if attributes (where N = the number of enable_if
-// attributes on Cand2), and Cand1 has more than N enable_if attributes.
-static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1,
- const FunctionDecl *Cand2) {
+namespace {
+enum class Comparison { Equal, Better, Worse };
+}
+
+/// Compares the enable_if attributes of two FunctionDecls, for the purposes of
+/// overload resolution.
+///
+/// Cand1's set of enable_if attributes are said to be "better" than Cand2's iff
+/// Cand1's first N enable_if attributes have precisely the same conditions as
+/// Cand2's first N enable_if attributes (where N = the number of enable_if
+/// attributes on Cand2), and Cand1 has more than N enable_if attributes.
+///
+/// Note that you can have a pair of candidates such that Cand1's enable_if
+/// attributes are worse than Cand2's, and Cand2's enable_if attributes are
+/// worse than Cand1's.
+static Comparison compareEnableIfAttrs(const Sema &S, const FunctionDecl *Cand1,
+ const FunctionDecl *Cand2) {
+ // Common case: One (or both) decls don't have enable_if attrs.
+ bool Cand1Attr = Cand1->hasAttr<EnableIfAttr>();
+ bool Cand2Attr = Cand2->hasAttr<EnableIfAttr>();
+ if (!Cand1Attr || !Cand2Attr) {
+ if (Cand1Attr == Cand2Attr)
+ return Comparison::Equal;
+ return Cand1Attr ? Comparison::Better : Comparison::Worse;
+ }
// FIXME: The next several lines are just
// specific_attr_iterator<EnableIfAttr> but going in declaration order,
@@ -8493,10 +8518,10 @@ static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1,
auto Cand1Attrs = getOrderedEnableIfAttrs(Cand1);
auto Cand2Attrs = getOrderedEnableIfAttrs(Cand2);
- // Candidate 1 is better if it has strictly more attributes and
- // the common sequence is identical.
- if (Cand1Attrs.size() <= Cand2Attrs.size())
- return false;
+ // It's impossible for Cand1 to be better than (or equal to) Cand2 if Cand1
+ // has fewer enable_if attributes than Cand2.
+ if (Cand1Attrs.size() < Cand2Attrs.size())
+ return Comparison::Worse;
auto Cand1I = Cand1Attrs.begin();
llvm::FoldingSetNodeID Cand1ID, Cand2ID;
@@ -8508,10 +8533,10 @@ static bool hasBetterEnableIfAttrs(Sema &S, const FunctionDecl *Cand1,
Cand1A->getCond()->Profile(Cand1ID, S.getASTContext(), true);
Cand2A->getCond()->Profile(Cand2ID, S.getASTContext(), true);
if (Cand1ID != Cand2ID)
- return false;
+ return Comparison::Worse;
}
- return true;
+ return Cand1I == Cand1Attrs.end() ? Comparison::Equal : Comparison::Better;
}
/// isBetterOverloadCandidate - Determines whether the first overload
@@ -8621,14 +8646,33 @@ bool clang::isBetterOverloadCandidate(Sema &S, const OverloadCandidate &Cand1,
return BetterTemplate == Cand1.Function->getPrimaryTemplate();
}
+ // FIXME: Work around a defect in the C++17 inheriting constructor wording.
+ // A derived-class constructor beats an (inherited) base class constructor.
+ bool Cand1IsInherited =
+ dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand1.FoundDecl.getDecl());
+ bool Cand2IsInherited =
+ dyn_cast_or_null<ConstructorUsingShadowDecl>(Cand2.FoundDecl.getDecl());
+ if (Cand1IsInherited != Cand2IsInherited)
+ return Cand2IsInherited;
+ else if (Cand1IsInherited) {
+ assert(Cand2IsInherited);
+ auto *Cand1Class = cast<CXXRecordDecl>(Cand1.Function->getDeclContext());
+ auto *Cand2Class = cast<CXXRecordDecl>(Cand2.Function->getDeclContext());
+ if (Cand1Class->isDerivedFrom(Cand2Class))
+ return true;
+ if (Cand2Class->isDerivedFrom(Cand1Class))
+ return false;
+ // Inherited from sibling base classes: still ambiguous.
+ }
+
// Check for enable_if value-based overload resolution.
- if (Cand1.Function && Cand2.Function &&
- (Cand1.Function->hasAttr<EnableIfAttr>() ||
- Cand2.Function->hasAttr<EnableIfAttr>()))
- return hasBetterEnableIfAttrs(S, Cand1.Function, Cand2.Function);
+ if (Cand1.Function && Cand2.Function) {
+ Comparison Cmp = compareEnableIfAttrs(S, Cand1.Function, Cand2.Function);
+ if (Cmp != Comparison::Equal)
+ return Cmp == Comparison::Better;
+ }
- if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads &&
- Cand1.Function && Cand2.Function) {
+ if (S.getLangOpts().CUDA && Cand1.Function && Cand2.Function) {
FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
return S.IdentifyCUDAPreference(Caller, Cand1.Function) >
S.IdentifyCUDAPreference(Caller, Cand2.Function);
@@ -8722,14 +8766,44 @@ OverloadingResult
OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
iterator &Best,
bool UserDefinedConversion) {
+ llvm::SmallVector<OverloadCandidate *, 16> Candidates;
+ std::transform(begin(), end(), std::back_inserter(Candidates),
+ [](OverloadCandidate &Cand) { return &Cand; });
+
+ // [CUDA] HD->H or HD->D calls are technically not allowed by CUDA
+ // but accepted by both clang and NVCC. However during a particular
+ // compilation mode only one call variant is viable. We need to
+ // exclude non-viable overload candidates from consideration based
+ // only on their host/device attributes. Specifically, if one
+ // candidate call is WrongSide and the other is SameSide, we ignore
+ // the WrongSide candidate.
+ if (S.getLangOpts().CUDA) {
+ const FunctionDecl *Caller = dyn_cast<FunctionDecl>(S.CurContext);
+ bool ContainsSameSideCandidate =
+ llvm::any_of(Candidates, [&](OverloadCandidate *Cand) {
+ return Cand->Function &&
+ S.IdentifyCUDAPreference(Caller, Cand->Function) ==
+ Sema::CFP_SameSide;
+ });
+ if (ContainsSameSideCandidate) {
+ auto IsWrongSideCandidate = [&](OverloadCandidate *Cand) {
+ return Cand->Function &&
+ S.IdentifyCUDAPreference(Caller, Cand->Function) ==
+ Sema::CFP_WrongSide;
+ };
+ Candidates.erase(std::remove_if(Candidates.begin(), Candidates.end(),
+ IsWrongSideCandidate),
+ Candidates.end());
+ }
+ }
+
// Find the best viable function.
Best = end();
- for (iterator Cand = begin(); Cand != end(); ++Cand) {
+ for (auto *Cand : Candidates)
if (Cand->Viable)
if (Best == end() || isBetterOverloadCandidate(S, *Cand, *Best, Loc,
UserDefinedConversion))
Best = Cand;
- }
// If we didn't find any viable functions, abort.
if (Best == end())
@@ -8739,7 +8813,7 @@ OverloadCandidateSet::BestViableFunction(Sema &S, SourceLocation Loc,
// Make sure that this function is better than every other viable
// function. If not, we have an ambiguity.
- for (iterator Cand = begin(); Cand != end(); ++Cand) {
+ for (auto *Cand : Candidates) {
if (Cand->Viable &&
Cand != Best &&
!isBetterOverloadCandidate(S, *Best, *Cand, Loc,
@@ -8782,10 +8856,12 @@ enum OverloadCandidateKind {
oc_implicit_move_constructor,
oc_implicit_copy_assignment,
oc_implicit_move_assignment,
- oc_implicit_inherited_constructor
+ oc_inherited_constructor,
+ oc_inherited_constructor_template
};
OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
+ NamedDecl *Found,
FunctionDecl *Fn,
std::string &Description) {
bool isTemplate = false;
@@ -8797,11 +8873,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
}
if (CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn)) {
- if (!Ctor->isImplicit())
- return isTemplate ? oc_constructor_template : oc_constructor;
-
- if (Ctor->getInheritedConstructor())
- return oc_implicit_inherited_constructor;
+ if (!Ctor->isImplicit()) {
+ if (isa<ConstructorUsingShadowDecl>(Found))
+ return isTemplate ? oc_inherited_constructor_template
+ : oc_inherited_constructor;
+ else
+ return isTemplate ? oc_constructor_template : oc_constructor;
+ }
if (Ctor->isDefaultConstructor())
return oc_implicit_default_constructor;
@@ -8833,14 +8911,13 @@ OverloadCandidateKind ClassifyOverloadCandidate(Sema &S,
return isTemplate ? oc_function_template : oc_function;
}
-void MaybeEmitInheritedConstructorNote(Sema &S, Decl *Fn) {
- const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(Fn);
- if (!Ctor) return;
-
- Ctor = Ctor->getInheritedConstructor();
- if (!Ctor) return;
-
- S.Diag(Ctor->getLocation(), diag::note_ovl_candidate_inherited_constructor);
+void MaybeEmitInheritedConstructorNote(Sema &S, Decl *FoundDecl) {
+ // FIXME: It'd be nice to only emit a note once per using-decl per overload
+ // set.
+ if (auto *Shadow = dyn_cast<ConstructorUsingShadowDecl>(FoundDecl))
+ S.Diag(FoundDecl->getLocation(),
+ diag::note_ovl_candidate_inherited_constructor)
+ << Shadow->getNominatedBaseClass();
}
} // end anonymous namespace
@@ -8879,8 +8956,8 @@ static bool checkAddressOfFunctionIsAvailable(Sema &S, const FunctionDecl *FD,
return false;
}
- auto I = std::find_if(FD->param_begin(), FD->param_end(),
- std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
+ auto I = llvm::find_if(
+ FD->parameters(), std::mem_fn(&ParmVarDecl::hasAttr<PassObjectSizeAttr>));
if (I == FD->param_end())
return true;
@@ -8914,19 +8991,19 @@ bool Sema::checkAddressOfFunctionIsAvailable(const FunctionDecl *Function,
}
// Notes the location of an overload candidate.
-void Sema::NoteOverloadCandidate(FunctionDecl *Fn, QualType DestType,
- bool TakingAddress) {
+void Sema::NoteOverloadCandidate(NamedDecl *Found, FunctionDecl *Fn,
+ QualType DestType, bool TakingAddress) {
if (TakingAddress && !checkAddressOfCandidateIsAvailable(*this, Fn))
return;
std::string FnDesc;
- OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Fn, FnDesc);
+ OverloadCandidateKind K = ClassifyOverloadCandidate(*this, Found, Fn, FnDesc);
PartialDiagnostic PD = PDiag(diag::note_ovl_candidate)
<< (unsigned) K << FnDesc;
HandleFunctionTypeMismatch(PD, Fn->getType(), DestType);
Diag(Fn->getLocation(), PD);
- MaybeEmitInheritedConstructorNote(*this, Fn);
+ MaybeEmitInheritedConstructorNote(*this, Found);
}
// Notes the location of all overload candidates designated through
@@ -8943,11 +9020,11 @@ void Sema::NoteAllOverloadCandidates(Expr *OverloadedExpr, QualType DestType,
I != IEnd; ++I) {
if (FunctionTemplateDecl *FunTmpl =
dyn_cast<FunctionTemplateDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(FunTmpl->getTemplatedDecl(), DestType,
+ NoteOverloadCandidate(*I, FunTmpl->getTemplatedDecl(), DestType,
TakingAddress);
} else if (FunctionDecl *Fun
= dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()) ) {
- NoteOverloadCandidate(Fun, DestType, TakingAddress);
+ NoteOverloadCandidate(*I, Fun, DestType, TakingAddress);
}
}
}
@@ -8971,7 +9048,7 @@ void ImplicitConversionSequence::DiagnoseAmbiguousConversion(
if (CandsShown >= 4 && ShowOverloads == Ovl_Best)
break;
++CandsShown;
- S.NoteOverloadCandidate(*I);
+ S.NoteOverloadCandidate(I->first, I->second);
}
if (I != E)
S.Diag(SourceLocation(), diag::note_ovl_too_many_candidates) << int(E - I);
@@ -8996,7 +9073,8 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
}
std::string FnDesc;
- OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+ OverloadCandidateKind FnKind =
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
Expr *FromExpr = Conv.Bad.FromExpr;
QualType FromTy = Conv.Bad.getFromType();
@@ -9013,7 +9091,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< ToTy << Name << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9026,8 +9104,10 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
else {
// TODO: detect and diagnose the full richness of const mismatches.
if (CanQual<PointerType> FromPT = CFromTy->getAs<PointerType>())
- if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>())
- CFromTy = FromPT->getPointeeType(), CToTy = ToPT->getPointeeType();
+ if (CanQual<PointerType> ToPT = CToTy->getAs<PointerType>()) {
+ CFromTy = FromPT->getPointeeType();
+ CToTy = ToPT->getPointeeType();
+ }
}
if (CToTy.getUnqualifiedType() == CFromTy.getUnqualifiedType() &&
@@ -9042,7 +9122,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getAddressSpace() << ToQs.getAddressSpace()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9053,7 +9133,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getObjCLifetime() << ToQs.getObjCLifetime()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9064,7 +9144,16 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< FromTy
<< FromQs.getObjCGCAttr() << ToQs.getObjCGCAttr()
<< (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
+ return;
+ }
+
+ if (FromQs.hasUnaligned() != ToQs.hasUnaligned()) {
+ S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_unaligned)
+ << (unsigned) FnKind << FnDesc
+ << (FromExpr ? FromExpr->getSourceRange() : SourceRange())
+ << FromTy << FromQs.hasUnaligned() << I+1;
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9082,7 +9171,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << (CVR - 1) << I+1;
}
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9093,7 +9182,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9104,11 +9193,14 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
if (const PointerType *PTy = TempFromTy->getAs<PointerType>())
TempFromTy = PTy->getPointeeType();
if (TempFromTy->isIncompleteType()) {
+ // Emit the generic diagnostic and, optionally, add the hints to it.
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_bad_conv_incomplete)
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
- << FromTy << ToTy << (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ << FromTy << ToTy << (unsigned) isObjectArgument << I+1
+ << (unsigned) (Cand->Fix.Kind);
+
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9147,7 +9239,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< (unsigned) isObjectArgument << I + 1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
}
@@ -9159,7 +9251,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< (BaseToDerivedConversion - 1)
<< FromTy << ToTy << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
@@ -9172,7 +9264,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
<< (unsigned) FnKind << FnDesc
<< (FromExpr ? FromExpr->getSourceRange() : SourceRange())
<< FromTy << ToTy << (unsigned) isObjectArgument << I+1;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
}
@@ -9194,7 +9286,7 @@ static void DiagnoseBadConversion(Sema &S, OverloadCandidate *Cand,
FDiag << *HI;
S.Diag(Fn->getLocation(), FDiag);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
}
/// Additional arity mismatch diagnosis specific to a function overload
@@ -9228,7 +9320,8 @@ static bool CheckArityMismatch(Sema &S, OverloadCandidate *Cand,
}
/// General arity mismatch diagnosis over a candidate in a candidate set.
-static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
+static void DiagnoseArityMismatch(Sema &S, NamedDecl *Found, Decl *D,
+ unsigned NumFormalArgs) {
assert(isa<FunctionDecl>(D) &&
"The templated declaration should at least be a function"
" when diagnosing bad template argument deduction due to too many"
@@ -9258,7 +9351,8 @@ static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
}
std::string Description;
- OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, Description);
+ OverloadCandidateKind FnKind =
+ ClassifyOverloadCandidate(S, Found, Fn, Description);
if (modeCount == 1 && Fn->getParamDecl(0)->getDeclName())
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity_one)
@@ -9268,28 +9362,25 @@ static void DiagnoseArityMismatch(Sema &S, Decl *D, unsigned NumFormalArgs) {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_arity)
<< (unsigned) FnKind << (Fn->getDescribedFunctionTemplate() != nullptr)
<< mode << modeCount << NumFormalArgs;
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Found);
}
/// Arity mismatch diagnosis specific to a function overload candidate.
static void DiagnoseArityMismatch(Sema &S, OverloadCandidate *Cand,
unsigned NumFormalArgs) {
if (!CheckArityMismatch(S, Cand, NumFormalArgs))
- DiagnoseArityMismatch(S, Cand->Function, NumFormalArgs);
+ DiagnoseArityMismatch(S, Cand->FoundDecl, Cand->Function, NumFormalArgs);
}
static TemplateDecl *getDescribedTemplate(Decl *Templated) {
- if (FunctionDecl *FD = dyn_cast<FunctionDecl>(Templated))
- return FD->getDescribedFunctionTemplate();
- else if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(Templated))
- return RD->getDescribedClassTemplate();
-
+ if (TemplateDecl *TD = Templated->getDescribedTemplate())
+ return TD;
llvm_unreachable("Unsupported: Getting the described template declaration"
" for bad deduction diagnosis");
}
/// Diagnose a failed template-argument deduction.
-static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
+static void DiagnoseBadDeduction(Sema &S, NamedDecl *Found, Decl *Templated,
DeductionFailureInfo &DeductionFailure,
unsigned NumArgs,
bool TakingCandidateAddress) {
@@ -9307,7 +9398,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_incomplete_deduction)
<< ParamD->getDeclName();
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9332,7 +9423,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_underqualified)
<< ParamD->getDeclName() << Arg << NonCanonParam;
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9351,7 +9442,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
diag::note_ovl_candidate_inconsistent_deduction)
<< which << ParamD->getDeclName() << *DeductionFailure.getFirstArg()
<< *DeductionFailure.getSecondArg();
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9374,18 +9465,18 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
diag::note_ovl_candidate_explicit_arg_mismatch_unnamed)
<< (index + 1);
}
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
case Sema::TDK_TooManyArguments:
case Sema::TDK_TooFewArguments:
- DiagnoseArityMismatch(S, Templated, NumArgs);
+ DiagnoseArityMismatch(S, Found, Templated, NumArgs);
return;
case Sema::TDK_InstantiationDepth:
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_instantiation_depth);
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
case Sema::TDK_SubstitutionFailure: {
@@ -9423,7 +9514,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
S.Diag(Templated->getLocation(),
diag::note_ovl_candidate_substitution_failure)
<< TemplateArgString << SFINAEArgString << R;
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
@@ -9495,7 +9586,7 @@ static void DiagnoseBadDeduction(Sema &S, Decl *Templated,
// note_ovl_candidate_bad_deduction, which is uselessly vague.
case Sema::TDK_MiscellaneousDeductionFailure:
S.Diag(Templated->getLocation(), diag::note_ovl_candidate_bad_deduction);
- MaybeEmitInheritedConstructorNote(S, Templated);
+ MaybeEmitInheritedConstructorNote(S, Found);
return;
}
}
@@ -9509,7 +9600,7 @@ static void DiagnoseBadDeduction(Sema &S, OverloadCandidate *Cand,
if (CheckArityMismatch(S, Cand, NumArgs))
return;
}
- DiagnoseBadDeduction(S, Cand->Function, // pattern
+ DiagnoseBadDeduction(S, Cand->FoundDecl, Cand->Function, // pattern
Cand->DeductionFailure, NumArgs, TakingCandidateAddress);
}
@@ -9522,7 +9613,8 @@ static void DiagnoseBadTarget(Sema &S, OverloadCandidate *Cand) {
CalleeTarget = S.IdentifyCUDATarget(Callee);
std::string FnDesc;
- OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Callee, FnDesc);
+ OverloadCandidateKind FnKind =
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Callee, FnDesc);
S.Diag(Callee->getLocation(), diag::note_ovl_candidate_bad_target)
<< (unsigned)FnKind << CalleeTarget << CallerTarget;
@@ -9599,18 +9691,19 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
if (Cand->Viable && (Fn->isDeleted() ||
S.isFunctionConsideredUnavailable(Fn))) {
std::string FnDesc;
- OverloadCandidateKind FnKind = ClassifyOverloadCandidate(S, Fn, FnDesc);
+ OverloadCandidateKind FnKind =
+ ClassifyOverloadCandidate(S, Cand->FoundDecl, Fn, FnDesc);
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_deleted)
<< FnKind << FnDesc
<< (Fn->isDeleted() ? (Fn->isDeletedAsWritten() ? 1 : 2) : 0);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
// We don't really have anything else to say about viable candidates.
if (Cand->Viable) {
- S.NoteOverloadCandidate(Fn);
+ S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
return;
}
@@ -9620,19 +9713,20 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
return DiagnoseArityMismatch(S, Cand, NumArgs);
case ovl_fail_bad_deduction:
- return DiagnoseBadDeduction(S, Cand, NumArgs, TakingCandidateAddress);
+ return DiagnoseBadDeduction(S, Cand, NumArgs,
+ TakingCandidateAddress);
case ovl_fail_illegal_constructor: {
S.Diag(Fn->getLocation(), diag::note_ovl_candidate_illegal_constructor)
<< (Fn->getPrimaryTemplate() ? 1 : 0);
- MaybeEmitInheritedConstructorNote(S, Fn);
+ MaybeEmitInheritedConstructorNote(S, Cand->FoundDecl);
return;
}
case ovl_fail_trivial_conversion:
case ovl_fail_bad_final_conversion:
case ovl_fail_final_conversion_not_exact:
- return S.NoteOverloadCandidate(Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
case ovl_fail_bad_conversion: {
unsigned I = (Cand->IgnoreObjectArgument ? 1 : 0);
@@ -9643,7 +9737,7 @@ static void NoteFunctionCandidate(Sema &S, OverloadCandidate *Cand,
// FIXME: this currently happens when we're called from SemaInit
// when user-conversion overload fails. Figure out how to handle
// those conditions and diagnose them well.
- return S.NoteOverloadCandidate(Fn);
+ return S.NoteOverloadCandidate(Cand->FoundDecl, Fn);
}
case ovl_fail_bad_target:
@@ -9691,7 +9785,6 @@ static void NoteSurrogateCandidate(Sema &S, OverloadCandidate *Cand) {
S.Diag(Cand->Surrogate->getLocation(), diag::note_ovl_surrogate_cand)
<< FnType;
- MaybeEmitInheritedConstructorNote(S, Cand->Surrogate);
}
static void NoteBuiltinOperatorCandidate(Sema &S, StringRef Opc,
@@ -9721,8 +9814,8 @@ static void NoteAmbiguousUserConversions(Sema &S, SourceLocation OpLoc,
if (ICS.isBad()) break; // all meaningless after first invalid
if (!ICS.isAmbiguous()) continue;
- ICS.DiagnoseAmbiguousConversion(S, OpLoc,
- S.PDiag(diag::note_ambiguous_type_conversion));
+ ICS.DiagnoseAmbiguousConversion(
+ S, OpLoc, S.PDiag(diag::note_ambiguous_type_conversion));
}
}
@@ -10089,7 +10182,7 @@ struct CompareTemplateSpecCandidatesForDisplay {
/// deductions.
void TemplateSpecCandidate::NoteDeductionFailure(Sema &S,
bool ForTakingAddress) {
- DiagnoseBadDeduction(S, Specialization, // pattern
+ DiagnoseBadDeduction(S, FoundDecl, Specialization, // pattern
DeductionFailure, /*NumArgs=*/0, ForTakingAddress);
}
@@ -10252,21 +10345,32 @@ public:
}
}
- if (S.getLangOpts().CUDA && S.getLangOpts().CUDATargetOverloads &&
- Matches.size() > 1)
+ if (S.getLangOpts().CUDA && Matches.size() > 1)
EliminateSuboptimalCudaMatches();
}
bool hasComplained() const { return HasComplained; }
private:
- // Is A considered a better overload candidate for the desired type than B?
+ bool candidateHasExactlyCorrectType(const FunctionDecl *FD) {
+ QualType Discard;
+ return Context.hasSameUnqualifiedType(TargetFunctionType, FD->getType()) ||
+ S.IsNoReturnConversion(FD->getType(), TargetFunctionType, Discard);
+ }
+
+ /// \return true if A is considered a better overload candidate for the
+ /// desired type than B.
bool isBetterCandidate(const FunctionDecl *A, const FunctionDecl *B) {
- return hasBetterEnableIfAttrs(S, A, B);
+ // If A doesn't have exactly the correct type, we don't want to classify it
+ // as "better" than anything else. This way, the user is required to
+ // disambiguate for us if there are multiple candidates and no exact match.
+ return candidateHasExactlyCorrectType(A) &&
+ (!candidateHasExactlyCorrectType(B) ||
+ compareEnableIfAttrs(S, A, B) == Comparison::Better);
}
- // Returns true if we've eliminated any (read: all but one) candidates, false
- // otherwise.
+ /// \return true if we were able to eliminate all but one overload candidate,
+ /// false otherwise.
bool eliminiateSuboptimalOverloadCandidates() {
// Same algorithm as overload resolution -- one pass to pick the "best",
// another pass to be sure that nothing is better than the best.
@@ -10331,7 +10435,7 @@ private:
Info, /*InOverloadResolution=*/true)) {
// Make a note of the failed deduction for diagnostics.
FailedCandidates.addCandidate()
- .set(FunctionTemplate->getTemplatedDecl(),
+ .set(CurAccessFunPair, FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
return false;
}
@@ -10339,7 +10443,6 @@ private:
// Template argument deduction ensures that we have an exact match or
// compatible pointer-to-function arguments that would be adjusted by ICS.
// This function template specicalization works.
- Specialization = cast<FunctionDecl>(Specialization->getCanonicalDecl());
assert(S.isSameOrCompatibleFunctionType(
Context.getCanonicalType(Specialization->getType()),
Context.getCanonicalType(TargetFunctionType)));
@@ -10380,12 +10483,9 @@ private:
if (!S.checkAddressOfFunctionIsAvailable(FunDecl))
return false;
- QualType ResultTy;
- if (Context.hasSameUnqualifiedType(TargetFunctionType,
- FunDecl->getType()) ||
- S.IsNoReturnConversion(FunDecl->getType(), TargetFunctionType,
- ResultTy) ||
- (!S.getLangOpts().CPlusPlus && TargetType->isVoidPointerType())) {
+ // If we're in C, we need to support types that aren't exactly identical.
+ if (!S.getLangOpts().CPlusPlus ||
+ candidateHasExactlyCorrectType(FunDecl)) {
Matches.push_back(std::make_pair(
CurAccessFunPair, cast<FunctionDecl>(FunDecl->getCanonicalDecl())));
FoundNonTemplateFunction = true;
@@ -10451,9 +10551,10 @@ private:
UnresolvedSetIterator Result = S.getMostSpecialized(
MatchesCopy.begin(), MatchesCopy.end(), FailedCandidates,
SourceExpr->getLocStart(), S.PDiag(),
- S.PDiag(diag::err_addr_ovl_ambiguous) << Matches[0]
- .second->getDeclName(),
- S.PDiag(diag::note_ovl_candidate) << (unsigned)oc_function_template,
+ S.PDiag(diag::err_addr_ovl_ambiguous)
+ << Matches[0].second->getDeclName(),
+ S.PDiag(diag::note_ovl_candidate)
+ << (unsigned)oc_function_template,
Complain, TargetFunctionType);
if (Result != MatchesCopy.end()) {
@@ -10501,7 +10602,7 @@ public:
if (FunctionDecl *Fun =
dyn_cast<FunctionDecl>((*I)->getUnderlyingDecl()))
if (!functionHasPassObjectSizeParams(Fun))
- S.NoteOverloadCandidate(Fun, TargetFunctionType,
+ S.NoteOverloadCandidate(*I, Fun, TargetFunctionType,
/*TakingAddress=*/true);
FailedCandidates.NoteCandidates(S, OvlExpr->getLocStart());
}
@@ -10614,6 +10715,72 @@ Sema::ResolveAddressOfOverloadedFunction(Expr *AddressOfExpr,
}
/// \brief Given an expression that refers to an overloaded function, try to
+/// resolve that function to a single function that can have its address taken.
+/// This will modify `Pair` iff it returns non-null.
+///
+/// This routine can only realistically succeed if all but one candidates in the
+/// overload set for SrcExpr cannot have their addresses taken.
+FunctionDecl *
+Sema::resolveAddressOfOnlyViableOverloadCandidate(Expr *E,
+ DeclAccessPair &Pair) {
+ OverloadExpr::FindResult R = OverloadExpr::find(E);
+ OverloadExpr *Ovl = R.Expression;
+ FunctionDecl *Result = nullptr;
+ DeclAccessPair DAP;
+ // Don't use the AddressOfResolver because we're specifically looking for
+ // cases where we have one overload candidate that lacks
+ // enable_if/pass_object_size/...
+ for (auto I = Ovl->decls_begin(), E = Ovl->decls_end(); I != E; ++I) {
+ auto *FD = dyn_cast<FunctionDecl>(I->getUnderlyingDecl());
+ if (!FD)
+ return nullptr;
+
+ if (!checkAddressOfFunctionIsAvailable(FD))
+ continue;
+
+ // We have more than one result; quit.
+ if (Result)
+ return nullptr;
+ DAP = I.getPair();
+ Result = FD;
+ }
+
+ if (Result)
+ Pair = DAP;
+ return Result;
+}
+
+/// \brief Given an overloaded function, tries to turn it into a non-overloaded
+/// function reference using resolveAddressOfOnlyViableOverloadCandidate. This
+/// will perform access checks, diagnose the use of the resultant decl, and, if
+/// necessary, perform a function-to-pointer decay.
+///
+/// Returns false if resolveAddressOfOnlyViableOverloadCandidate fails.
+/// Otherwise, returns true. This may emit diagnostics and return true.
+bool Sema::resolveAndFixAddressOfOnlyViableOverloadCandidate(
+ ExprResult &SrcExpr) {
+ Expr *E = SrcExpr.get();
+ assert(E->getType() == Context.OverloadTy && "SrcExpr must be an overload");
+
+ DeclAccessPair DAP;
+ FunctionDecl *Found = resolveAddressOfOnlyViableOverloadCandidate(E, DAP);
+ if (!Found)
+ return false;
+
+ // Emitting multiple diagnostics for a function that is both inaccessible and
+ // unavailable is consistent with our behavior elsewhere. So, always check
+ // for both.
+ DiagnoseUseOfDecl(Found, E->getExprLoc());
+ CheckAddressOfMemberAccess(E, DAP);
+ Expr *Fixed = FixOverloadedFunctionReference(E, DAP, Found);
+ if (Fixed->getType()->isFunctionType())
+ SrcExpr = DefaultFunctionArrayConversion(Fixed, /*Diagnose=*/false);
+ else
+ SrcExpr = Fixed;
+ return true;
+}
+
+/// \brief Given an expression that refers to an overloaded function, try to
/// resolve that overloaded function expression down to a single function.
///
/// This routine can only resolve template-ids that refer to a single function
@@ -10671,7 +10838,7 @@ Sema::ResolveSingleFunctionTemplateSpecialization(OverloadExpr *ovl,
// Make a note of the failed deduction for diagnostics.
// TODO: Actually use the failed-deduction info?
FailedCandidates.addCandidate()
- .set(FunctionTemplate->getTemplatedDecl(),
+ .set(I.getPair(), FunctionTemplate->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, Result, Info));
continue;
}
@@ -12236,6 +12403,16 @@ Sema::BuildCallToMemberFunction(Scope *S, Expr *MemExprE,
<< MD->getDeclName();
}
}
+
+ if (CXXDestructorDecl *DD =
+ dyn_cast<CXXDestructorDecl>(TheCall->getMethodDecl())) {
+ // a->A::f() doesn't go through the vtable, except in AppleKext mode.
+ bool CallCanBeVirtual = !MemExpr->hasQualifier() || getLangOpts().AppleKext;
+ CheckVirtualDtorCall(DD, MemExpr->getLocStart(), /*IsDelete=*/false,
+ CallCanBeVirtual, /*WarnOnNonAbstractTypes=*/true,
+ MemExpr->getMemberLoc());
+ }
+
return MaybeBindToTemporary(TheCall);
}
@@ -12843,6 +13020,9 @@ Expr *Sema::FixOverloadedFunctionReference(Expr *E, DeclAccessPair Found,
= Context.getTypeDeclType(cast<RecordDecl>(Method->getDeclContext()));
QualType MemPtrType
= Context.getMemberPointerType(Fn->getType(), ClassType.getTypePtr());
+ // Under the MS ABI, lock down the inheritance model now.
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft())
+ (void)isCompleteType(UnOp->getOperatorLoc(), MemPtrType);
return new (Context) UnaryOperator(SubExpr, UO_AddrOf, MemPtrType,
VK_RValue, OK_Ordinary,
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
index e5d51f173caa..c93d800f96d1 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaPseudoObject.cpp
@@ -578,7 +578,7 @@ bool ObjCPropertyOpBuilder::isWeakProperty() const {
if (RefExpr->isExplicitProperty()) {
const ObjCPropertyDecl *Prop = RefExpr->getExplicitProperty();
if (Prop->getPropertyAttributes() & ObjCPropertyDecl::OBJC_PR_weak)
- return !Prop->hasAttr<IBOutletAttr>();
+ return true;
T = Prop->getType();
} else if (Getter) {
@@ -658,7 +658,8 @@ bool ObjCPropertyOpBuilder::findSetter(bool warn) {
SmallString<100> PropertyName = thisPropertyName;
PropertyName[0] = front;
IdentifierInfo *AltMember = &S.PP.getIdentifierTable().get(PropertyName);
- if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(AltMember))
+ if (ObjCPropertyDecl *prop1 = IFace->FindPropertyDeclaration(
+ AltMember, prop->getQueryKind()))
if (prop != prop1 && (prop1->getSetterMethodDecl() == setter)) {
S.Diag(RefExpr->getExprLoc(), diag::error_property_setter_ambiguous_use)
<< prop << prop1 << setter->getSelector();
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
index e1b1a47e182b..8e8104e581b2 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmt.cpp
@@ -37,6 +37,7 @@
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallVector.h"
+
using namespace clang;
using namespace sema;
@@ -249,10 +250,10 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
// is written in a macro body, only warn if it has the warn_unused_result
// attribute.
if (const Decl *FD = CE->getCalleeDecl()) {
- const FunctionDecl *Func = dyn_cast<FunctionDecl>(FD);
- if (Func ? Func->hasUnusedResultAttr()
- : FD->hasAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << R1 << R2;
+ if (const Attr *A = isa<FunctionDecl>(FD)
+ ? cast<FunctionDecl>(FD)->getUnusedResultAttr()
+ : FD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
return;
}
if (ShouldSuppress)
@@ -276,8 +277,8 @@ void Sema::DiagnoseUnusedExprResult(const Stmt *S) {
}
const ObjCMethodDecl *MD = ME->getMethodDecl();
if (MD) {
- if (MD->hasAttr<WarnUnusedResultAttr>()) {
- Diag(Loc, diag::warn_unused_result) << R1 << R2;
+ if (const auto *A = MD->getAttr<WarnUnusedResultAttr>()) {
+ Diag(Loc, diag::warn_unused_result) << A << R1 << R2;
return;
}
}
@@ -488,36 +489,62 @@ StmtResult Sema::ActOnAttributedStmt(SourceLocation AttrLoc,
return LS;
}
+namespace {
+class CommaVisitor : public EvaluatedExprVisitor<CommaVisitor> {
+ typedef EvaluatedExprVisitor<CommaVisitor> Inherited;
+ Sema &SemaRef;
+public:
+ CommaVisitor(Sema &SemaRef) : Inherited(SemaRef.Context), SemaRef(SemaRef) {}
+ void VisitBinaryOperator(BinaryOperator *E) {
+ if (E->getOpcode() == BO_Comma)
+ SemaRef.DiagnoseCommaOperator(E->getLHS(), E->getExprLoc());
+ EvaluatedExprVisitor<CommaVisitor>::VisitBinaryOperator(E);
+ }
+};
+}
+
StmtResult
-Sema::ActOnIfStmt(SourceLocation IfLoc, FullExprArg CondVal, Decl *CondVar,
+Sema::ActOnIfStmt(SourceLocation IfLoc, bool IsConstexpr, Stmt *InitStmt,
+ ConditionResult Cond,
Stmt *thenStmt, SourceLocation ElseLoc,
Stmt *elseStmt) {
- ExprResult CondResult(CondVal.release());
-
- VarDecl *ConditionVar = nullptr;
- if (CondVar) {
- ConditionVar = cast<VarDecl>(CondVar);
- CondResult = CheckConditionVariable(ConditionVar, IfLoc, true);
- CondResult = ActOnFinishFullExpr(CondResult.get(), IfLoc);
- }
- Expr *ConditionExpr = CondResult.getAs<Expr>();
- if (ConditionExpr) {
- DiagnoseUnusedExprResult(thenStmt);
+ if (Cond.isInvalid())
+ Cond = ConditionResult(
+ *this, nullptr,
+ MakeFullExpr(new (Context) OpaqueValueExpr(SourceLocation(),
+ Context.BoolTy, VK_RValue),
+ IfLoc),
+ false);
+
+ Expr *CondExpr = Cond.get().second;
+ if (!Diags.isIgnored(diag::warn_comma_operator,
+ CondExpr->getExprLoc()))
+ CommaVisitor(*this).Visit(CondExpr);
+
+ if (!elseStmt)
+ DiagnoseEmptyStmtBody(CondExpr->getLocEnd(), thenStmt,
+ diag::warn_empty_if_body);
+
+ return BuildIfStmt(IfLoc, IsConstexpr, InitStmt, Cond, thenStmt, ElseLoc,
+ elseStmt);
+}
+
+StmtResult Sema::BuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+ Stmt *InitStmt, ConditionResult Cond,
+ Stmt *thenStmt, SourceLocation ElseLoc,
+ Stmt *elseStmt) {
+ if (Cond.isInvalid())
+ return StmtError();
- if (!elseStmt) {
- DiagnoseEmptyStmtBody(ConditionExpr->getLocEnd(), thenStmt,
- diag::warn_empty_if_body);
- }
+ if (IsConstexpr)
+ getCurFunction()->setHasBranchProtectedScope();
- DiagnoseUnusedExprResult(elseStmt);
- } else {
- // Create a dummy Expr for the condition for error recovery
- ConditionExpr = new (Context) OpaqueValueExpr(SourceLocation(),
- Context.BoolTy, VK_RValue);
- }
+ DiagnoseUnusedExprResult(thenStmt);
+ DiagnoseUnusedExprResult(elseStmt);
- return new (Context) IfStmt(Context, IfLoc, ConditionVar, ConditionExpr,
- thenStmt, ElseLoc, elseStmt);
+ return new (Context)
+ IfStmt(Context, IfLoc, IsConstexpr, InitStmt, Cond.get().first,
+ Cond.get().second, thenStmt, ElseLoc, elseStmt);
}
namespace {
@@ -579,24 +606,7 @@ static QualType GetTypeBeforeIntegralPromotion(Expr *&expr) {
return expr->getType();
}
-StmtResult
-Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
- Decl *CondVar) {
- ExprResult CondResult;
-
- VarDecl *ConditionVar = nullptr;
- if (CondVar) {
- ConditionVar = cast<VarDecl>(CondVar);
- CondResult = CheckConditionVariable(ConditionVar, SourceLocation(), false);
- if (CondResult.isInvalid())
- return StmtError();
-
- Cond = CondResult.get();
- }
-
- if (!Cond)
- return StmtError();
-
+ExprResult Sema::CheckSwitchCondition(SourceLocation SwitchLoc, Expr *Cond) {
class SwitchConvertDiagnoser : public ICEConvertDiagnoser {
Expr *Cond;
@@ -644,24 +654,24 @@ Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc, Expr *Cond,
}
} SwitchDiagnoser(Cond);
- CondResult =
+ ExprResult CondResult =
PerformContextualImplicitConversion(SwitchLoc, Cond, SwitchDiagnoser);
- if (CondResult.isInvalid()) return StmtError();
- Cond = CondResult.get();
+ if (CondResult.isInvalid())
+ return ExprError();
// C99 6.8.4.2p5 - Integer promotions are performed on the controlling expr.
- CondResult = UsualUnaryConversions(Cond);
- if (CondResult.isInvalid()) return StmtError();
- Cond = CondResult.get();
+ return UsualUnaryConversions(CondResult.get());
+}
- CondResult = ActOnFinishFullExpr(Cond, SwitchLoc);
- if (CondResult.isInvalid())
+StmtResult Sema::ActOnStartOfSwitchStmt(SourceLocation SwitchLoc,
+ Stmt *InitStmt, ConditionResult Cond) {
+ if (Cond.isInvalid())
return StmtError();
- Cond = CondResult.get();
getCurFunction()->setHasBranchIntoScope();
- SwitchStmt *SS = new (Context) SwitchStmt(Context, ConditionVar, Cond);
+ SwitchStmt *SS = new (Context)
+ SwitchStmt(Context, InitStmt, Cond.get().first, Cond.get().second);
getCurFunction()->SwitchStack.push_back(SS);
return SS;
}
@@ -980,7 +990,8 @@ Sema::ActOnFinishSwitchStmt(SourceLocation SwitchLoc, Stmt *Switch,
<< SourceRange(CR->getLHS()->getLocStart(),
Hi->getLocEnd());
CaseRanges.erase(CaseRanges.begin()+i);
- --i, --e;
+ --i;
+ --e;
continue;
}
@@ -1221,23 +1232,17 @@ Sema::DiagnoseAssignmentEnum(QualType DstType, QualType SrcType,
}
}
-StmtResult
-Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
- Decl *CondVar, Stmt *Body) {
- ExprResult CondResult(Cond.release());
-
- VarDecl *ConditionVar = nullptr;
- if (CondVar) {
- ConditionVar = cast<VarDecl>(CondVar);
- CondResult = CheckConditionVariable(ConditionVar, WhileLoc, true);
- CondResult = ActOnFinishFullExpr(CondResult.get(), WhileLoc);
- if (CondResult.isInvalid())
- return StmtError();
- }
- Expr *ConditionExpr = CondResult.get();
- if (!ConditionExpr)
+StmtResult Sema::ActOnWhileStmt(SourceLocation WhileLoc, ConditionResult Cond,
+ Stmt *Body) {
+ if (Cond.isInvalid())
return StmtError();
- CheckBreakContinueBinding(ConditionExpr);
+
+ auto CondVal = Cond.get();
+ CheckBreakContinueBinding(CondVal.second);
+
+ if (CondVal.second &&
+ !Diags.isIgnored(diag::warn_comma_operator, CondVal.second->getExprLoc()))
+ CommaVisitor(*this).Visit(CondVal.second);
DiagnoseUnusedExprResult(Body);
@@ -1245,7 +1250,7 @@ Sema::ActOnWhileStmt(SourceLocation WhileLoc, FullExprArg Cond,
getCurCompoundScope().setHasEmptyLoopBodies();
return new (Context)
- WhileStmt(Context, ConditionVar, ConditionExpr, Body, WhileLoc);
+ WhileStmt(Context, CondVal.first, CondVal.second, Body, WhileLoc);
}
StmtResult
@@ -1255,7 +1260,7 @@ Sema::ActOnDoStmt(SourceLocation DoLoc, Stmt *Body,
assert(Cond && "ActOnDoStmt(): missing expression");
CheckBreakContinueBinding(Cond);
- ExprResult CondResult = CheckBooleanCondition(Cond, DoLoc);
+ ExprResult CondResult = CheckBooleanCondition(DoLoc, Cond);
if (CondResult.isInvalid())
return StmtError();
Cond = CondResult.get();
@@ -1416,6 +1421,18 @@ namespace {
FoundDecl = true;
}
+ void VisitPseudoObjectExpr(PseudoObjectExpr *POE) {
+ // Only need to visit the semantics for POE.
+ // SyntaticForm doesn't really use the Decal.
+ for (auto *S : POE->semantics()) {
+ if (auto *OVE = dyn_cast<OpaqueValueExpr>(S))
+ // Look past the OVE into the expression it binds.
+ Visit(OVE->getSourceExpr());
+ else
+ Visit(S);
+ }
+ }
+
bool FoundDeclInUse() { return FoundDecl; }
}; // end class DeclMatcher
@@ -1481,6 +1498,10 @@ namespace {
// variables Increment and DRE.
bool ProcessIterationStmt(Sema &S, Stmt* Statement, bool &Increment,
DeclRefExpr *&DRE) {
+ if (auto Cleanups = dyn_cast<ExprWithCleanups>(Statement))
+ if (!Cleanups->cleanupsHaveSideEffects())
+ Statement = Cleanups->getSubExpr();
+
if (UnaryOperator *UO = dyn_cast<UnaryOperator>(Statement)) {
switch (UO->getOpcode()) {
default: return false;
@@ -1603,11 +1624,13 @@ void Sema::CheckBreakContinueBinding(Expr *E) {
}
}
-StmtResult
-Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
- Stmt *First, FullExprArg second, Decl *secondVar,
- FullExprArg third,
- SourceLocation RParenLoc, Stmt *Body) {
+StmtResult Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
+ Stmt *First, ConditionResult Second,
+ FullExprArg third, SourceLocation RParenLoc,
+ Stmt *Body) {
+ if (Second.isInvalid())
+ return StmtError();
+
if (!getLangOpts().CPlusPlus) {
if (DeclStmt *DS = dyn_cast_or_null<DeclStmt>(First)) {
// C99 6.8.5p3: The declaration part of a 'for' statement shall only
@@ -1625,21 +1648,18 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
}
}
- CheckBreakContinueBinding(second.get());
+ CheckBreakContinueBinding(Second.get().second);
CheckBreakContinueBinding(third.get());
- CheckForLoopConditionalStatement(*this, second.get(), third.get(), Body);
+ if (!Second.get().first)
+ CheckForLoopConditionalStatement(*this, Second.get().second, third.get(),
+ Body);
CheckForRedundantIteration(*this, third.get(), Body);
- ExprResult SecondResult(second.release());
- VarDecl *ConditionVar = nullptr;
- if (secondVar) {
- ConditionVar = cast<VarDecl>(secondVar);
- SecondResult = CheckConditionVariable(ConditionVar, ForLoc, true);
- SecondResult = ActOnFinishFullExpr(SecondResult.get(), ForLoc);
- if (SecondResult.isInvalid())
- return StmtError();
- }
+ if (Second.get().second &&
+ !Diags.isIgnored(diag::warn_comma_operator,
+ Second.get().second->getExprLoc()))
+ CommaVisitor(*this).Visit(Second.get().second);
Expr *Third = third.release().getAs<Expr>();
@@ -1650,8 +1670,9 @@ Sema::ActOnForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
if (isa<NullStmt>(Body))
getCurCompoundScope().setHasEmptyLoopBodies();
- return new (Context) ForStmt(Context, First, SecondResult.get(), ConditionVar,
- Third, Body, ForLoc, LParenLoc, RParenLoc);
+ return new (Context)
+ ForStmt(Context, First, Second.get().second, Second.get().first, Third,
+ Body, ForLoc, LParenLoc, RParenLoc);
}
/// In an Objective C collection iteration statement:
@@ -1992,8 +2013,9 @@ StmtResult Sema::ActOnCXXForRangeStmt(Scope *S, SourceLocation ForLoc,
}
return BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc, RangeDecl.get(),
- /*BeginEndDecl=*/nullptr, /*Cond=*/nullptr,
- /*Inc=*/nullptr, DS, RParenLoc, Kind);
+ /*BeginStmt=*/nullptr, /*EndStmt=*/nullptr,
+ /*Cond=*/nullptr, /*Inc=*/nullptr,
+ DS, RParenLoc, Kind);
}
/// \brief Create the initialization, compare, and increment steps for
@@ -2143,8 +2165,8 @@ struct InvalidateOnErrorScope {
/// BuildCXXForRangeStmt - Build or instantiate a C++11 for-range statement.
StmtResult
Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
- SourceLocation ColonLoc,
- Stmt *RangeDecl, Stmt *BeginEnd, Expr *Cond,
+ SourceLocation ColonLoc, Stmt *RangeDecl,
+ Stmt *Begin, Stmt *End, Expr *Cond,
Expr *Inc, Stmt *LoopVarDecl,
SourceLocation RParenLoc, BuildForRangeKind Kind) {
// FIXME: This should not be used during template instantiation. We should
@@ -2170,7 +2192,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
InvalidateOnErrorScope Invalidate(*this, LoopVar,
LoopVar->getType()->isUndeducedType());
- StmtResult BeginEndDecl = BeginEnd;
+ StmtResult BeginDeclStmt = Begin;
+ StmtResult EndDeclStmt = End;
ExprResult NotEqExpr = Cond, IncrExpr = Inc;
if (RangeVarType->isDependentType()) {
@@ -2181,7 +2204,7 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// them in properly when we instantiate the loop.
if (!LoopVar->isInvalidDecl() && Kind != BFRK_Check)
LoopVar->setType(SubstAutoType(LoopVar->getType(), Context.DependentTy));
- } else if (!BeginEndDecl.get()) {
+ } else if (!BeginDeclStmt.get()) {
SourceLocation RangeLoc = RangeVar->getLocation();
const QualType RangeVarNonRefType = RangeVarType.getNonReferenceType();
@@ -2306,20 +2329,21 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
"invalid range expression in for loop");
// C++11 [dcl.spec.auto]p7: BeginType and EndType must be the same.
+ // C++1z removes this restriction.
QualType BeginType = BeginVar->getType(), EndType = EndVar->getType();
if (!Context.hasSameType(BeginType, EndType)) {
- Diag(RangeLoc, diag::err_for_range_begin_end_types_differ)
- << BeginType << EndType;
+ Diag(RangeLoc, getLangOpts().CPlusPlus1z
+ ? diag::warn_for_range_begin_end_types_differ
+ : diag::ext_for_range_begin_end_types_differ)
+ << BeginType << EndType;
NoteForRangeBeginEndFunction(*this, BeginExpr.get(), BEF_begin);
NoteForRangeBeginEndFunction(*this, EndExpr.get(), BEF_end);
}
- Decl *BeginEndDecls[] = { BeginVar, EndVar };
- // Claim the type doesn't contain auto: we've already done the checking.
- DeclGroupPtrTy BeginEndGroup =
- BuildDeclaratorGroup(MutableArrayRef<Decl *>(BeginEndDecls, 2),
- /*TypeMayContainAuto=*/ false);
- BeginEndDecl = ActOnDeclStmt(BeginEndGroup, ColonLoc, ColonLoc);
+ BeginDeclStmt =
+ ActOnDeclStmt(ConvertDeclToDeclGroup(BeginVar), ColonLoc, ColonLoc);
+ EndDeclStmt =
+ ActOnDeclStmt(ConvertDeclToDeclGroup(EndVar), ColonLoc, ColonLoc);
const QualType BeginRefNonRefType = BeginType.getNonReferenceType();
ExprResult BeginRef = BuildDeclRefExpr(BeginVar, BeginRefNonRefType,
@@ -2335,8 +2359,10 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
// Build and check __begin != __end expression.
NotEqExpr = ActOnBinOp(S, ColonLoc, tok::exclaimequal,
BeginRef.get(), EndRef.get());
- NotEqExpr = ActOnBooleanCondition(S, ColonLoc, NotEqExpr.get());
- NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
+ if (!NotEqExpr.isInvalid())
+ NotEqExpr = CheckBooleanCondition(ColonLoc, NotEqExpr.get());
+ if (!NotEqExpr.isInvalid())
+ NotEqExpr = ActOnFinishFullExpr(NotEqExpr.get());
if (NotEqExpr.isInvalid()) {
Diag(RangeLoc, diag::note_for_range_invalid_iterator)
<< RangeLoc << 0 << BeginRangeRef.get()->getType();
@@ -2394,7 +2420,8 @@ Sema::BuildCXXForRangeStmt(SourceLocation ForLoc, SourceLocation CoawaitLoc,
return StmtResult();
return new (Context) CXXForRangeStmt(
- RangeDS, cast_or_null<DeclStmt>(BeginEndDecl.get()), NotEqExpr.get(),
+ RangeDS, cast_or_null<DeclStmt>(BeginDeclStmt.get()),
+ cast_or_null<DeclStmt>(EndDeclStmt.get()), NotEqExpr.get(),
IncrExpr.get(), LoopVarDS, /*Body=*/nullptr, ForLoc, CoawaitLoc,
ColonLoc, RParenLoc);
}
@@ -2426,6 +2453,10 @@ static void DiagnoseForRangeReferenceVariableCopies(Sema &SemaRef,
QualType VariableType = VD->getType();
+ if (auto Cleanups = dyn_cast<ExprWithCleanups>(InitExpr))
+ if (!Cleanups->cleanupsHaveSideEffects())
+ InitExpr = Cleanups->getSubExpr();
+
const MaterializeTemporaryExpr *MTE =
dyn_cast<MaterializeTemporaryExpr>(InitExpr);
@@ -2663,16 +2694,16 @@ Sema::ActOnBreakStmt(SourceLocation BreakLoc, Scope *CurScope) {
/// \param E The expression being returned from the function or block, or
/// being thrown.
///
-/// \param AllowFunctionParameter Whether we allow function parameters to
-/// be considered NRVO candidates. C++ prohibits this for NRVO itself, but
-/// we re-use this logic to determine whether we should try to move as part of
-/// a return or throw (which does allow function parameters).
+/// \param AllowParamOrMoveConstructible Whether we allow function parameters or
+/// id-expressions that could be moved out of the function to be considered NRVO
+/// candidates. C++ prohibits these for NRVO itself, but we re-use this logic to
+/// determine whether we should try to move as part of a return or throw (which
+/// does allow function parameters).
///
/// \returns The NRVO candidate variable, if the return statement may use the
/// NRVO, or NULL if there is no such candidate.
-VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
- Expr *E,
- bool AllowFunctionParameter) {
+VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType, Expr *E,
+ bool AllowParamOrMoveConstructible) {
if (!getLangOpts().CPlusPlus)
return nullptr;
@@ -2685,13 +2716,13 @@ VarDecl *Sema::getCopyElisionCandidate(QualType ReturnType,
if (!VD)
return nullptr;
- if (isCopyElisionCandidate(ReturnType, VD, AllowFunctionParameter))
+ if (isCopyElisionCandidate(ReturnType, VD, AllowParamOrMoveConstructible))
return VD;
return nullptr;
}
bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
- bool AllowFunctionParameter) {
+ bool AllowParamOrMoveConstructible) {
QualType VDType = VD->getType();
// - in a return statement in a function with ...
// ... a class return type ...
@@ -2699,20 +2730,24 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
if (!ReturnType->isRecordType())
return false;
// ... the same cv-unqualified type as the function return type ...
- if (!VDType->isDependentType() &&
+ // When considering moving this expression out, allow dissimilar types.
+ if (!AllowParamOrMoveConstructible && !VDType->isDependentType() &&
!Context.hasSameUnqualifiedType(ReturnType, VDType))
return false;
}
// ...object (other than a function or catch-clause parameter)...
if (VD->getKind() != Decl::Var &&
- !(AllowFunctionParameter && VD->getKind() == Decl::ParmVar))
+ !(AllowParamOrMoveConstructible && VD->getKind() == Decl::ParmVar))
return false;
if (VD->isExceptionVariable()) return false;
// ...automatic...
if (!VD->hasLocalStorage()) return false;
+ if (AllowParamOrMoveConstructible)
+ return true;
+
// ...non-volatile...
if (VD->getType().isVolatileQualified()) return false;
@@ -2731,7 +2766,7 @@ bool Sema::isCopyElisionCandidate(QualType ReturnType, const VarDecl *VD,
/// \brief Perform the initialization of a potentially-movable value, which
/// is the result of return value.
///
-/// This routine implements C++0x [class.copy]p33, which attempts to treat
+/// This routine implements C++14 [class.copy]p32, which attempts to treat
/// returned lvalues as rvalues in certain cases (to prefer move construction),
/// then falls back to treating them as lvalues if that failed.
ExprResult
@@ -2740,52 +2775,59 @@ Sema::PerformMoveOrCopyInitialization(const InitializedEntity &Entity,
QualType ResultType,
Expr *Value,
bool AllowNRVO) {
- // C++0x [class.copy]p33:
- // When the criteria for elision of a copy operation are met or would
- // be met save for the fact that the source object is a function
- // parameter, and the object to be copied is designated by an lvalue,
- // overload resolution to select the constructor for the copy is first
- // performed as if the object were designated by an rvalue.
+ // C++14 [class.copy]p32:
+ // When the criteria for elision of a copy/move operation are met, but not for
+ // an exception-declaration, and the object to be copied is designated by an
+ // lvalue, or when the expression in a return statement is a (possibly
+ // parenthesized) id-expression that names an object with automatic storage
+ // duration declared in the body or parameter-declaration-clause of the
+ // innermost enclosing function or lambda-expression, overload resolution to
+ // select the constructor for the copy is first performed as if the object
+ // were designated by an rvalue.
ExprResult Res = ExprError();
- if (AllowNRVO &&
- (NRVOCandidate || getCopyElisionCandidate(ResultType, Value, true))) {
- ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack,
- Value->getType(), CK_NoOp, Value, VK_XValue);
+
+ if (AllowNRVO && !NRVOCandidate)
+ NRVOCandidate = getCopyElisionCandidate(ResultType, Value, true);
+
+ if (AllowNRVO && NRVOCandidate) {
+ ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
+ CK_NoOp, Value, VK_XValue);
Expr *InitExpr = &AsRvalue;
- InitializationKind Kind
- = InitializationKind::CreateCopy(Value->getLocStart(),
- Value->getLocStart());
- InitializationSequence Seq(*this, Entity, Kind, InitExpr);
- // [...] If overload resolution fails, or if the type of the first
- // parameter of the selected constructor is not an rvalue reference
- // to the object's type (possibly cv-qualified), overload resolution
- // is performed again, considering the object as an lvalue.
+ InitializationKind Kind = InitializationKind::CreateCopy(
+ Value->getLocStart(), Value->getLocStart());
+
+ InitializationSequence Seq(*this, Entity, Kind, InitExpr);
if (Seq) {
- for (InitializationSequence::step_iterator Step = Seq.step_begin(),
- StepEnd = Seq.step_end();
- Step != StepEnd; ++Step) {
- if (Step->Kind != InitializationSequence::SK_ConstructorInitialization)
+ for (const InitializationSequence::Step &Step : Seq.steps()) {
+ if (!(Step.Kind ==
+ InitializationSequence::SK_ConstructorInitialization ||
+ (Step.Kind == InitializationSequence::SK_UserConversion &&
+ isa<CXXConstructorDecl>(Step.Function.Function))))
continue;
- CXXConstructorDecl *Constructor
- = cast<CXXConstructorDecl>(Step->Function.Function);
+ CXXConstructorDecl *Constructor =
+ cast<CXXConstructorDecl>(Step.Function.Function);
const RValueReferenceType *RRefType
= Constructor->getParamDecl(0)->getType()
->getAs<RValueReferenceType>();
- // If we don't meet the criteria, break out now.
+ // [...] If the first overload resolution fails or was not performed, or
+ // if the type of the first parameter of the selected constructor is not
+ // an rvalue reference to the object’s type (possibly cv-qualified),
+ // overload resolution is performed again, considering the object as an
+ // lvalue.
if (!RRefType ||
!Context.hasSameUnqualifiedType(RRefType->getPointeeType(),
- Context.getTypeDeclType(Constructor->getParent())))
+ NRVOCandidate->getType()))
break;
// Promote "AsRvalue" to the heap, since we now need this
// expression node to persist.
- Value = ImplicitCastExpr::Create(Context, Value->getType(),
- CK_NoOp, Value, nullptr, VK_XValue);
+ Value = ImplicitCastExpr::Create(Context, Value->getType(), CK_NoOp,
+ Value, nullptr, VK_XValue);
// Complete type-checking the initialization of the return type
// using the constructor we found.
@@ -2821,8 +2863,21 @@ Sema::ActOnCapScopeReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
CapturingScopeInfo *CurCap = cast<CapturingScopeInfo>(getCurFunction());
QualType FnRetType = CurCap->ReturnType;
LambdaScopeInfo *CurLambda = dyn_cast<LambdaScopeInfo>(CurCap);
+ bool HasDeducedReturnType =
+ CurLambda && hasDeducedReturnType(CurLambda->CallOperator);
+
+ if (ExprEvalContexts.back().Context == DiscardedStatement &&
+ (HasDeducedReturnType || CurCap->HasImplicitReturnType)) {
+ if (RetValExp) {
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.get();
+ }
+ return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
+ }
- if (CurLambda && hasDeducedReturnType(CurLambda->CallOperator)) {
+ if (HasDeducedReturnType) {
// In C++1y, the return type may involve 'auto'.
// FIXME: Blocks might have a return type of 'auto' explicitly specified.
FunctionDecl *FD = CurLambda->CallOperator;
@@ -3066,22 +3121,28 @@ bool Sema::DeduceFunctionTypeFromReturnExpr(FunctionDecl *FD,
// has multiple return statements, the return type is deduced for each return
// statement. [...] if the type deduced is not the same in each deduction,
// the program is ill-formed.
- if (AT->isDeduced() && !FD->isInvalidDecl()) {
+ QualType DeducedT = AT->getDeducedType();
+ if (!DeducedT.isNull() && !FD->isInvalidDecl()) {
AutoType *NewAT = Deduced->getContainedAutoType();
+ // It is possible that NewAT->getDeducedType() is null. When that happens,
+ // we should not crash, instead we ignore this deduction.
+ if (NewAT->getDeducedType().isNull())
+ return false;
+
CanQualType OldDeducedType = Context.getCanonicalFunctionResultType(
- AT->getDeducedType());
+ DeducedT);
CanQualType NewDeducedType = Context.getCanonicalFunctionResultType(
NewAT->getDeducedType());
if (!FD->isDependentContext() && OldDeducedType != NewDeducedType) {
const LambdaScopeInfo *LambdaSI = getCurLambda();
if (LambdaSI && LambdaSI->HasImplicitReturnType) {
Diag(ReturnLoc, diag::err_typecheck_missing_return_type_incompatible)
- << NewAT->getDeducedType() << AT->getDeducedType()
+ << NewAT->getDeducedType() << DeducedT
<< true /*IsLambda*/;
} else {
Diag(ReturnLoc, diag::err_auto_fn_different_deductions)
<< (AT->isDecltypeAuto() ? 1 : 0)
- << NewAT->getDeducedType() << AT->getDeducedType();
+ << NewAT->getDeducedType() << DeducedT;
}
return true;
}
@@ -3097,9 +3158,8 @@ StmtResult
Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp,
Scope *CurScope) {
StmtResult R = BuildReturnStmt(ReturnLoc, RetValExp);
- if (R.isInvalid()) {
+ if (R.isInvalid() || ExprEvalContexts.back().Context == DiscardedStatement)
return R;
- }
if (VarDecl *VD =
const_cast<VarDecl*>(cast<ReturnStmt>(R.get())->getNRVOCandidate())) {
@@ -3148,6 +3208,19 @@ StmtResult Sema::BuildReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) {
} else // If we don't have a function/method context, bail.
return StmtError();
+ // C++1z: discarded return statements are not considered when deducing a
+ // return type.
+ if (ExprEvalContexts.back().Context == DiscardedStatement &&
+ FnRetType->getContainedAutoType()) {
+ if (RetValExp) {
+ ExprResult ER = ActOnFinishFullExpr(RetValExp, ReturnLoc);
+ if (ER.isInvalid())
+ return StmtError();
+ RetValExp = ER.get();
+ }
+ return new (Context) ReturnStmt(ReturnLoc, RetValExp, nullptr);
+ }
+
// FIXME: Add a flag to the ScopeInfo to indicate whether we're performing
// deduction.
if (getLangOpts().CPlusPlus14) {
@@ -3525,11 +3598,6 @@ template <> struct DenseMapInfo<CatchHandlerType> {
return LHS == RHS;
}
};
-
-// It's OK to treat CatchHandlerType as a POD type.
-template <> struct isPodLike<CatchHandlerType> {
- static const bool value = true;
-};
}
namespace {
@@ -3554,7 +3622,7 @@ public:
bool operator()(const CXXBaseSpecifier *S, CXXBasePath &) {
if (S->getAccessSpecifier() == AccessSpecifier::AS_public) {
CatchHandlerType Check(S->getType(), CheckAgainstPointer);
- auto M = TypesToCheck;
+ const auto &M = TypesToCheck;
auto I = M.find(Check);
if (I != M.end()) {
FoundHandler = I->second;
@@ -3916,9 +3984,9 @@ StmtResult Sema::ActOnCapturedRegionEnd(Stmt *S) {
CapturedDecl *CD = RSI->TheCapturedDecl;
RecordDecl *RD = RSI->TheRecordDecl;
- CapturedStmt *Res = CapturedStmt::Create(getASTContext(), S,
- RSI->CapRegionKind, Captures,
- CaptureInits, CD, RD);
+ CapturedStmt *Res = CapturedStmt::Create(
+ getASTContext(), S, static_cast<CapturedRegionKind>(RSI->CapRegionKind),
+ Captures, CaptureInits, CD, RD);
CD->setBody(Res->getCapturedStmt());
RD->completeDefinition();
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
index 11a4f8bfa85c..cd4269cd7eae 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAsm.cpp
@@ -623,16 +623,12 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
if (!LookupName(BaseResult, getCurScope()))
return true;
-
- LookupResult CurrBaseResult(BaseResult);
-
+
+ if(!BaseResult.isSingleResult())
+ return true;
+ NamedDecl *FoundDecl = BaseResult.getFoundDecl();
for (StringRef NextMember : Members) {
-
- if (!CurrBaseResult.isSingleResult())
- return true;
-
const RecordType *RT = nullptr;
- NamedDecl *FoundDecl = CurrBaseResult.getFoundDecl();
if (VarDecl *VD = dyn_cast<VarDecl>(FoundDecl))
RT = VD->getType()->getAs<RecordType>();
else if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(FoundDecl)) {
@@ -655,13 +651,15 @@ bool Sema::LookupInlineAsmField(StringRef Base, StringRef Member,
if (!LookupQualifiedName(FieldResult, RT->getDecl()))
return true;
+ if (!FieldResult.isSingleResult())
+ return true;
+ FoundDecl = FieldResult.getFoundDecl();
+
// FIXME: Handle IndirectFieldDecl?
- FieldDecl *FD = dyn_cast<FieldDecl>(FieldResult.getFoundDecl());
+ FieldDecl *FD = dyn_cast<FieldDecl>(FoundDecl);
if (!FD)
return true;
- CurrBaseResult = FieldResult;
-
const ASTRecordLayout &RL = Context.getASTRecordLayout(RT->getDecl());
unsigned i = FD->getFieldIndex();
CharUnits Result = Context.toCharUnitsFromBits(RL.getFieldOffset(i));
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
index 984bd078fa03..87fd88939572 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaStmtAttr.cpp
@@ -25,9 +25,11 @@ using namespace sema;
static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
+ FallThroughAttr Attr(A.getRange(), S.Context,
+ A.getAttributeSpellingListIndex());
if (!isa<NullStmt>(St)) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_wrong_target)
- << St->getLocStart();
+ << Attr.getSpelling() << St->getLocStart();
if (isa<SwitchCase>(St)) {
SourceLocation L = S.getLocForEndOfToken(Range.getEnd());
S.Diag(L, diag::note_fallthrough_insert_semi_fixit)
@@ -35,12 +37,20 @@ static Attr *handleFallThroughAttr(Sema &S, Stmt *St, const AttributeList &A,
}
return nullptr;
}
- if (S.getCurFunction()->SwitchStack.empty()) {
+ auto *FnScope = S.getCurFunction();
+ if (FnScope->SwitchStack.empty()) {
S.Diag(A.getRange().getBegin(), diag::err_fallthrough_attr_outside_switch);
return nullptr;
}
- return ::new (S.Context) FallThroughAttr(A.getRange(), S.Context,
- A.getAttributeSpellingListIndex());
+
+ // If this is spelled as the standard C++1z attribute, but not in C++1z, warn
+ // about using it as an extension.
+ if (!S.getLangOpts().CPlusPlus1z && A.isCXX11Attribute() &&
+ !A.getScopeName())
+ S.Diag(A.getLoc(), diag::ext_cxx1z_attr) << A.getName();
+
+ FnScope->setHasFallthroughStmt();
+ return ::new (S.Context) auto(Attr);
}
static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
@@ -97,6 +107,7 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
.Case("interleave_count", LoopHintAttr::InterleaveCount)
.Case("unroll", LoopHintAttr::Unroll)
.Case("unroll_count", LoopHintAttr::UnrollCount)
+ .Case("distribute", LoopHintAttr::Distribute)
.Default(LoopHintAttr::Vectorize);
if (Option == LoopHintAttr::VectorizeWidth ||
Option == LoopHintAttr::InterleaveCount ||
@@ -107,7 +118,8 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
State = LoopHintAttr::Numeric;
} else if (Option == LoopHintAttr::Vectorize ||
Option == LoopHintAttr::Interleave ||
- Option == LoopHintAttr::Unroll) {
+ Option == LoopHintAttr::Unroll ||
+ Option == LoopHintAttr::Distribute) {
assert(StateLoc && StateLoc->Ident && "Loop hint must have an argument");
if (StateLoc->Ident->isStr("disable"))
State = LoopHintAttr::Disable;
@@ -130,18 +142,21 @@ static Attr *handleLoopHintAttr(Sema &S, Stmt *St, const AttributeList &A,
static void
CheckForIncompatibleAttributes(Sema &S,
const SmallVectorImpl<const Attr *> &Attrs) {
- // There are 3 categories of loop hints attributes: vectorize, interleave,
- // and unroll. Each comes in two variants: a state form and a numeric form.
- // The state form selectively defaults/enables/disables the transformation
- // for the loop (for unroll, default indicates full unrolling rather than
- // enabling the transformation). The numeric form form provides an integer
- // hint (for example, unroll count) to the transformer. The following array
- // accumulates the hints encountered while iterating through the attributes
- // to check for compatibility.
+ // There are 4 categories of loop hints attributes: vectorize, interleave,
+ // unroll and distribute. Except for distribute they come in two variants: a
+ // state form and a numeric form. The state form selectively
+ // defaults/enables/disables the transformation for the loop (for unroll,
+ // default indicates full unrolling rather than enabling the transformation).
+ // The numeric form form provides an integer hint (for example, unroll count)
+ // to the transformer. The following array accumulates the hints encountered
+ // while iterating through the attributes to check for compatibility.
struct {
const LoopHintAttr *StateAttr;
const LoopHintAttr *NumericAttr;
- } HintAttrs[] = {{nullptr, nullptr}, {nullptr, nullptr}, {nullptr, nullptr}};
+ } HintAttrs[] = {{nullptr, nullptr},
+ {nullptr, nullptr},
+ {nullptr, nullptr},
+ {nullptr, nullptr}};
for (const auto *I : Attrs) {
const LoopHintAttr *LH = dyn_cast<LoopHintAttr>(I);
@@ -151,7 +166,7 @@ CheckForIncompatibleAttributes(Sema &S,
continue;
LoopHintAttr::OptionType Option = LH->getOption();
- enum { Vectorize, Interleave, Unroll } Category;
+ enum { Vectorize, Interleave, Unroll, Distribute } Category;
switch (Option) {
case LoopHintAttr::Vectorize:
case LoopHintAttr::VectorizeWidth:
@@ -165,12 +180,17 @@ CheckForIncompatibleAttributes(Sema &S,
case LoopHintAttr::UnrollCount:
Category = Unroll;
break;
+ case LoopHintAttr::Distribute:
+ // Perform the check for duplicated 'distribute' hints.
+ Category = Distribute;
+ break;
};
auto &CategoryState = HintAttrs[Category];
const LoopHintAttr *PrevAttr;
if (Option == LoopHintAttr::Vectorize ||
- Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll) {
+ Option == LoopHintAttr::Interleave || Option == LoopHintAttr::Unroll ||
+ Option == LoopHintAttr::Distribute) {
// Enable|Disable|AssumeSafety hint. For example, vectorize(enable).
PrevAttr = CategoryState.StateAttr;
CategoryState.StateAttr = LH;
@@ -203,6 +223,52 @@ CheckForIncompatibleAttributes(Sema &S,
}
}
+static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const AttributeList &A,
+ SourceRange Range) {
+ // OpenCL v2.0 s6.11.5 - opencl_unroll_hint can have 0 arguments (compiler
+ // determines unrolling factor) or 1 argument (the unroll factor provided
+ // by the user).
+
+ if (S.getLangOpts().OpenCLVersion < 200) {
+ S.Diag(A.getLoc(), diag::err_attribute_requires_opencl_version)
+ << A.getName() << "2.0" << 1;
+ return nullptr;
+ }
+
+ unsigned NumArgs = A.getNumArgs();
+
+ if (NumArgs > 1) {
+ S.Diag(A.getLoc(), diag::err_attribute_too_many_arguments) << A.getName()
+ << 1;
+ return nullptr;
+ }
+
+ unsigned UnrollFactor = 0;
+
+ if (NumArgs == 1) {
+ Expr *E = A.getArgAsExpr(0);
+ llvm::APSInt ArgVal(32);
+
+ if (!E->isIntegerConstantExpr(ArgVal, S.Context)) {
+ S.Diag(A.getLoc(), diag::err_attribute_argument_type)
+ << A.getName() << AANT_ArgumentIntegerConstant << E->getSourceRange();
+ return nullptr;
+ }
+
+ int Val = ArgVal.getSExtValue();
+
+ if (Val <= 0) {
+ S.Diag(A.getRange().getBegin(),
+ diag::err_attribute_requires_positive_integer)
+ << A.getName();
+ return nullptr;
+ }
+ UnrollFactor = Val;
+ }
+
+ return OpenCLUnrollHintAttr::CreateImplicit(S.Context, UnrollFactor);
+}
+
static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
SourceRange Range) {
switch (A.getKind()) {
@@ -215,10 +281,12 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const AttributeList &A,
return handleFallThroughAttr(S, St, A, Range);
case AttributeList::AT_LoopHint:
return handleLoopHintAttr(S, St, A, Range);
+ case AttributeList::AT_OpenCLUnrollHint:
+ return handleOpenCLUnrollHint(S, St, A, Range);
default:
// if we're here, then we parsed a known attribute, but didn't recognize
// it as a statement attribute => it is declaration attribute
- S.Diag(A.getRange().getBegin(), diag::err_attribute_invalid_on_stmt)
+ S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
<< A.getName() << St->getLocStart();
return nullptr;
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
index 138cee0b9424..7fc5db82d32c 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplate.cpp
@@ -1,13 +1,13 @@
-//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===/
+//===------- SemaTemplate.cpp - Semantic Analysis for C++ Templates -------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
//
// This file implements semantic analysis for C++ templates.
-//===----------------------------------------------------------------------===/
+//===----------------------------------------------------------------------===//
#include "TreeTransform.h"
#include "clang/AST/ASTConsumer.h"
@@ -32,6 +32,8 @@
#include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+
+#include <iterator>
using namespace clang;
using namespace sema;
@@ -413,9 +415,22 @@ Sema::ActOnDependentIdExpression(const CXXScopeSpec &SS,
const TemplateArgumentListInfo *TemplateArgs) {
DeclContext *DC = getFunctionLevelDeclContext();
- if (!isAddressOfOperand &&
- isa<CXXMethodDecl>(DC) &&
- cast<CXXMethodDecl>(DC)->isInstance()) {
+ // C++11 [expr.prim.general]p12:
+ // An id-expression that denotes a non-static data member or non-static
+ // member function of a class can only be used:
+ // (...)
+ // - if that id-expression denotes a non-static data member and it
+ // appears in an unevaluated operand.
+ //
+ // If this might be the case, form a DependentScopeDeclRefExpr instead of a
+ // CXXDependentScopeMemberExpr. The former can instantiate to either
+ // DeclRefExpr or MemberExpr depending on lookup results, while the latter is
+ // always a MemberExpr.
+ bool MightBeCxx11UnevalField =
+ getLangOpts().CPlusPlus11 && isUnevaluatedContext();
+
+ if (!MightBeCxx11UnevalField && !isAddressOfOperand &&
+ isa<CXXMethodDecl>(DC) && cast<CXXMethodDecl>(DC)->isInstance()) {
QualType ThisType = cast<CXXMethodDecl>(DC)->getThisType(Context);
// Since the 'this' expression is synthesized, we don't need to
@@ -458,7 +473,6 @@ void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
Diag(Loc, diag::err_template_param_shadow)
<< cast<NamedDecl>(PrevDecl)->getDeclName();
Diag(PrevDecl->getLocation(), diag::note_template_param_here);
- return;
}
/// AdjustDeclIfTemplate - If the given decl happens to be a template, reset
@@ -555,7 +569,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
ParsedType DefaultArg) {
assert(S->isTemplateParamScope() &&
"Template type parameter not in template parameter scope!");
- bool Invalid = false;
SourceLocation Loc = ParamNameLoc;
if (!ParamName)
@@ -567,8 +580,6 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
KeyLoc, Loc, Depth, Position, ParamName,
Typename, IsParameterPack);
Param->setAccess(AS_public);
- if (Invalid)
- Param->setInvalidDecl();
if (ParamName) {
maybeDiagnoseTemplateParameterShadow(*this, S, ParamNameLoc, ParamName);
@@ -583,7 +594,7 @@ Decl *Sema::ActOnTypeParameter(Scope *S, bool Typename,
// template-parameter that is not a template parameter pack.
if (DefaultArg && IsParameterPack) {
Diag(EqualLoc, diag::err_template_param_pack_default_arg);
- DefaultArg = ParsedType();
+ DefaultArg = nullptr;
}
// Handle the default argument, if provided.
@@ -790,7 +801,7 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
// However, it isn't worth doing.
TemplateArgumentLoc DefaultArg = translateTemplateArgument(*this, Default);
if (DefaultArg.getArgument().getAsTemplate().isNull()) {
- Diag(DefaultArg.getLocation(), diag::err_template_arg_not_class_template)
+ Diag(DefaultArg.getLocation(), diag::err_template_arg_not_valid_template)
<< DefaultArg.getSourceRange();
return Param;
}
@@ -807,18 +818,21 @@ Decl *Sema::ActOnTemplateTemplateParameter(Scope* S,
return Param;
}
-/// ActOnTemplateParameterList - Builds a TemplateParameterList that
-/// contains the template parameters in Params/NumParams.
+/// ActOnTemplateParameterList - Builds a TemplateParameterList, optionally
+/// constrained by RequiresClause, that contains the template parameters in
+/// Params.
TemplateParameterList *
Sema::ActOnTemplateParameterList(unsigned Depth,
SourceLocation ExportLoc,
SourceLocation TemplateLoc,
SourceLocation LAngleLoc,
ArrayRef<Decl *> Params,
- SourceLocation RAngleLoc) {
+ SourceLocation RAngleLoc,
+ Expr *RequiresClause) {
if (ExportLoc.isValid())
Diag(ExportLoc, diag::warn_template_export_unsupported);
+ // FIXME: store RequiresClause
return TemplateParameterList::Create(
Context, TemplateLoc, LAngleLoc,
llvm::makeArrayRef((NamedDecl *const *)Params.data(), Params.size()),
@@ -916,6 +930,13 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
if (Previous.begin() != Previous.end())
PrevDecl = (*Previous.begin())->getUnderlyingDecl();
+ if (PrevDecl && PrevDecl->isTemplateParameter()) {
+ // Maybe we will complain about the shadowed template parameter.
+ DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
+ // Just pretend that we didn't see the previous declaration.
+ PrevDecl = nullptr;
+ }
+
// If there is a previous declaration with the same name, check
// whether this is a valid redeclaration.
ClassTemplateDecl *PrevClassTemplate
@@ -1041,12 +1062,7 @@ Sema::CheckClassTemplate(Scope *S, unsigned TagSpec, TagUseKind TUK,
// definition, as part of error recovery?
return true;
}
- }
- } else if (PrevDecl && PrevDecl->isTemplateParameter()) {
- // Maybe we will complain about the shadowed template parameter.
- DiagnoseTemplateParameterShadow(NameLoc, PrevDecl);
- // Just pretend that we didn't see the previous declaration.
- PrevDecl = nullptr;
+ }
} else if (PrevDecl) {
// C++ [temp]p5:
// A class template shall not have the same name as any other
@@ -1577,7 +1593,7 @@ struct DependencyChecker : RecursiveASTVisitor<DependencyChecker> {
return TraverseType(T->getInjectedSpecializationType());
}
};
-}
+} // end anonymous namespace
/// Determines whether a given type depends on the given parameter
/// list.
@@ -2027,7 +2043,7 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
TemplateArgumentListInfo &TemplateArgs) {
ASTContext &Context = SemaRef.getASTContext();
switch (BTD->getBuiltinTemplateKind()) {
- case BTK__make_integer_seq:
+ case BTK__make_integer_seq: {
// Specializations of __make_integer_seq<S, T, N> are treated like
// S<T, 0, ..., N-1>.
@@ -2069,6 +2085,29 @@ checkBuiltinTemplateIdType(Sema &SemaRef, BuiltinTemplateDecl *BTD,
return SemaRef.CheckTemplateIdType(Converted[0].getAsTemplate(),
TemplateLoc, SyntheticTemplateArgs);
}
+
+ case BTK__type_pack_element:
+ // Specializations of
+ // __type_pack_element<Index, T_1, ..., T_N>
+ // are treated like T_Index.
+ assert(Converted.size() == 2 &&
+ "__type_pack_element should be given an index and a parameter pack");
+
+ // If the Index is out of bounds, the program is ill-formed.
+ TemplateArgument IndexArg = Converted[0], Ts = Converted[1];
+ llvm::APSInt Index = IndexArg.getAsIntegral();
+ assert(Index >= 0 && "the index used with __type_pack_element should be of "
+ "type std::size_t, and hence be non-negative");
+ if (Index >= Ts.pack_size()) {
+ SemaRef.Diag(TemplateArgs[0].getLocation(),
+ diag::err_type_pack_element_out_of_bounds);
+ return QualType();
+ }
+
+ // We simply return the type at index `Index`.
+ auto Nth = std::next(Ts.pack_begin(), Index.getExtValue());
+ return Nth->getAsType();
+ }
llvm_unreachable("unexpected BuiltinTemplateDecl!");
}
@@ -2119,7 +2158,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
return QualType();
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
@@ -2150,8 +2189,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
// template<typename T, typename U = T> struct A;
TemplateName CanonName = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonName,
- Converted.data(),
- Converted.size());
+ Converted);
// FIXME: CanonType is not actually the canonical type, and unfortunately
// it is a TemplateSpecializationType that we will never use again.
@@ -2213,8 +2251,7 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
ClassTemplate->getTemplatedDecl()->getLocStart(),
ClassTemplate->getLocation(),
ClassTemplate,
- Converted.data(),
- Converted.size(), nullptr);
+ Converted, nullptr);
ClassTemplate->AddSpecialization(Decl, InsertPos);
if (ClassTemplate->isOutOfLine())
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
@@ -2538,7 +2575,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs.getArgumentArray(), TemplateArgs.size(),
+ TemplateArgs.arguments(),
InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< VarTemplate->getDeclName();
@@ -2595,7 +2632,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
VarTemplatePartialSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc,
TemplateNameLoc, TemplateParams, VarTemplate, DI->getType(), DI, SC,
- Converted.data(), Converted.size(), TemplateArgs);
+ Converted, TemplateArgs);
if (!PrevPartial)
VarTemplate->AddPartialSpecialization(Partial, InsertPos);
@@ -2637,7 +2674,7 @@ DeclResult Sema::ActOnVarTemplateSpecialization(
// this explicit specialization or friend declaration.
Specialization = VarTemplateSpecializationDecl::Create(
Context, VarTemplate->getDeclContext(), TemplateKWLoc, TemplateNameLoc,
- VarTemplate, DI->getType(), DI, SC, Converted.data(), Converted.size());
+ VarTemplate, DI->getType(), DI, SC, Converted);
Specialization->setTemplateArgsInfo(TemplateArgs);
if (!PrevDecl)
@@ -2713,7 +2750,7 @@ struct PartialSpecMatchResult {
VarTemplatePartialSpecializationDecl *Partial;
TemplateArgumentList *Args;
};
-}
+} // end anonymous namespace
DeclResult
Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
@@ -2733,9 +2770,11 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// corresponds to these arguments.
void *InsertPos = nullptr;
if (VarTemplateSpecializationDecl *Spec = Template->findSpecialization(
- Converted, InsertPos))
+ Converted, InsertPos)) {
+ checkSpecializationVisibility(TemplateNameLoc, Spec);
// If we already have a variable template specialization, return it.
return Spec;
+ }
// This is the first time we have referenced this variable template
// specialization. Create the canonical declaration and add it to
@@ -2743,7 +2782,7 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
// that it represents. That is,
VarDecl *InstantiationPattern = Template->getTemplatedDecl();
TemplateArgumentList TemplateArgList(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
TemplateArgumentList *InstantiationArgs = &TemplateArgList;
bool AmbiguousPartialSpec = false;
typedef PartialSpecMatchResult MatchResult;
@@ -2776,8 +2815,9 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
DeduceTemplateArguments(Partial, TemplateArgList, Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
- FailedCandidates.addCandidate()
- .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
+ FailedCandidates.addCandidate().set(
+ DeclAccessPair::make(Template, AS_public), Partial,
+ MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
@@ -2834,8 +2874,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
}
// 2. Create the canonical declaration.
- // Note that we do not instantiate the variable just yet, since
- // instantiation is handled in DoMarkVarDeclReferenced().
+ // Note that we do not instantiate a definition until we see an odr-use
+ // in DoMarkVarDeclReferenced().
// FIXME: LateAttrs et al.?
VarTemplateSpecializationDecl *Decl = BuildVarTemplateInstantiation(
Template, InstantiationPattern, *InstantiationArgs, TemplateArgs,
@@ -2863,6 +2903,8 @@ Sema::CheckVarTemplateId(VarTemplateDecl *Template, SourceLocation TemplateLoc,
dyn_cast<VarTemplatePartialSpecializationDecl>(InstantiationPattern))
Decl->setInstantiationOf(D, InstantiationArgs);
+ checkSpecializationVisibility(TemplateNameLoc, Decl);
+
assert(Decl && "No variable template specialization?");
return Decl;
}
@@ -3219,8 +3261,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
if (Inst.isInvalid())
return nullptr;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
@@ -3272,8 +3313,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
if (Inst.isInvalid())
return ExprError();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
@@ -3324,8 +3364,7 @@ SubstDefaultTemplateArgument(Sema &SemaRef,
if (Inst.isInvalid())
return TemplateName();
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
// Only substitute for the innermost template argument list.
MultiLevelTemplateArgumentList TemplateArgLists;
@@ -3476,7 +3515,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
return true;
TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ Converted);
NTTPType = SubstType(NTTPType,
MultiLevelTemplateArgumentList(TemplateArgs),
NTTP->getLocation(),
@@ -3616,8 +3655,7 @@ bool Sema::CheckTemplateArgument(NamedDecl *Param,
if (Inst.isInvalid())
return true;
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Converted.data(), Converted.size());
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Converted);
TempParm = cast_or_null<TemplateTemplateParmDecl>(
SubstDecl(TempParm, CurContext,
MultiLevelTemplateArgumentList(TemplateArgs)));
@@ -3728,7 +3766,7 @@ static bool diagnoseMissingArgument(Sema &S, SourceLocation Loc,
S.diagnoseMissingImport(Loc, cast<NamedDecl>(TD),
D->getDefaultArgumentLoc(), Modules,
Sema::MissingImportKind::DefaultArgument,
- /*Recover*/ true);
+ /*Recover*/true);
return true;
}
@@ -4014,7 +4052,7 @@ namespace {
bool VisitTagDecl(const TagDecl *Tag);
bool VisitNestedNameSpecifier(NestedNameSpecifier *NNS);
};
-}
+} // end anonymous namespace
bool UnnamedLocalNoLinkageFinder::VisitBuiltinType(const BuiltinType*) {
return false;
@@ -4229,7 +4267,6 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}
-
/// \brief Check a template argument against its corresponding
/// template type parameter.
///
@@ -5340,10 +5377,11 @@ bool Sema::CheckTemplateArgument(TemplateTemplateParmDecl *Param,
// partial specializations.
if (!isa<ClassTemplateDecl>(Template) &&
!isa<TemplateTemplateParmDecl>(Template) &&
- !isa<TypeAliasTemplateDecl>(Template)) {
+ !isa<TypeAliasTemplateDecl>(Template) &&
+ !isa<BuiltinTemplateDecl>(Template)) {
assert(isa<FunctionTemplateDecl>(Template) &&
"Only function templates are possible here");
- Diag(Arg.getLocation(), diag::err_template_arg_not_class_template);
+ Diag(Arg.getLocation(), diag::err_template_arg_not_valid_template);
Diag(Template->getLocation(), diag::note_template_arg_refers_here_func)
<< Template;
}
@@ -6281,9 +6319,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
bool InstantiationDependent;
if (!Name.isDependent() &&
!TemplateSpecializationType::anyDependentTemplateArguments(
- TemplateArgs.getArgumentArray(),
- TemplateArgs.size(),
- InstantiationDependent)) {
+ TemplateArgs.arguments(), InstantiationDependent)) {
Diag(TemplateNameLoc, diag::err_partial_spec_fully_specialized)
<< ClassTemplate->getDeclName();
isPartialSpecialization = false;
@@ -6316,8 +6352,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
// arguments of the class template partial specialization.
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(CanonTemplate,
- Converted.data(),
- Converted.size());
+ Converted);
if (Context.hasSameType(CanonType,
ClassTemplate->getInjectedClassNameSpecialization())) {
@@ -6348,8 +6383,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
KWLoc, TemplateNameLoc,
TemplateParams,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
TemplateArgs,
CanonType,
PrevPartial);
@@ -6404,8 +6438,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
ClassTemplate->getDeclContext(),
KWLoc, TemplateNameLoc,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
PrevDecl);
SetNestedNameSpecifier(Specialization, SS);
if (TemplateParameterLists.size() > 0) {
@@ -6423,7 +6456,7 @@ Sema::ActOnClassTemplateSpecialization(Scope *S, unsigned TagSpec,
"Only possible with -fms-extensions!");
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
CanonType = Context.getTemplateSpecializationType(
- CanonTemplate, Converted.data(), Converted.size());
+ CanonTemplate, Converted);
} else {
CanonType = Context.getTypeDeclType(Specialization);
}
@@ -6879,12 +6912,13 @@ bool Sema::CheckFunctionTemplateSpecialization(
FunctionDecl *Specialization = nullptr;
if (TemplateDeductionResult TDK = DeduceTemplateArguments(
cast<FunctionTemplateDecl>(FunTmpl->getFirstDecl()),
- ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization, Info)) {
+ ExplicitTemplateArgs ? &Args : nullptr, FT, Specialization,
+ Info)) {
// Template argument deduction failed; record why it failed, so
// that we can provide nifty diagnostics.
- FailedCandidates.addCandidate()
- .set(FunTmpl->getTemplatedDecl(),
- MakeDeductionFailureInfo(Context, TDK, Info));
+ FailedCandidates.addCandidate().set(
+ I.getPair(), FunTmpl->getTemplatedDecl(),
+ MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
}
@@ -6911,6 +6945,15 @@ bool Sema::CheckFunctionTemplateSpecialization(
// Ignore access information; it doesn't figure into redeclaration checking.
FunctionDecl *Specialization = cast<FunctionDecl>(*Result);
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare [...]
+ // an explicit specialization (14.8.3) [...] of a concept definition.
+ if (Specialization->getPrimaryTemplate()->isConcept()) {
+ Diag(FD->getLocation(), diag::err_concept_specialized)
+ << 0 /*function*/ << 1 /*explicitly specialized*/;
+ Diag(Specialization->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
FunctionTemplateSpecializationInfo *SpecInfo
= Specialization->getTemplateSpecializationInfo();
assert(SpecInfo && "Function template specialization info missing?");
@@ -6960,6 +7003,21 @@ bool Sema::CheckFunctionTemplateSpecialization(
// Mark the prior declaration as an explicit specialization, so that later
// clients know that this is an explicit specialization.
if (!isFriend) {
+ // Since explicit specializations do not inherit '=delete' from their
+ // primary function template - check if the 'specialization' that was
+ // implicitly generated (during template argument deduction for partial
+ // ordering) from the most specialized of all the function templates that
+ // 'FD' could have been specializing, has a 'deleted' definition. If so,
+ // first check that it was implicitly generated during template argument
+ // deduction by making sure it wasn't referenced, and then reset the deleted
+ // flag to not-deleted, so that we can inherit that information from 'FD'.
+ if (Specialization->isDeleted() && !SpecInfo->isExplicitSpecialization() &&
+ !Specialization->getCanonicalDecl()->isReferenced()) {
+ assert(
+ Specialization->getCanonicalDecl() == Specialization &&
+ "This must be the only existing declaration of this specialization");
+ Specialization->setDeletedAsWritten(false);
+ }
SpecInfo->setTemplateSpecializationKind(TSK_ExplicitSpecialization);
MarkUnusedFileScopedDecl(Specialization);
}
@@ -7001,6 +7059,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
assert(!isa<TemplateDecl>(Member) && "Only for non-template members");
// Try to find the member we are instantiating.
+ NamedDecl *FoundInstantiation = nullptr;
NamedDecl *Instantiation = nullptr;
NamedDecl *InstantiatedFrom = nullptr;
MemberSpecializationInfo *MSInfo = nullptr;
@@ -7016,6 +7075,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
if (!hasExplicitCallingConv(Adjusted))
Adjusted = adjustCCAndNoReturn(Adjusted, Method->getType());
if (Context.hasSameType(Adjusted, Method->getType())) {
+ FoundInstantiation = *I;
Instantiation = Method;
InstantiatedFrom = Method->getInstantiatedFromMemberFunction();
MSInfo = Method->getMemberSpecializationInfo();
@@ -7028,6 +7088,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
if (Previous.isSingleResult() &&
(PrevVar = dyn_cast<VarDecl>(Previous.getFoundDecl())))
if (PrevVar->isStaticDataMember()) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevVar;
InstantiatedFrom = PrevVar->getInstantiatedFromStaticDataMember();
MSInfo = PrevVar->getMemberSpecializationInfo();
@@ -7036,6 +7097,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
CXXRecordDecl *PrevRecord;
if (Previous.isSingleResult() &&
(PrevRecord = dyn_cast<CXXRecordDecl>(Previous.getFoundDecl()))) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevRecord;
InstantiatedFrom = PrevRecord->getInstantiatedFromMemberClass();
MSInfo = PrevRecord->getMemberSpecializationInfo();
@@ -7044,6 +7106,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
EnumDecl *PrevEnum;
if (Previous.isSingleResult() &&
(PrevEnum = dyn_cast<EnumDecl>(Previous.getFoundDecl()))) {
+ FoundInstantiation = Previous.getRepresentativeDecl();
Instantiation = PrevEnum;
InstantiatedFrom = PrevEnum->getInstantiatedFromMemberEnum();
MSInfo = PrevEnum->getMemberSpecializationInfo();
@@ -7072,7 +7135,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
}
Previous.clear();
- Previous.addDecl(Instantiation);
+ Previous.addDecl(FoundInstantiation);
return false;
}
@@ -7119,6 +7182,13 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
InstantiationFunction->setTemplateSpecializationKind(
TSK_ExplicitSpecialization);
InstantiationFunction->setLocation(Member->getLocation());
+ // Explicit specializations of member functions of class templates do not
+ // inherit '=delete' from the member function they are specializing.
+ if (InstantiationFunction->isDeleted()) {
+ assert(InstantiationFunction->getCanonicalDecl() ==
+ InstantiationFunction);
+ InstantiationFunction->setDeletedAsWritten(false);
+ }
}
cast<FunctionDecl>(Member)->setInstantiationOfMemberFunction(
@@ -7166,7 +7236,7 @@ Sema::CheckMemberSpecialization(NamedDecl *Member, LookupResult &Previous) {
// Save the caller the trouble of having to figure out which declaration
// this specialization matches.
Previous.clear();
- Previous.addDecl(Instantiation);
+ Previous.addDecl(FoundInstantiation);
return false;
}
@@ -7268,15 +7338,21 @@ Sema::ActOnExplicitInstantiation(Scope *S,
assert(Kind != TTK_Enum &&
"Invalid enum tag in class template explicit instantiation!");
- if (isa<TypeAliasTemplateDecl>(TD)) {
- Diag(KWLoc, diag::err_tag_reference_non_tag) << Kind;
- Diag(TD->getTemplatedDecl()->getLocation(),
- diag::note_previous_use);
+ ClassTemplateDecl *ClassTemplate = dyn_cast<ClassTemplateDecl>(TD);
+
+ if (!ClassTemplate) {
+ unsigned ErrorKind = 0;
+ if (isa<TypeAliasTemplateDecl>(TD)) {
+ ErrorKind = 4;
+ } else if (isa<TemplateTemplateParmDecl>(TD)) {
+ ErrorKind = 5;
+ }
+
+ Diag(TemplateNameLoc, diag::err_tag_reference_non_tag) << ErrorKind;
+ Diag(TD->getLocation(), diag::note_previous_use);
return true;
}
- ClassTemplateDecl *ClassTemplate = cast<ClassTemplateDecl>(TD);
-
if (!isAcceptableTagRedeclaration(ClassTemplate->getTemplatedDecl(),
Kind, /*isDefinition*/false, KWLoc,
ClassTemplate->getIdentifier())) {
@@ -7315,6 +7391,29 @@ Sema::ActOnExplicitInstantiation(Scope *S,
}
}
+ // In MSVC mode, dllimported explicit instantiation definitions are treated as
+ // instantiation declarations for most purposes.
+ bool DLLImportExplicitInstantiationDef = false;
+ if (TSK == TSK_ExplicitInstantiationDefinition &&
+ Context.getTargetInfo().getCXXABI().isMicrosoft()) {
+ // Check for dllimport class template instantiation definitions.
+ bool DLLImport =
+ ClassTemplate->getTemplatedDecl()->getAttr<DLLImportAttr>();
+ for (AttributeList *A = Attr; A; A = A->getNext()) {
+ if (A->getKind() == AttributeList::AT_DLLImport)
+ DLLImport = true;
+ if (A->getKind() == AttributeList::AT_DLLExport) {
+ // dllexport trumps dllimport here.
+ DLLImport = false;
+ break;
+ }
+ }
+ if (DLLImport) {
+ TSK = TSK_ExplicitInstantiationDeclaration;
+ DLLImportExplicitInstantiationDef = true;
+ }
+ }
+
// Translate the parser's template argument list in our AST format.
TemplateArgumentListInfo TemplateArgs(LAngleLoc, RAngleLoc);
translateTemplateArguments(TemplateArgsIn, TemplateArgs);
@@ -7368,6 +7467,12 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->setLocation(TemplateNameLoc);
PrevDecl = nullptr;
}
+
+ if (PrevDecl_TSK == TSK_ExplicitInstantiationDeclaration &&
+ DLLImportExplicitInstantiationDef) {
+ // The new specialization might add a dllimport attribute.
+ HasNoEffect = false;
+ }
}
if (!Specialization) {
@@ -7378,8 +7483,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
ClassTemplate->getDeclContext(),
KWLoc, TemplateNameLoc,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
PrevDecl);
SetNestedNameSpecifier(Specialization, SS);
@@ -7405,7 +7509,7 @@ Sema::ActOnExplicitInstantiation(Scope *S,
// Set source locations for keywords.
Specialization->setExternLoc(ExternLoc);
Specialization->setTemplateKeywordLoc(TemplateLoc);
- Specialization->setRBraceLoc(SourceLocation());
+ Specialization->setBraceRange(SourceRange());
if (Attr)
ProcessDeclAttributeList(S, Specialization, Attr);
@@ -7445,11 +7549,11 @@ Sema::ActOnExplicitInstantiation(Scope *S,
Specialization->getDefinition());
if (Def) {
TemplateSpecializationKind Old_TSK = Def->getTemplateSpecializationKind();
-
// Fix a TSK_ExplicitInstantiationDeclaration followed by a
// TSK_ExplicitInstantiationDefinition
if (Old_TSK == TSK_ExplicitInstantiationDeclaration &&
- TSK == TSK_ExplicitInstantiationDefinition) {
+ (TSK == TSK_ExplicitInstantiationDefinition ||
+ DLLImportExplicitInstantiationDef)) {
// FIXME: Need to notify the ASTMutationListener that we did this.
Def->setTemplateSpecializationKind(TSK);
@@ -7462,7 +7566,13 @@ Sema::ActOnExplicitInstantiation(Scope *S,
getDLLAttr(Specialization)->clone(getASTContext()));
A->setInherited(true);
Def->addAttr(A);
+
+ // We reject explicit instantiations in class scope, so there should
+ // never be any delayed exported classes to worry about.
+ assert(DelayedDllExportClasses.empty() &&
+ "delayed exports present at explicit instantiation");
checkClassLevelDLLAttribute(Def);
+ referenceDLLExportedClassMethods();
// Propagate attribute to base class templates.
for (auto &B : Def->bases()) {
@@ -7673,6 +7783,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
Diag(D.getDeclSpec().getConstexprSpecLoc(),
diag::err_explicit_instantiation_constexpr);
+ // C++ Concepts TS [dcl.spec.concept]p1: The concept specifier shall be
+ // applied only to the definition of a function template or variable template,
+ // declared in namespace scope.
+ if (D.getDeclSpec().isConceptSpecified()) {
+ Diag(D.getDeclSpec().getConceptSpecLoc(),
+ diag::err_concept_specified_specialization) << 0;
+ return true;
+ }
+
// C++0x [temp.explicit]p2:
// There are two forms of explicit instantiation: an explicit instantiation
// definition and an explicit instantiation declaration. An explicit
@@ -7744,6 +7863,15 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
return true;
}
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
+ // explicit instantiation (14.8.2) [...] of a concept definition.
+ if (PrevTemplate->isConcept()) {
+ Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
+ << 1 /*variable*/ << 0 /*explicitly instantiated*/;
+ Diag(PrevTemplate->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
// Translate the parser's template argument list into our AST format.
TemplateArgumentListInfo TemplateArgs =
makeTemplateArgumentListInfo(*this, *D.getName().TemplateId);
@@ -7856,7 +7984,7 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
R, Specialization, Info)) {
// Keep track of almost-matches.
FailedCandidates.addCandidate()
- .set(FunTmpl->getTemplatedDecl(),
+ .set(P.getPair(), FunTmpl->getTemplatedDecl(),
MakeDeductionFailureInfo(Context, TDK, Info));
(void)TDK;
continue;
@@ -7958,6 +8086,16 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
diag::ext_explicit_instantiation_without_qualified_id)
<< Specialization << D.getCXXScopeSpec().getRange();
+ // C++ Concepts TS [dcl.spec.concept]p7: A program shall not declare an
+ // explicit instantiation (14.8.2) [...] of a concept definition.
+ if (FunTmpl && FunTmpl->isConcept() &&
+ !D.getDeclSpec().isConceptSpecified()) {
+ Diag(D.getIdentifierLoc(), diag::err_concept_specialized)
+ << 0 /*function*/ << 0 /*explicitly instantiated*/;
+ Diag(FunTmpl->getLocation(), diag::note_previous_declaration);
+ return true;
+ }
+
CheckExplicitInstantiationScope(*this,
FunTmpl? (NamedDecl *)FunTmpl
: Specialization->getInstantiatedFromMemberFunction(),
@@ -8294,7 +8432,7 @@ namespace {
return E;
}
};
-}
+} // end anonymous namespace
/// \brief Rebuilds a type within the context of the current instantiation.
///
@@ -8469,3 +8607,149 @@ bool Sema::IsInsideALocalClassWithinATemplateFunction() {
}
return false;
}
+
+/// \brief Walk the path from which a declaration was instantiated, and check
+/// that every explicit specialization along that path is visible. This enforces
+/// C++ [temp.expl.spec]/6:
+///
+/// If a template, a member template or a member of a class template is
+/// explicitly specialized then that specialization shall be declared before
+/// the first use of that specialization that would cause an implicit
+/// instantiation to take place, in every translation unit in which such a
+/// use occurs; no diagnostic is required.
+///
+/// and also C++ [temp.class.spec]/1:
+///
+/// A partial specialization shall be declared before the first use of a
+/// class template specialization that would make use of the partial
+/// specialization as the result of an implicit or explicit instantiation
+/// in every translation unit in which such a use occurs; no diagnostic is
+/// required.
+class ExplicitSpecializationVisibilityChecker {
+ Sema &S;
+ SourceLocation Loc;
+ llvm::SmallVector<Module *, 8> Modules;
+
+public:
+ ExplicitSpecializationVisibilityChecker(Sema &S, SourceLocation Loc)
+ : S(S), Loc(Loc) {}
+
+ void check(NamedDecl *ND) {
+ if (auto *FD = dyn_cast<FunctionDecl>(ND))
+ return checkImpl(FD);
+ if (auto *RD = dyn_cast<CXXRecordDecl>(ND))
+ return checkImpl(RD);
+ if (auto *VD = dyn_cast<VarDecl>(ND))
+ return checkImpl(VD);
+ if (auto *ED = dyn_cast<EnumDecl>(ND))
+ return checkImpl(ED);
+ }
+
+private:
+ void diagnose(NamedDecl *D, bool IsPartialSpec) {
+ auto Kind = IsPartialSpec ? Sema::MissingImportKind::PartialSpecialization
+ : Sema::MissingImportKind::ExplicitSpecialization;
+ const bool Recover = true;
+
+ // If we got a custom set of modules (because only a subset of the
+ // declarations are interesting), use them, otherwise let
+ // diagnoseMissingImport intelligently pick some.
+ if (Modules.empty())
+ S.diagnoseMissingImport(Loc, D, Kind, Recover);
+ else
+ S.diagnoseMissingImport(Loc, D, D->getLocation(), Modules, Kind, Recover);
+ }
+
+ // Check a specific declaration. There are three problematic cases:
+ //
+ // 1) The declaration is an explicit specialization of a template
+ // specialization.
+ // 2) The declaration is an explicit specialization of a member of an
+ // templated class.
+ // 3) The declaration is an instantiation of a template, and that template
+ // is an explicit specialization of a member of a templated class.
+ //
+ // We don't need to go any deeper than that, as the instantiation of the
+ // surrounding class / etc is not triggered by whatever triggered this
+ // instantiation, and thus should be checked elsewhere.
+ template<typename SpecDecl>
+ void checkImpl(SpecDecl *Spec) {
+ bool IsHiddenExplicitSpecialization = false;
+ if (Spec->getTemplateSpecializationKind() == TSK_ExplicitSpecialization) {
+ IsHiddenExplicitSpecialization =
+ Spec->getMemberSpecializationInfo()
+ ? !S.hasVisibleMemberSpecialization(Spec, &Modules)
+ : !S.hasVisibleDeclaration(Spec);
+ } else {
+ checkInstantiated(Spec);
+ }
+
+ if (IsHiddenExplicitSpecialization)
+ diagnose(Spec->getMostRecentDecl(), false);
+ }
+
+ void checkInstantiated(FunctionDecl *FD) {
+ if (auto *TD = FD->getPrimaryTemplate())
+ checkTemplate(TD);
+ }
+
+ void checkInstantiated(CXXRecordDecl *RD) {
+ auto *SD = dyn_cast<ClassTemplateSpecializationDecl>(RD);
+ if (!SD)
+ return;
+
+ auto From = SD->getSpecializedTemplateOrPartial();
+ if (auto *TD = From.dyn_cast<ClassTemplateDecl *>())
+ checkTemplate(TD);
+ else if (auto *TD =
+ From.dyn_cast<ClassTemplatePartialSpecializationDecl *>()) {
+ if (!S.hasVisibleDeclaration(TD))
+ diagnose(TD, true);
+ checkTemplate(TD);
+ }
+ }
+
+ void checkInstantiated(VarDecl *RD) {
+ auto *SD = dyn_cast<VarTemplateSpecializationDecl>(RD);
+ if (!SD)
+ return;
+
+ auto From = SD->getSpecializedTemplateOrPartial();
+ if (auto *TD = From.dyn_cast<VarTemplateDecl *>())
+ checkTemplate(TD);
+ else if (auto *TD =
+ From.dyn_cast<VarTemplatePartialSpecializationDecl *>()) {
+ if (!S.hasVisibleDeclaration(TD))
+ diagnose(TD, true);
+ checkTemplate(TD);
+ }
+ }
+
+ void checkInstantiated(EnumDecl *FD) {}
+
+ template<typename TemplDecl>
+ void checkTemplate(TemplDecl *TD) {
+ if (TD->isMemberSpecialization()) {
+ if (!S.hasVisibleMemberSpecialization(TD, &Modules))
+ diagnose(TD->getMostRecentDecl(), false);
+ }
+ }
+};
+
+void Sema::checkSpecializationVisibility(SourceLocation Loc, NamedDecl *Spec) {
+ if (!getLangOpts().Modules)
+ return;
+
+ ExplicitSpecializationVisibilityChecker(*this, Loc).check(Spec);
+}
+
+/// \brief Check whether a template partial specialization that we've discovered
+/// is hidden, and produce suitable diagnostics if so.
+void Sema::checkPartialSpecializationVisibility(SourceLocation Loc,
+ NamedDecl *Spec) {
+ llvm::SmallVector<Module *, 8> Modules;
+ if (!hasVisibleDeclaration(Spec, &Modules))
+ diagnoseMissingImport(Loc, Spec, Spec->getLocation(), Modules,
+ MissingImportKind::PartialSpecialization,
+ /*Recover*/true);
+}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
index 71faafc6bc12..5740bc712e86 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -103,12 +103,12 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
bool PartialOrdering = false);
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
+DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced);
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool NumberOfArgumentsMustMatch);
/// \brief If the given expression is of a form that permits the deduction
/// of a non-type template parameter, return the declaration of that
@@ -286,13 +286,10 @@ checkDeducedTemplateArguments(ASTContext &Context,
/// \brief Deduce the value of the given non-type template parameter
/// from the given constant.
-static Sema::TemplateDeductionResult
-DeduceNonTypeTemplateArgument(Sema &S,
- NonTypeTemplateParmDecl *NTTP,
- llvm::APSInt Value, QualType ValueType,
- bool DeducedFromArrayBound,
- TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+static Sema::TemplateDeductionResult DeduceNonTypeTemplateArgument(
+ Sema &S, NonTypeTemplateParmDecl *NTTP, const llvm::APSInt &Value,
+ QualType ValueType, bool DeducedFromArrayBound, TemplateDeductionInfo &Info,
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
assert(NTTP->getDepth() == 0 &&
"Cannot deduce non-type template argument with depth > 0");
@@ -456,10 +453,10 @@ DeduceTemplateArguments(Sema &S,
// Perform template argument deduction on each template
// argument. Ignore any missing/extra arguments, since they could be
// filled in by default arguments.
- return DeduceTemplateArguments(S, TemplateParams,
- Param->getArgs(), Param->getNumArgs(),
- SpecArg->getArgs(), SpecArg->getNumArgs(),
- Info, Deduced);
+ return DeduceTemplateArguments(S, TemplateParams, Param->getArgs(),
+ Param->getNumArgs(), SpecArg->getArgs(),
+ SpecArg->getNumArgs(), Info, Deduced,
+ /*NumberOfArgumentsMustMatch=*/false);
}
// If the argument type is a class template specialization, we
@@ -490,11 +487,10 @@ DeduceTemplateArguments(Sema &S,
return Result;
// Perform template argument deduction for the template arguments.
- return DeduceTemplateArguments(S, TemplateParams,
- Param->getArgs(), Param->getNumArgs(),
- SpecArg->getTemplateArgs().data(),
- SpecArg->getTemplateArgs().size(),
- Info, Deduced);
+ return DeduceTemplateArguments(
+ S, TemplateParams, Param->getArgs(), Param->getNumArgs(),
+ SpecArg->getTemplateArgs().data(), SpecArg->getTemplateArgs().size(),
+ Info, Deduced, /*NumberOfArgumentsMustMatch=*/true);
}
/// \brief Determines whether the given type is an opaque type that
@@ -1418,85 +1414,101 @@ DeduceTemplateArgumentsByTypeMatch(Sema &S,
// TT<i>
// TT<>
case Type::TemplateSpecialization: {
- const TemplateSpecializationType *SpecParam
- = cast<TemplateSpecializationType>(Param);
-
- // Try to deduce template arguments from the template-id.
- Sema::TemplateDeductionResult Result
- = DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg,
- Info, Deduced);
-
- if (Result && (TDF & TDF_DerivedClass)) {
- // C++ [temp.deduct.call]p3b3:
- // If P is a class, and P has the form template-id, then A can be a
- // derived class of the deduced A. Likewise, if P is a pointer to a
- // class of the form template-id, A can be a pointer to a derived
- // class pointed to by the deduced A.
- //
- // More importantly:
- // These alternatives are considered only if type deduction would
- // otherwise fail.
- if (const RecordType *RecordT = Arg->getAs<RecordType>()) {
- // We cannot inspect base classes as part of deduction when the type
- // is incomplete, so either instantiate any templates necessary to
- // complete the type, or skip over it if it cannot be completed.
- if (!S.isCompleteType(Info.getLocation(), Arg))
- return Result;
-
- // Use data recursion to crawl through the list of base classes.
- // Visited contains the set of nodes we have already visited, while
- // ToVisit is our stack of records that we still need to visit.
- llvm::SmallPtrSet<const RecordType *, 8> Visited;
- SmallVector<const RecordType *, 8> ToVisit;
- ToVisit.push_back(RecordT);
- bool Successful = false;
- SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
- Deduced.end());
- while (!ToVisit.empty()) {
- // Retrieve the next class in the inheritance hierarchy.
- const RecordType *NextT = ToVisit.pop_back_val();
-
- // If we have already seen this type, skip it.
- if (!Visited.insert(NextT).second)
- continue;
-
- // If this is a base class, try to perform template argument
- // deduction from it.
- if (NextT != RecordT) {
- TemplateDeductionInfo BaseInfo(Info.getLocation());
- Sema::TemplateDeductionResult BaseResult
- = DeduceTemplateArguments(S, TemplateParams, SpecParam,
- QualType(NextT, 0), BaseInfo,
- Deduced);
-
- // If template argument deduction for this base was successful,
- // note that we had some success. Otherwise, ignore any deductions
- // from this base class.
- if (BaseResult == Sema::TDK_Success) {
- Successful = true;
- DeducedOrig.clear();
- DeducedOrig.append(Deduced.begin(), Deduced.end());
- Info.Param = BaseInfo.Param;
- Info.FirstArg = BaseInfo.FirstArg;
- Info.SecondArg = BaseInfo.SecondArg;
- }
- else
- Deduced = DeducedOrig;
- }
-
- // Visit base classes
- CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
- for (const auto &Base : Next->bases()) {
- assert(Base.getType()->isRecordType() &&
- "Base class that isn't a record?");
- ToVisit.push_back(Base.getType()->getAs<RecordType>());
- }
+ const TemplateSpecializationType *SpecParam =
+ cast<TemplateSpecializationType>(Param);
+
+ // When Arg cannot be a derived class, we can just try to deduce template
+ // arguments from the template-id.
+ const RecordType *RecordT = Arg->getAs<RecordType>();
+ if (!(TDF & TDF_DerivedClass) || !RecordT)
+ return DeduceTemplateArguments(S, TemplateParams, SpecParam, Arg, Info,
+ Deduced);
+
+ SmallVector<DeducedTemplateArgument, 8> DeducedOrig(Deduced.begin(),
+ Deduced.end());
+
+ Sema::TemplateDeductionResult Result = DeduceTemplateArguments(
+ S, TemplateParams, SpecParam, Arg, Info, Deduced);
+
+ if (Result == Sema::TDK_Success)
+ return Result;
+
+ // We cannot inspect base classes as part of deduction when the type
+ // is incomplete, so either instantiate any templates necessary to
+ // complete the type, or skip over it if it cannot be completed.
+ if (!S.isCompleteType(Info.getLocation(), Arg))
+ return Result;
+
+ // C++14 [temp.deduct.call] p4b3:
+ // If P is a class and P has the form simple-template-id, then the
+ // transformed A can be a derived class of the deduced A. Likewise if
+ // P is a pointer to a class of the form simple-template-id, the
+ // transformed A can be a pointer to a derived class pointed to by the
+ // deduced A.
+ //
+ // These alternatives are considered only if type deduction would
+ // otherwise fail. If they yield more than one possible deduced A, the
+ // type deduction fails.
+
+ // Reset the incorrectly deduced argument from above.
+ Deduced = DeducedOrig;
+
+ // Use data recursion to crawl through the list of base classes.
+ // Visited contains the set of nodes we have already visited, while
+ // ToVisit is our stack of records that we still need to visit.
+ llvm::SmallPtrSet<const RecordType *, 8> Visited;
+ SmallVector<const RecordType *, 8> ToVisit;
+ ToVisit.push_back(RecordT);
+ bool Successful = false;
+ SmallVector<DeducedTemplateArgument, 8> SuccessfulDeduced;
+ while (!ToVisit.empty()) {
+ // Retrieve the next class in the inheritance hierarchy.
+ const RecordType *NextT = ToVisit.pop_back_val();
+
+ // If we have already seen this type, skip it.
+ if (!Visited.insert(NextT).second)
+ continue;
+
+ // If this is a base class, try to perform template argument
+ // deduction from it.
+ if (NextT != RecordT) {
+ TemplateDeductionInfo BaseInfo(Info.getLocation());
+ Sema::TemplateDeductionResult BaseResult =
+ DeduceTemplateArguments(S, TemplateParams, SpecParam,
+ QualType(NextT, 0), BaseInfo, Deduced);
+
+ // If template argument deduction for this base was successful,
+ // note that we had some success. Otherwise, ignore any deductions
+ // from this base class.
+ if (BaseResult == Sema::TDK_Success) {
+ // If we've already seen some success, then deduction fails due to
+ // an ambiguity (temp.deduct.call p5).
+ if (Successful)
+ return Sema::TDK_MiscellaneousDeductionFailure;
+
+ Successful = true;
+ std::swap(SuccessfulDeduced, Deduced);
+
+ Info.Param = BaseInfo.Param;
+ Info.FirstArg = BaseInfo.FirstArg;
+ Info.SecondArg = BaseInfo.SecondArg;
}
- if (Successful)
- return Sema::TDK_Success;
+ Deduced = DeducedOrig;
}
+ // Visit base classes
+ CXXRecordDecl *Next = cast<CXXRecordDecl>(NextT->getDecl());
+ for (const auto &Base : Next->bases()) {
+ assert(Base.getType()->isRecordType() &&
+ "Base class that isn't a record?");
+ ToVisit.push_back(Base.getType()->getAs<RecordType>());
+ }
+ }
+
+ if (Successful) {
+ std::swap(SuccessfulDeduced, Deduced);
+ return Sema::TDK_Success;
}
return Result;
@@ -1821,12 +1833,12 @@ static bool hasPackExpansionBeforeEnd(const TemplateArgument *Args,
}
static Sema::TemplateDeductionResult
-DeduceTemplateArguments(Sema &S,
- TemplateParameterList *TemplateParams,
+DeduceTemplateArguments(Sema &S, TemplateParameterList *TemplateParams,
const TemplateArgument *Params, unsigned NumParams,
const TemplateArgument *Args, unsigned NumArgs,
TemplateDeductionInfo &Info,
- SmallVectorImpl<DeducedTemplateArgument> &Deduced) {
+ SmallVectorImpl<DeducedTemplateArgument> &Deduced,
+ bool NumberOfArgumentsMustMatch) {
// C++0x [temp.deduct.type]p9:
// If the template argument list of P contains a pack expansion that is not
// the last template argument, the entire template argument list is a
@@ -1846,7 +1858,8 @@ DeduceTemplateArguments(Sema &S,
// Check whether we have enough arguments.
if (!hasTemplateArgumentForDeduction(Args, ArgIdx, NumArgs))
- return Sema::TDK_Success;
+ return NumberOfArgumentsMustMatch ? Sema::TDK_TooFewArguments
+ : Sema::TDK_Success;
if (Args[ArgIdx].isPackExpansion()) {
// FIXME: We follow the logic of C++0x [temp.deduct.type]p22 here,
@@ -1917,7 +1930,7 @@ DeduceTemplateArguments(Sema &S,
return DeduceTemplateArguments(S, TemplateParams,
ParamList.data(), ParamList.size(),
ArgList.data(), ArgList.size(),
- Info, Deduced);
+ Info, Deduced, false);
}
/// \brief Determine whether two template arguments are the same.
@@ -2060,11 +2073,45 @@ static bool
ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
DeducedTemplateArgument Arg,
NamedDecl *Template,
- QualType NTTPType,
- unsigned ArgumentPackIndex,
TemplateDeductionInfo &Info,
bool InFunctionTemplate,
SmallVectorImpl<TemplateArgument> &Output) {
+ // First, for a non-type template parameter type that is
+ // initialized by a declaration, we need the type of the
+ // corresponding non-type template parameter.
+ QualType NTTPType;
+ if (NonTypeTemplateParmDecl *NTTP =
+ dyn_cast<NonTypeTemplateParmDecl>(Param)) {
+ NTTPType = NTTP->getType();
+ if (NTTPType->isDependentType()) {
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
+ NTTPType = S.SubstType(NTTPType,
+ MultiLevelTemplateArgumentList(TemplateArgs),
+ NTTP->getLocation(),
+ NTTP->getDeclName());
+ if (NTTPType.isNull())
+ return true;
+ }
+ }
+
+ auto ConvertArg = [&](DeducedTemplateArgument Arg,
+ unsigned ArgumentPackIndex) {
+ // Convert the deduced template argument into a template
+ // argument that we can check, almost as if the user had written
+ // the template argument explicitly.
+ TemplateArgumentLoc ArgLoc =
+ getTrivialTemplateArgumentLoc(S, Arg, NTTPType, Info.getLocation());
+
+ // Check the template argument, converting it as necessary.
+ return S.CheckTemplateArgument(
+ Param, ArgLoc, Template, Template->getLocation(),
+ Template->getSourceRange().getEnd(), ArgumentPackIndex, Output,
+ InFunctionTemplate
+ ? (Arg.wasDeducedFromArrayBound() ? Sema::CTAK_DeducedFromArrayBound
+ : Sema::CTAK_Deduced)
+ : Sema::CTAK_Specified);
+ };
+
if (Arg.getKind() == TemplateArgument::Pack) {
// This is a template argument pack, so check each of its arguments against
// the template parameter.
@@ -2075,39 +2122,41 @@ ConvertDeducedTemplateArgument(Sema &S, NamedDecl *Param,
// checking logic has all of the prior template arguments available.
DeducedTemplateArgument InnerArg(P);
InnerArg.setDeducedFromArrayBound(Arg.wasDeducedFromArrayBound());
- if (ConvertDeducedTemplateArgument(S, Param, InnerArg, Template,
- NTTPType, PackedArgsBuilder.size(),
- Info, InFunctionTemplate, Output))
+ assert(InnerArg.getKind() != TemplateArgument::Pack &&
+ "deduced nested pack");
+ if (ConvertArg(InnerArg, PackedArgsBuilder.size()))
return true;
// Move the converted template argument into our argument pack.
PackedArgsBuilder.push_back(Output.pop_back_val());
}
+ // If the pack is empty, we still need to substitute into the parameter
+ // itself, in case that substitution fails. For non-type parameters, we did
+ // this above. For type parameters, no substitution is ever required.
+ auto *TTP = dyn_cast<TemplateTemplateParmDecl>(Param);
+ if (TTP && PackedArgsBuilder.empty()) {
+ // Set up a template instantiation context.
+ LocalInstantiationScope Scope(S);
+ Sema::InstantiatingTemplate Inst(S, Template->getLocation(), Template,
+ TTP, Output,
+ Template->getSourceRange());
+ if (Inst.isInvalid())
+ return true;
+
+ TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack, Output);
+ if (!S.SubstDecl(TTP, S.CurContext,
+ MultiLevelTemplateArgumentList(TemplateArgs)))
+ return true;
+ }
+
// Create the resulting argument pack.
Output.push_back(
TemplateArgument::CreatePackCopy(S.Context, PackedArgsBuilder));
return false;
}
- // Convert the deduced template argument into a template
- // argument that we can check, almost as if the user had written
- // the template argument explicitly.
- TemplateArgumentLoc ArgLoc = getTrivialTemplateArgumentLoc(S, Arg, NTTPType,
- Info.getLocation());
-
- // Check the template argument, converting it as necessary.
- return S.CheckTemplateArgument(Param, ArgLoc,
- Template,
- Template->getLocation(),
- Template->getSourceRange().getEnd(),
- ArgumentPackIndex,
- Output,
- InFunctionTemplate
- ? (Arg.wasDeducedFromArrayBound()
- ? Sema::CTAK_DeducedFromArrayBound
- : Sema::CTAK_Deduced)
- : Sema::CTAK_Specified);
+ return ConvertArg(Arg, 0);
}
/// Complete template argument deduction for a class template partial
@@ -2138,47 +2187,19 @@ FinishTemplateArgumentDeduction(Sema &S,
// We have deduced this argument, so it still needs to be
// checked and converted.
-
- // First, for a non-type template parameter type that is
- // initialized by a declaration, we need the type of the
- // corresponding non-type template parameter.
- QualType NTTPType;
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- NTTPType = NTTP->getType();
- if (NTTPType->isDependentType()) {
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Builder.data(), Builder.size());
- NTTPType = S.SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
- NTTP->getDeclName());
- if (NTTPType.isNull()) {
- Info.Param = makeTemplateParameter(Param);
- // FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context,
- Builder.data(),
- Builder.size()));
- return Sema::TDK_SubstitutionFailure;
- }
- }
- }
-
if (ConvertDeducedTemplateArgument(S, Param, Deduced[I],
- Partial, NTTPType, 0, Info, false,
+ Partial, Info, false,
Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
- Builder.size()));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
- Builder.size());
+ = TemplateArgumentList::CreateCopy(S.Context, Builder);
Info.reset(DeducedArgumentList);
@@ -2306,43 +2327,18 @@ static Sema::TemplateDeductionResult FinishTemplateArgumentDeduction(
// We have deduced this argument, so it still needs to be
// checked and converted.
-
- // First, for a non-type template parameter type that is
- // initialized by a declaration, we need the type of the
- // corresponding non-type template parameter.
- QualType NTTPType;
- if (NonTypeTemplateParmDecl *NTTP =
- dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- NTTPType = NTTP->getType();
- if (NTTPType->isDependentType()) {
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Builder.data(), Builder.size());
- NTTPType =
- S.SubstType(NTTPType, MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(), NTTP->getDeclName());
- if (NTTPType.isNull()) {
- Info.Param = makeTemplateParameter(Param);
- // FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
- Builder.size()));
- return Sema::TDK_SubstitutionFailure;
- }
- }
- }
-
- if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial, NTTPType,
- 0, Info, false, Builder)) {
+ if (ConvertDeducedTemplateArgument(S, Param, Deduced[I], Partial,
+ Info, false, Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder.data(),
- Builder.size()));
+ Info.reset(TemplateArgumentList::CreateCopy(S.Context, Builder));
return Sema::TDK_SubstitutionFailure;
}
}
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList = TemplateArgumentList::CreateCopy(
- S.Context, Builder.data(), Builder.size());
+ S.Context, Builder);
Info.reset(DeducedArgumentList);
@@ -2488,7 +2484,7 @@ Sema::SubstituteExplicitTemplateArguments(
if (ExplicitTemplateArgs.size() == 0) {
// No arguments to substitute; just copy over the parameter types and
// fill in the function type.
- for (auto P : Function->params())
+ for (auto P : Function->parameters())
ParamTypes.push_back(P->getType());
if (FunctionType)
@@ -2533,7 +2529,7 @@ Sema::SubstituteExplicitTemplateArguments(
// Form the template argument list from the explicitly-specified
// template arguments.
TemplateArgumentList *ExplicitArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size());
+ = TemplateArgumentList::CreateCopy(Context, Builder);
Info.reset(ExplicitArgumentList);
// Template argument deduction and the final substitution should be
@@ -2564,15 +2560,17 @@ Sema::SubstituteExplicitTemplateArguments(
// Isolate our substituted parameters from our caller.
LocalInstantiationScope InstScope(*this, /*MergeWithOuterScope*/true);
+ ExtParameterInfoBuilder ExtParamInfos;
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments. If the function has a trailing
// return type, substitute it after the arguments to ensure we substitute
// in lexical order.
if (Proto->hasTrailingReturn()) {
- if (SubstParmTypes(Function->getLocation(),
- Function->param_begin(), Function->getNumParams(),
+ if (SubstParmTypes(Function->getLocation(), Function->parameters(),
+ Proto->getExtParameterInfosOrNull(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes))
+ ParamTypes, /*params*/ nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
}
@@ -2602,21 +2600,23 @@ Sema::SubstituteExplicitTemplateArguments(
if (ResultType.isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
-
+
// Instantiate the types of each of the function parameters given the
// explicitly-specified template arguments if we didn't do so earlier.
if (!Proto->hasTrailingReturn() &&
- SubstParmTypes(Function->getLocation(),
- Function->param_begin(), Function->getNumParams(),
+ SubstParmTypes(Function->getLocation(), Function->parameters(),
+ Proto->getExtParameterInfosOrNull(),
MultiLevelTemplateArgumentList(*ExplicitArgumentList),
- ParamTypes))
+ ParamTypes, /*params*/ nullptr, ExtParamInfos))
return TDK_SubstitutionFailure;
if (FunctionType) {
+ auto EPI = Proto->getExtProtoInfo();
+ EPI.ExtParameterInfos = ExtParamInfos.getPointerOrNull(ParamTypes.size());
*FunctionType = BuildFunctionType(ResultType, ParamTypes,
Function->getLocation(),
Function->getDeclName(),
- Proto->getExtProtoInfo());
+ EPI);
if (FunctionType->isNull() || Trap.hasErrorOccurred())
return TDK_SubstitutionFailure;
}
@@ -2804,41 +2804,15 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
}
continue;
}
+
// We have deduced this argument, so it still needs to be
// checked and converted.
-
- // First, for a non-type template parameter type that is
- // initialized by a declaration, we need the type of the
- // corresponding non-type template parameter.
- QualType NTTPType;
- if (NonTypeTemplateParmDecl *NTTP
- = dyn_cast<NonTypeTemplateParmDecl>(Param)) {
- NTTPType = NTTP->getType();
- if (NTTPType->isDependentType()) {
- TemplateArgumentList TemplateArgs(TemplateArgumentList::OnStack,
- Builder.data(), Builder.size());
- NTTPType = SubstType(NTTPType,
- MultiLevelTemplateArgumentList(TemplateArgs),
- NTTP->getLocation(),
- NTTP->getDeclName());
- if (NTTPType.isNull()) {
- Info.Param = makeTemplateParameter(Param);
- // FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(Context,
- Builder.data(),
- Builder.size()));
- return TDK_SubstitutionFailure;
- }
- }
- }
-
if (ConvertDeducedTemplateArgument(*this, Param, Deduced[I],
- FunctionTemplate, NTTPType, 0, Info,
+ FunctionTemplate, Info,
true, Builder)) {
Info.Param = makeTemplateParameter(Param);
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
- Builder.size()));
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
return TDK_SubstitutionFailure;
}
@@ -2862,11 +2836,21 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
Builder.push_back(TemplateArgument(
llvm::makeArrayRef(ExplicitArgs, NumExplicitArgs)));
- // Forget the partially-substituted pack; it's substitution is now
+ // Forget the partially-substituted pack; its substitution is now
// complete.
CurrentInstantiationScope->ResetPartiallySubstitutedPack();
} else {
- Builder.push_back(TemplateArgument::getEmptyPack());
+ // Go through the motions of checking the empty argument pack against
+ // the parameter pack.
+ DeducedTemplateArgument DeducedPack(TemplateArgument::getEmptyPack());
+ if (ConvertDeducedTemplateArgument(*this, Param, DeducedPack,
+ FunctionTemplate, Info, true,
+ Builder)) {
+ Info.Param = makeTemplateParameter(Param);
+ // FIXME: These template arguments are temporary. Free them!
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
+ return TDK_SubstitutionFailure;
+ }
}
continue;
}
@@ -2884,8 +2868,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
if (DefArg.getArgument().isNull()) {
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
- Builder.size()));
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
if (PartialOverloading) break;
return HasDefaultArg ? TDK_SubstitutionFailure : TDK_Incomplete;
@@ -2901,8 +2884,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
Info.Param = makeTemplateParameter(
const_cast<NamedDecl *>(TemplateParams->getParam(I)));
// FIXME: These template arguments are temporary. Free them!
- Info.reset(TemplateArgumentList::CreateCopy(Context, Builder.data(),
- Builder.size()));
+ Info.reset(TemplateArgumentList::CreateCopy(Context, Builder));
return TDK_SubstitutionFailure;
}
@@ -2911,7 +2893,7 @@ Sema::FinishTemplateArgumentDeduction(FunctionTemplateDecl *FunctionTemplate,
// Form the template argument list from the deduced template arguments.
TemplateArgumentList *DeducedArgumentList
- = TemplateArgumentList::CreateCopy(Context, Builder.data(), Builder.size());
+ = TemplateArgumentList::CreateCopy(Context, Builder);
Info.reset(DeducedArgumentList);
// Substitute the deduced template arguments into the function template
@@ -3036,6 +3018,11 @@ ResolveOverloadForDeduction(Sema &S, TemplateParameterList *TemplateParams,
return GetTypeOfFunction(S, R, ExplicitSpec);
}
+ DeclAccessPair DAP;
+ if (FunctionDecl *Viable =
+ S.resolveAddressOfOnlyViableOverloadCandidate(Arg, DAP))
+ return GetTypeOfFunction(S, R, Viable);
+
return QualType();
}
@@ -4609,11 +4596,9 @@ Sema::getMoreSpecializedPartialSpecialization(
TemplateName Name(PS1->getSpecializedTemplate());
TemplateName CanonTemplate = Context.getCanonicalTemplateName(Name);
QualType PT1 = Context.getTemplateSpecializationType(
- CanonTemplate, PS1->getTemplateArgs().data(),
- PS1->getTemplateArgs().size());
+ CanonTemplate, PS1->getTemplateArgs().asArray());
QualType PT2 = Context.getTemplateSpecializationType(
- CanonTemplate, PS2->getTemplateArgs().data(),
- PS2->getTemplateArgs().size());
+ CanonTemplate, PS2->getTemplateArgs().asArray());
// Determine whether PS1 is at least as specialized as PS2
Deduced.resize(PS2->getTemplateParameters()->size());
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
index fb7fc109d2e9..48c6a506ee36 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiate.cpp
@@ -21,6 +21,7 @@
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/Initialization.h"
#include "clang/Sema/Lookup.h"
+#include "clang/Sema/PrettyDeclStackTrace.h"
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
@@ -446,10 +447,8 @@ void Sema::PrintInstantiationStack() {
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
Template->printName(OS);
- TemplateSpecializationType::PrintTemplateArgumentList(OS,
- Active->TemplateArgs,
- Active->NumTemplateArgs,
- getPrintingPolicy());
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Active->template_arguments(), getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_arg_instantiation_here)
<< OS.str()
@@ -500,10 +499,8 @@ void Sema::PrintInstantiationStack() {
SmallVector<char, 128> TemplateArgsStr;
llvm::raw_svector_ostream OS(TemplateArgsStr);
FD->printName(OS);
- TemplateSpecializationType::PrintTemplateArgumentList(OS,
- Active->TemplateArgs,
- Active->NumTemplateArgs,
- getPrintingPolicy());
+ TemplateSpecializationType::PrintTemplateArgumentList(
+ OS, Active->template_arguments(), getPrintingPolicy());
Diags.Report(Active->PointOfInstantiation,
diag::note_default_function_arg_instantiation_here)
<< OS.str()
@@ -729,6 +726,11 @@ namespace {
}
SemaRef.CurrentInstantiationScope->InstantiatedLocal(Old, New);
+
+ // We recreated a local declaration, but not by instantiating it. There
+ // may be pending dependent diagnostics to produce.
+ if (auto *DC = dyn_cast<DeclContext>(Old))
+ SemaRef.PerformDependentDiagnostics(DC, TemplateArgs);
}
/// \brief Transform the definition of the given declaration by
@@ -1512,7 +1514,7 @@ QualType Sema::SubstType(QualType T,
}
static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
- if (T->getType()->isInstantiationDependentType() ||
+ if (T->getType()->isInstantiationDependentType() ||
T->getType()->isVariablyModifiedType())
return true;
@@ -1521,23 +1523,13 @@ static bool NeedsInstantiationAsFunctionType(TypeSourceInfo *T) {
return false;
FunctionProtoTypeLoc FP = TL.castAs<FunctionProtoTypeLoc>();
- for (unsigned I = 0, E = FP.getNumParams(); I != E; ++I) {
- ParmVarDecl *P = FP.getParam(I);
-
+ for (ParmVarDecl *P : FP.getParams()) {
// This must be synthesized from a typedef.
if (!P) continue;
- // The parameter's type as written might be dependent even if the
- // decayed type was not dependent.
- if (TypeSourceInfo *TSInfo = P->getTypeSourceInfo())
- if (TSInfo->getType()->isInstantiationDependentType())
- return true;
-
- // TODO: currently we always rebuild expressions. When we
- // properly get lazier about this, we should use the same
- // logic to avoid rebuilding prototypes here.
- if (P->hasDefaultArg())
- return true;
+ // If there are any parameters, a new TypeSourceInfo that refers to the
+ // instantiated parameters must be built.
+ return true;
}
return false;
@@ -1556,7 +1548,7 @@ TypeSourceInfo *Sema::SubstFunctionDeclType(TypeSourceInfo *T,
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
-
+
if (!NeedsInstantiationAsFunctionType(T))
return T;
@@ -1718,20 +1710,21 @@ ParmVarDecl *Sema::SubstParmVarDecl(ParmVarDecl *OldParm,
/// \brief Substitute the given template arguments into the given set of
/// parameters, producing the set of parameter types that would be generated
/// from such a substitution.
-bool Sema::SubstParmTypes(SourceLocation Loc,
- ParmVarDecl **Params, unsigned NumParams,
- const MultiLevelTemplateArgumentList &TemplateArgs,
- SmallVectorImpl<QualType> &ParamTypes,
- SmallVectorImpl<ParmVarDecl *> *OutParams) {
+bool Sema::SubstParmTypes(
+ SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
+ const FunctionProtoType::ExtParameterInfo *ExtParamInfos,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ SmallVectorImpl<QualType> &ParamTypes,
+ SmallVectorImpl<ParmVarDecl *> *OutParams,
+ ExtParameterInfoBuilder &ParamInfos) {
assert(!ActiveTemplateInstantiations.empty() &&
"Cannot perform an instantiation without some context on the "
"instantiation stack");
TemplateInstantiator Instantiator(*this, TemplateArgs, Loc,
DeclarationName());
- return Instantiator.TransformFunctionTypeParams(Loc, Params, NumParams,
- nullptr, ParamTypes,
- OutParams);
+ return Instantiator.TransformFunctionTypeParams(
+ Loc, Params, nullptr, ExtParamInfos, ParamTypes, OutParams, ParamInfos);
}
/// \brief Perform substitution on the base class specifiers of the
@@ -1861,8 +1854,19 @@ static bool DiagnoseUninstantiableTemplate(Sema &S,
TagDecl *PatternDef,
TemplateSpecializationKind TSK,
bool Complain = true) {
- if (PatternDef && !PatternDef->isBeingDefined())
+ if (PatternDef && !PatternDef->isBeingDefined()) {
+ NamedDecl *SuggestedDef = nullptr;
+ if (!S.hasVisibleDefinition(PatternDef, &SuggestedDef,
+ /*OnlyNeedComplete*/false)) {
+ // If we're allowed to diagnose this and recover, do so.
+ bool Recover = Complain && !S.isSFINAEContext();
+ if (Complain)
+ S.diagnoseMissingImport(PointOfInstantiation, SuggestedDef,
+ Sema::MissingImportKind::Definition, Recover);
+ return !Recover;
+ }
return false;
+ }
if (!Complain || (PatternDef && PatternDef->isInvalidDecl())) {
// Say nothing
@@ -1946,6 +1950,8 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
+ "instantiating class definition");
// Enter the scope of this instantiation. We don't use
// PushDeclContext because we don't have a scope.
@@ -1959,6 +1965,13 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
bool MergeWithParentScope = !Instantiation->isDefinedOutsideFunctionOrMethod();
LocalInstantiationScope Scope(*this, MergeWithParentScope);
+ // All dllexported classes created during instantiation should be fully
+ // emitted after instantiation completes. We may not be ready to emit any
+ // delayed classes already on the stack, so save them away and put them back
+ // later.
+ decltype(DelayedDllExportClasses) ExportedClasses;
+ std::swap(ExportedClasses, DelayedDllExportClasses);
+
// Pull attributes from the pattern onto the instantiation.
InstantiateAttrs(TemplateArgs, Pattern, Instantiation);
@@ -2044,6 +2057,9 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
// default arg exprs for default constructors if necessary now.
ActOnFinishCXXNonNestedClass(Instantiation);
+ // Put back the delayed exported classes that we moved out of the way.
+ std::swap(ExportedClasses, DelayedDllExportClasses);
+
// Instantiate late parsed attributes, and attach them to their decls.
// See Sema::InstantiateAttrs
for (LateInstantiatedAttrVec::iterator I = LateAttrs.begin(),
@@ -2074,7 +2090,7 @@ Sema::InstantiateClass(SourceLocation PointOfInstantiation,
if (TSK == TSK_ImplicitInstantiation) {
Instantiation->setLocation(Pattern->getLocation());
Instantiation->setLocStart(Pattern->getInnerLocStart());
- Instantiation->setRBraceLoc(Pattern->getRBraceLoc());
+ Instantiation->setBraceRange(Pattern->getBraceRange());
}
if (!Instantiation->isInvalidDecl()) {
@@ -2159,6 +2175,8 @@ bool Sema::InstantiateEnum(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
+ "instantiating enum definition");
// The instantiation is visible here, even if it was first declared in an
// unimported module.
@@ -2231,6 +2249,8 @@ bool Sema::InstantiateInClassInitializer(
InstantiatingTemplate Inst(*this, PointOfInstantiation, Instantiation);
if (Inst.isInvalid())
return true;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Instantiation, SourceLocation(),
+ "instantiating default member init");
// Enter the scope of this instantiation. We don't use PushDeclContext because
// we don't have a scope.
@@ -2302,8 +2322,9 @@ bool Sema::InstantiateClassTemplateSpecialization(
Info)) {
// Store the failed-deduction information for use in diagnostics, later.
// TODO: Actually use the failed-deduction info?
- FailedCandidates.addCandidate()
- .set(Partial, MakeDeductionFailureInfo(Context, Result, Info));
+ FailedCandidates.addCandidate().set(
+ DeclAccessPair::make(Template, AS_public), Partial,
+ MakeDeductionFailureInfo(Context, Result, Info));
(void)Result;
} else {
Matched.push_back(PartialSpecMatchResult());
@@ -2495,8 +2516,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
// specialization and is only an explicit instantiation definition
// of members whose definition is visible at the point of
// instantiation.
- if (!Var->getInstantiatedFromStaticDataMember()
- ->getOutOfLineDefinition())
+ if (!Var->getInstantiatedFromStaticDataMember()->getDefinition())
continue;
Var->setTemplateSpecializationKind(TSK, PointOfInstantiation);
@@ -2522,6 +2542,13 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
== TSK_ExplicitSpecialization)
continue;
+ if (Context.getTargetInfo().getCXXABI().isMicrosoft() &&
+ TSK == TSK_ExplicitInstantiationDeclaration) {
+ // In MSVC mode, explicit instantiation decl of the outer class doesn't
+ // affect the inner class.
+ continue;
+ }
+
if (CheckSpecializationInstantiationRedecl(PointOfInstantiation, TSK,
Record,
MSInfo->getTemplateSpecializationKind(),
@@ -2583,7 +2610,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
if (Enum->getDefinition())
continue;
- EnumDecl *Pattern = Enum->getInstantiatedFromMemberEnum();
+ EnumDecl *Pattern = Enum->getTemplateInstantiationPattern();
assert(Pattern && "Missing instantiated-from-template information");
if (TSK == TSK_ExplicitInstantiationDefinition) {
@@ -2603,8 +2630,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
Instantiation->getTemplateInstantiationPattern();
DeclContext::lookup_result Lookup =
ClassPattern->lookup(Field->getDeclName());
- assert(Lookup.size() == 1);
- FieldDecl *Pattern = cast<FieldDecl>(Lookup[0]);
+ FieldDecl *Pattern = cast<FieldDecl>(Lookup.front());
InstantiateInClassInitializer(PointOfInstantiation, Field, Pattern,
TemplateArgs);
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 7a452af77839..6a213953ec9a 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -227,6 +227,86 @@ static void instantiateDependentCUDALaunchBoundsAttr(
Attr.getSpellingListIndex());
}
+static void
+instantiateDependentModeAttr(Sema &S,
+ const MultiLevelTemplateArgumentList &TemplateArgs,
+ const ModeAttr &Attr, Decl *New) {
+ S.AddModeAttr(Attr.getRange(), New, Attr.getMode(),
+ Attr.getSpellingListIndex(), /*InInstantiation=*/true);
+}
+
+/// Instantiation of 'declare simd' attribute and its arguments.
+static void instantiateOMPDeclareSimdDeclAttr(
+ Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs,
+ const OMPDeclareSimdDeclAttr &Attr, Decl *New) {
+ // Allow 'this' in clauses with varlists.
+ if (auto *FTD = dyn_cast<FunctionTemplateDecl>(New))
+ New = FTD->getTemplatedDecl();
+ auto *FD = cast<FunctionDecl>(New);
+ auto *ThisContext = dyn_cast_or_null<CXXRecordDecl>(FD->getDeclContext());
+ SmallVector<Expr *, 4> Uniforms, Aligneds, Alignments, Linears, Steps;
+ SmallVector<unsigned, 4> LinModifiers;
+
+ auto &&Subst = [&](Expr *E) -> ExprResult {
+ if (auto *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()))
+ if (auto *PVD = dyn_cast<ParmVarDecl>(DRE->getDecl())) {
+ Sema::ContextRAII SavedContext(S, FD);
+ LocalInstantiationScope Local(S);
+ if (FD->getNumParams() > PVD->getFunctionScopeIndex())
+ Local.InstantiatedLocal(
+ PVD, FD->getParamDecl(PVD->getFunctionScopeIndex()));
+ return S.SubstExpr(E, TemplateArgs);
+ }
+ Sema::CXXThisScopeRAII ThisScope(S, ThisContext, /*TypeQuals=*/0,
+ FD->isCXXInstanceMember());
+ return S.SubstExpr(E, TemplateArgs);
+ };
+
+ ExprResult Simdlen;
+ if (auto *E = Attr.getSimdlen())
+ Simdlen = Subst(E);
+
+ if (Attr.uniforms_size() > 0) {
+ for(auto *E : Attr.uniforms()) {
+ ExprResult Inst = Subst(E);
+ if (Inst.isInvalid())
+ continue;
+ Uniforms.push_back(Inst.get());
+ }
+ }
+
+ auto AI = Attr.alignments_begin();
+ for (auto *E : Attr.aligneds()) {
+ ExprResult Inst = Subst(E);
+ if (Inst.isInvalid())
+ continue;
+ Aligneds.push_back(Inst.get());
+ Inst = ExprEmpty();
+ if (*AI)
+ Inst = S.SubstExpr(*AI, TemplateArgs);
+ Alignments.push_back(Inst.get());
+ ++AI;
+ }
+
+ auto SI = Attr.steps_begin();
+ for (auto *E : Attr.linears()) {
+ ExprResult Inst = Subst(E);
+ if (Inst.isInvalid())
+ continue;
+ Linears.push_back(Inst.get());
+ Inst = ExprEmpty();
+ if (*SI)
+ Inst = S.SubstExpr(*SI, TemplateArgs);
+ Steps.push_back(Inst.get());
+ ++SI;
+ }
+ LinModifiers.append(Attr.modifiers_begin(), Attr.modifiers_end());
+ (void)S.ActOnOpenMPDeclareSimdDirective(
+ S.ConvertDeclToDeclGroup(New), Attr.getBranchState(), Simdlen.get(),
+ Uniforms, Aligneds, Alignments, Linears, LinModifiers, Steps,
+ Attr.getRange());
+}
+
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
const Decl *Tmpl, Decl *New,
LateInstantiatedAttrVec *LateAttrs,
@@ -265,6 +345,16 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
continue;
}
+ if (const ModeAttr *Mode = dyn_cast<ModeAttr>(TmplAttr)) {
+ instantiateDependentModeAttr(*this, TemplateArgs, *Mode, New);
+ continue;
+ }
+
+ if (const auto *OMPAttr = dyn_cast<OMPDeclareSimdDeclAttr>(TmplAttr)) {
+ instantiateOMPDeclareSimdDeclAttr(*this, TemplateArgs, *OMPAttr, New);
+ continue;
+ }
+
// Existing DLL attribute on the instantiation takes precedence.
if (TmplAttr->getKind() == attr::DLLExport ||
TmplAttr->getKind() == attr::DLLImport) {
@@ -273,6 +363,20 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
}
}
+ if (auto ABIAttr = dyn_cast<ParameterABIAttr>(TmplAttr)) {
+ AddParameterABIAttr(ABIAttr->getRange(), New, ABIAttr->getABI(),
+ ABIAttr->getSpellingListIndex());
+ continue;
+ }
+
+ if (isa<NSConsumedAttr>(TmplAttr) || isa<CFConsumedAttr>(TmplAttr)) {
+ AddNSConsumedAttr(TmplAttr->getRange(), New,
+ TmplAttr->getSpellingListIndex(),
+ isa<NSConsumedAttr>(TmplAttr),
+ /*template instantiation*/ true);
+ continue;
+ }
+
assert(!TmplAttr->isPackExpansion());
if (TmplAttr->isLateParsed() && LateAttrs) {
// Late parsed attributes must be instantiated and attached after the
@@ -321,6 +425,16 @@ TemplateDeclInstantiator::VisitTranslationUnitDecl(TranslationUnitDecl *D) {
}
Decl *
+TemplateDeclInstantiator::VisitPragmaCommentDecl(PragmaCommentDecl *D) {
+ llvm_unreachable("pragma comment cannot be instantiated");
+}
+
+Decl *TemplateDeclInstantiator::VisitPragmaDetectMismatchDecl(
+ PragmaDetectMismatchDecl *D) {
+ llvm_unreachable("pragma comment cannot be instantiated");
+}
+
+Decl *
TemplateDeclInstantiator::VisitExternCContextDecl(ExternCContextDecl *D) {
llvm_unreachable("extern \"C\" context cannot be instantiated");
}
@@ -491,13 +605,6 @@ Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D) {
Decl *TemplateDeclInstantiator::VisitVarDecl(VarDecl *D,
bool InstantiatingVarTemplate) {
- // If this is the variable for an anonymous struct or union,
- // instantiate the anonymous struct/union type first.
- if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
- if (RecordTy->getDecl()->isAnonymousStructOrUnion())
- if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return nullptr;
-
// Do substitution on the type of the declaration
TypeSourceInfo *DI = SemaRef.SubstType(D->getTypeSourceInfo(),
TemplateArgs,
@@ -696,7 +803,7 @@ Decl *TemplateDeclInstantiator::VisitIndirectFieldDecl(IndirectFieldDecl *D) {
QualType T = cast<FieldDecl>(NamedChain[i-1])->getType();
IndirectFieldDecl *IndirectField = IndirectFieldDecl::Create(
SemaRef.Context, Owner, D->getLocation(), D->getIdentifier(), T,
- NamedChain, D->getChainingSize());
+ {NamedChain, D->getChainingSize()});
for (const auto *Attr : D->attrs())
IndirectField->addAttr(Attr->clone(SemaRef.Context));
@@ -911,9 +1018,7 @@ void TemplateDeclInstantiator::InstantiateEnumDefinition(
}
}
- // FIXME: Fixup LBraceLoc
- SemaRef.ActOnEnumBody(Enum->getLocation(), SourceLocation(),
- Enum->getRBraceLoc(), Enum,
+ SemaRef.ActOnEnumBody(Enum->getLocation(), Enum->getBraceRange(), Enum,
Enumerators,
nullptr, nullptr);
}
@@ -1499,8 +1604,7 @@ Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D,
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Function->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
- Innermost.begin(),
- Innermost.size()),
+ Innermost),
/*InsertPos=*/nullptr);
} else if (isFriend) {
// Note, we need this connection even if the friend doesn't have a body.
@@ -1736,36 +1840,6 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
Constructor->isExplicit(),
Constructor->isInlineSpecified(),
false, Constructor->isConstexpr());
-
- // Claim that the instantiation of a constructor or constructor template
- // inherits the same constructor that the template does.
- if (CXXConstructorDecl *Inh = const_cast<CXXConstructorDecl *>(
- Constructor->getInheritedConstructor())) {
- // If we're instantiating a specialization of a function template, our
- // "inherited constructor" will actually itself be a function template.
- // Instantiate a declaration of it, too.
- if (FunctionTemplate) {
- assert(!TemplateParams && Inh->getDescribedFunctionTemplate() &&
- !Inh->getParent()->isDependentContext() &&
- "inheriting constructor template in dependent context?");
- Sema::InstantiatingTemplate Inst(SemaRef, Constructor->getLocation(),
- Inh);
- if (Inst.isInvalid())
- return nullptr;
- Sema::ContextRAII SavedContext(SemaRef, Inh->getDeclContext());
- LocalInstantiationScope LocalScope(SemaRef);
-
- // Use the same template arguments that we deduced for the inheriting
- // constructor. There's no way they could be deduced differently.
- MultiLevelTemplateArgumentList InheritedArgs;
- InheritedArgs.addOuterTemplateArguments(TemplateArgs.getInnermost());
- Inh = cast_or_null<CXXConstructorDecl>(
- SemaRef.SubstDecl(Inh, Inh->getDeclContext(), InheritedArgs));
- if (!Inh)
- return nullptr;
- }
- cast<CXXConstructorDecl>(Method)->setInheritedConstructor(Inh);
- }
} else if (CXXDestructorDecl *Destructor = dyn_cast<CXXDestructorDecl>(D)) {
Method = CXXDestructorDecl::Create(SemaRef.Context, Record,
StartLoc, NameInfo, T, TInfo,
@@ -1821,8 +1895,7 @@ TemplateDeclInstantiator::VisitCXXMethodDecl(CXXMethodDecl *D,
ArrayRef<TemplateArgument> Innermost = TemplateArgs.getInnermost();
Method->setFunctionTemplateSpecialization(FunctionTemplate,
TemplateArgumentList::CreateCopy(SemaRef.Context,
- Innermost.begin(),
- Innermost.size()),
+ Innermost),
/*InsertPos=*/nullptr);
} else if (!isFriend) {
// Record that this is an instantiation of a member function.
@@ -2080,16 +2153,11 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
NonTypeTemplateParmDecl *Param;
if (IsExpandedParameterPack)
- Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
- D->getInnerLocStart(),
- D->getLocation(),
- D->getDepth() - TemplateArgs.getNumLevels(),
- D->getPosition(),
- D->getIdentifier(), T,
- DI,
- ExpandedParameterPackTypes.data(),
- ExpandedParameterPackTypes.size(),
- ExpandedParameterPackTypesAsWritten.data());
+ Param = NonTypeTemplateParmDecl::Create(
+ SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
+ D->getDepth() - TemplateArgs.getNumLevels(), D->getPosition(),
+ D->getIdentifier(), T, DI, ExpandedParameterPackTypes,
+ ExpandedParameterPackTypesAsWritten);
else
Param = NonTypeTemplateParmDecl::Create(SemaRef.Context, Owner,
D->getInnerLocStart(),
@@ -2104,6 +2172,8 @@ Decl *TemplateDeclInstantiator::VisitNonTypeTemplateParmDecl(
Param->setInvalidDecl();
if (D->hasDefaultArgument() && !D->defaultArgumentWasInherited()) {
+ EnterExpressionEvaluationContext ConstantEvaluated(SemaRef,
+ Sema::ConstantEvaluated);
ExprResult Value = SemaRef.SubstExpr(D->getDefaultArgument(), TemplateArgs);
if (!Value.isInvalid())
Param->setDefaultArgument(Value.get());
@@ -2289,9 +2359,14 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (!QualifierLoc)
return nullptr;
- // The name info is non-dependent, so no transformation
- // is required.
+ // For an inheriting constructor declaration, the name of the using
+ // declaration is the name of a constructor in this class, not in the
+ // base class.
DeclarationNameInfo NameInfo = D->getNameInfo();
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
+ if (auto *RD = dyn_cast<CXXRecordDecl>(SemaRef.CurContext))
+ NameInfo.setName(SemaRef.Context.DeclarationNames.getCXXConstructorName(
+ SemaRef.Context.getCanonicalType(SemaRef.Context.getRecordType(RD))));
// We only need to do redeclaration lookups if we're in a class
// scope (in fact, it's not really even possible in non-class
@@ -2334,18 +2409,23 @@ Decl *TemplateDeclInstantiator::VisitUsingDecl(UsingDecl *D) {
if (NewUD->isInvalidDecl())
return NewUD;
- if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName) {
+ if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
SemaRef.CheckInheritingConstructorUsingDecl(NewUD);
- return NewUD;
- }
bool isFunctionScope = Owner->isFunctionOrMethod();
// Process the shadow decls.
for (auto *Shadow : D->shadows()) {
+ // FIXME: UsingShadowDecl doesn't preserve its immediate target, so
+ // reconstruct it in the case where it matters.
+ NamedDecl *OldTarget = Shadow->getTargetDecl();
+ if (auto *CUSD = dyn_cast<ConstructorUsingShadowDecl>(Shadow))
+ if (auto *BaseShadow = CUSD->getNominatedBaseClassShadowDecl())
+ OldTarget = BaseShadow;
+
NamedDecl *InstTarget =
cast_or_null<NamedDecl>(SemaRef.FindInstantiatedDecl(
- Shadow->getLocation(), Shadow->getTargetDecl(), TemplateArgs));
+ Shadow->getLocation(), OldTarget, TemplateArgs));
if (!InstTarget)
return nullptr;
@@ -2376,6 +2456,12 @@ Decl *TemplateDeclInstantiator::VisitUsingShadowDecl(UsingShadowDecl *D) {
return nullptr;
}
+Decl *TemplateDeclInstantiator::VisitConstructorUsingShadowDecl(
+ ConstructorUsingShadowDecl *D) {
+ // Ignore these; we handle them in bulk when processing the UsingDecl.
+ return nullptr;
+}
+
Decl * TemplateDeclInstantiator
::VisitUnresolvedUsingTypenameDecl(UnresolvedUsingTypenameDecl *D) {
NestedNameSpecifierLoc QualifierLoc
@@ -2477,6 +2563,86 @@ Decl *TemplateDeclInstantiator::VisitOMPThreadPrivateDecl(
return TD;
}
+Decl *TemplateDeclInstantiator::VisitOMPDeclareReductionDecl(
+ OMPDeclareReductionDecl *D) {
+ // Instantiate type and check if it is allowed.
+ QualType SubstReductionType = SemaRef.ActOnOpenMPDeclareReductionType(
+ D->getLocation(),
+ ParsedType::make(SemaRef.SubstType(D->getType(), TemplateArgs,
+ D->getLocation(), DeclarationName())));
+ if (SubstReductionType.isNull())
+ return nullptr;
+ bool IsCorrect = !SubstReductionType.isNull();
+ // Create instantiated copy.
+ std::pair<QualType, SourceLocation> ReductionTypes[] = {
+ std::make_pair(SubstReductionType, D->getLocation())};
+ auto *PrevDeclInScope = D->getPrevDeclInScope();
+ if (PrevDeclInScope && !PrevDeclInScope->isInvalidDecl()) {
+ PrevDeclInScope = cast<OMPDeclareReductionDecl>(
+ SemaRef.CurrentInstantiationScope->findInstantiationOf(PrevDeclInScope)
+ ->get<Decl *>());
+ }
+ auto DRD = SemaRef.ActOnOpenMPDeclareReductionDirectiveStart(
+ /*S=*/nullptr, Owner, D->getDeclName(), ReductionTypes, D->getAccess(),
+ PrevDeclInScope);
+ auto *NewDRD = cast<OMPDeclareReductionDecl>(DRD.get().getSingleDecl());
+ if (isDeclWithinFunction(NewDRD))
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(D, NewDRD);
+ Expr *SubstCombiner = nullptr;
+ Expr *SubstInitializer = nullptr;
+ // Combiners instantiation sequence.
+ if (D->getCombiner()) {
+ SemaRef.ActOnOpenMPDeclareReductionCombinerStart(
+ /*S=*/nullptr, NewDRD);
+ const char *Names[] = {"omp_in", "omp_out"};
+ for (auto &Name : Names) {
+ DeclarationName DN(&SemaRef.Context.Idents.get(Name));
+ auto OldLookup = D->lookup(DN);
+ auto Lookup = NewDRD->lookup(DN);
+ if (!OldLookup.empty() && !Lookup.empty()) {
+ assert(Lookup.size() == 1 && OldLookup.size() == 1);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(OldLookup.front(),
+ Lookup.front());
+ }
+ }
+ SubstCombiner = SemaRef.SubstExpr(D->getCombiner(), TemplateArgs).get();
+ SemaRef.ActOnOpenMPDeclareReductionCombinerEnd(NewDRD, SubstCombiner);
+ // Initializers instantiation sequence.
+ if (D->getInitializer()) {
+ SemaRef.ActOnOpenMPDeclareReductionInitializerStart(
+ /*S=*/nullptr, NewDRD);
+ const char *Names[] = {"omp_orig", "omp_priv"};
+ for (auto &Name : Names) {
+ DeclarationName DN(&SemaRef.Context.Idents.get(Name));
+ auto OldLookup = D->lookup(DN);
+ auto Lookup = NewDRD->lookup(DN);
+ if (!OldLookup.empty() && !Lookup.empty()) {
+ assert(Lookup.size() == 1 && OldLookup.size() == 1);
+ SemaRef.CurrentInstantiationScope->InstantiatedLocal(
+ OldLookup.front(), Lookup.front());
+ }
+ }
+ SubstInitializer =
+ SemaRef.SubstExpr(D->getInitializer(), TemplateArgs).get();
+ SemaRef.ActOnOpenMPDeclareReductionInitializerEnd(NewDRD,
+ SubstInitializer);
+ }
+ IsCorrect = IsCorrect && SubstCombiner &&
+ (!D->getInitializer() || SubstInitializer);
+ } else
+ IsCorrect = false;
+
+ (void)SemaRef.ActOnOpenMPDeclareReductionDirectiveEnd(/*S=*/nullptr, DRD,
+ IsCorrect);
+
+ return NewDRD;
+}
+
+Decl *TemplateDeclInstantiator::VisitOMPCapturedExprDecl(
+ OMPCapturedExprDecl * /*D*/) {
+ llvm_unreachable("Should not be met in templates");
+}
+
Decl *TemplateDeclInstantiator::VisitFunctionDecl(FunctionDecl *D) {
return VisitFunctionDecl(D, nullptr);
}
@@ -2580,8 +2746,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
D->getLocStart(),
D->getLocation(),
InstClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
PrevDecl);
// Add this partial specialization to the set of class template partial
@@ -2596,7 +2761,7 @@ TemplateDeclInstantiator::VisitClassTemplateSpecializationDecl(
// Build the canonical type that describes the converted template
// arguments of the class template explicit specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(InstClassTemplate), Converted.data(), Converted.size(),
+ TemplateName(InstClassTemplate), Converted,
SemaRef.Context.getRecordType(InstD));
// Build the fully-sugared type for this class template
@@ -2673,13 +2838,6 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
const TemplateArgumentListInfo &TemplateArgsInfo,
ArrayRef<TemplateArgument> Converted) {
- // If this is the variable for an anonymous struct or union,
- // instantiate the anonymous struct/union type first.
- if (const RecordType *RecordTy = D->getType()->getAs<RecordType>())
- if (RecordTy->getDecl()->isAnonymousStructOrUnion())
- if (!VisitCXXRecordDecl(cast<CXXRecordDecl>(RecordTy->getDecl())))
- return nullptr;
-
// Do substitution on the type of the declaration
TypeSourceInfo *DI =
SemaRef.SubstType(D->getTypeSourceInfo(), TemplateArgs,
@@ -2696,8 +2854,7 @@ Decl *TemplateDeclInstantiator::VisitVarTemplateSpecializationDecl(
// Build the instantiated declaration
VarTemplateSpecializationDecl *Var = VarTemplateSpecializationDecl::Create(
SemaRef.Context, Owner, D->getInnerLocStart(), D->getLocation(),
- VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted.data(),
- Converted.size());
+ VarTemplate, DI->getType(), DI, D->getStorageClass(), Converted);
Var->setTemplateArgsInfo(TemplateArgsInfo);
if (InsertPos)
VarTemplate->AddSpecialization(Var, InsertPos);
@@ -2830,8 +2987,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
// arguments of the class template partial specialization.
QualType CanonType
= SemaRef.Context.getTemplateSpecializationType(TemplateName(ClassTemplate),
- Converted.data(),
- Converted.size());
+ Converted);
// Build the fully-sugared type for this class template
// specialization as the user wrote in the specialization
@@ -2880,8 +3036,7 @@ TemplateDeclInstantiator::InstantiateClassTemplatePartialSpecialization(
PartialSpec->getLocation(),
InstParams,
ClassTemplate,
- Converted.data(),
- Converted.size(),
+ Converted,
InstTemplateArgs,
CanonType,
nullptr);
@@ -2953,7 +3108,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
// Build the canonical type that describes the converted template
// arguments of the variable template partial specialization.
QualType CanonType = SemaRef.Context.getTemplateSpecializationType(
- TemplateName(VarTemplate), Converted.data(), Converted.size());
+ TemplateName(VarTemplate), Converted);
// Build the fully-sugared type for this variable template
// specialization as the user wrote in the specialization
@@ -3009,8 +3164,7 @@ TemplateDeclInstantiator::InstantiateVarTemplatePartialSpecialization(
VarTemplatePartialSpecializationDecl::Create(
SemaRef.Context, Owner, PartialSpec->getInnerLocStart(),
PartialSpec->getLocation(), InstParams, VarTemplate, DI->getType(),
- DI, PartialSpec->getStorageClass(), Converted.data(),
- Converted.size(), InstTemplateArgs);
+ DI, PartialSpec->getStorageClass(), Converted, InstTemplateArgs);
// Substitute the nested name specifier, if any.
if (SubstQualifier(PartialSpec, InstPartialSpec))
@@ -3118,9 +3272,10 @@ TemplateDeclInstantiator::SubstFunctionType(FunctionDecl *D,
// In this case, we'll just go instantiate the ParmVarDecls that we
// synthesized in the method declaration.
SmallVector<QualType, 4> ParamTypes;
- if (SemaRef.SubstParmTypes(D->getLocation(), D->param_begin(),
- D->getNumParams(), TemplateArgs, ParamTypes,
- &Params))
+ Sema::ExtParameterInfoBuilder ExtParamInfos;
+ if (SemaRef.SubstParmTypes(D->getLocation(), D->parameters(), nullptr,
+ TemplateArgs, ParamTypes, &Params,
+ ExtParamInfos))
return nullptr;
}
@@ -3347,7 +3502,8 @@ TemplateDeclInstantiator::InitMethodInstantiation(CXXMethodDecl *New,
void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
FunctionDecl *Function,
bool Recursive,
- bool DefinitionRequired) {
+ bool DefinitionRequired,
+ bool AtEndOfTU) {
if (Function->isInvalidDecl() || Function->isDefined())
return;
@@ -3401,6 +3557,10 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
Pattern = PatternDecl->getBody(PatternDecl);
}
+ // FIXME: Check that the definition is visible before trying to instantiate
+ // it. This requires us to track the instantiation stack in order to know
+ // which definitions should be visible.
+
if (!Pattern && !PatternDecl->isDefaulted()) {
if (DefinitionRequired) {
if (Function->getPrimaryTemplate())
@@ -3421,6 +3581,16 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
assert(!Recursive);
PendingInstantiations.push_back(
std::make_pair(Function, PointOfInstantiation));
+ } else if (Function->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
+ Diag(PointOfInstantiation, diag::warn_func_template_missing)
+ << Function;
+ Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
+ if (getLangOpts().CPlusPlus11)
+ Diag(PointOfInstantiation, diag::note_inst_declaration_hint)
+ << Function;
+ }
}
return;
@@ -3451,6 +3621,8 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Function);
if (Inst.isInvalid())
return;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(),
+ "instantiating function definition");
// Copy the inner loc start from the pattern.
Function->setInnerLocStart(PatternDecl->getInnerLocStart());
@@ -3681,11 +3853,12 @@ void Sema::BuildVariableInstantiation(
Context.setManglingNumber(NewVar, Context.getManglingNumber(OldVar));
Context.setStaticLocalNumber(NewVar, Context.getStaticLocalNumber(OldVar));
- // Delay instantiation of the initializer for variable templates until a
- // definition of the variable is needed. We need it right away if the type
- // contains 'auto'.
+ // Delay instantiation of the initializer for variable templates or inline
+ // static data members until a definition of the variable is needed. We need
+ // it right away if the type contains 'auto'.
if ((!isa<VarTemplateSpecializationDecl>(NewVar) &&
- !InstantiatingVarTemplate) ||
+ !InstantiatingVarTemplate &&
+ !(OldVar->isInline() && OldVar->isThisDeclarationADefinition())) ||
NewVar->getType()->isUndeducedType())
InstantiateVariableInitializer(NewVar, OldVar, TemplateArgs);
@@ -3701,6 +3874,13 @@ void Sema::BuildVariableInstantiation(
void Sema::InstantiateVariableInitializer(
VarDecl *Var, VarDecl *OldVar,
const MultiLevelTemplateArgumentList &TemplateArgs) {
+ // We propagate the 'inline' flag with the initializer, because it
+ // would otherwise imply that the variable is a definition for a
+ // non-static data member.
+ if (OldVar->isInlineSpecified())
+ Var->setInlineSpecified();
+ else if (OldVar->isInline())
+ Var->setImplicitlyInline();
if (Var->getAnyInitializer())
// We already have an initializer in the class.
@@ -3713,9 +3893,14 @@ void Sema::InstantiateVariableInitializer(
PushExpressionEvaluationContext(Sema::PotentiallyEvaluated, OldVar);
// Instantiate the initializer.
- ExprResult Init =
- SubstInitializer(OldVar->getInit(), TemplateArgs,
- OldVar->getInitStyle() == VarDecl::CallInit);
+ ExprResult Init;
+
+ {
+ ContextRAII SwitchContext(*this, Var->getDeclContext());
+ Init = SubstInitializer(OldVar->getInit(), TemplateArgs,
+ OldVar->getInitStyle() == VarDecl::CallInit);
+ }
+
if (!Init.isInvalid()) {
bool TypeMayContainAuto = true;
Expr *InitExpr = Init.get();
@@ -3768,7 +3953,7 @@ void Sema::InstantiateStaticDataMemberDefinition(
void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
VarDecl *Var, bool Recursive,
- bool DefinitionRequired) {
+ bool DefinitionRequired, bool AtEndOfTU) {
if (Var->isInvalidDecl())
return;
@@ -3830,6 +4015,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst.isInvalid())
return;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
+ "instantiating variable initializer");
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate
@@ -3876,9 +4063,13 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
assert(PatternDecl && "data member was not instantiated from a template?");
assert(PatternDecl->isStaticDataMember() && "not a static data member?");
- Def = PatternDecl->getOutOfLineDefinition();
+ Def = PatternDecl->getDefinition();
}
+ // FIXME: Check that the definition is visible before trying to instantiate
+ // it. This requires us to track the instantiation stack in order to know
+ // which definitions should be visible.
+
// If we don't have a definition of the variable template, we won't perform
// any instantiation. Rather, we rely on the user to instantiate this
// definition (or provide a specialization for it) in another translation
@@ -3900,6 +4091,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
== TSK_ExplicitInstantiationDefinition) {
PendingInstantiations.push_back(
std::make_pair(Var, PointOfInstantiation));
+ } else if (Var->getTemplateSpecializationKind()
+ == TSK_ImplicitInstantiation) {
+ // Warn about missing definition at the end of translation unit.
+ if (AtEndOfTU && !getDiagnostics().hasErrorOccurred()) {
+ Diag(PointOfInstantiation, diag::warn_var_template_missing)
+ << Var;
+ Diag(PatternDecl->getLocation(), diag::note_forward_template_decl);
+ if (getLangOpts().CPlusPlus11)
+ Diag(PointOfInstantiation, diag::note_inst_declaration_hint) << Var;
+ }
}
return;
@@ -3943,6 +4144,8 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
InstantiatingTemplate Inst(*this, PointOfInstantiation, Var);
if (Inst.isInvalid())
return;
+ PrettyDeclStackTraceEntry CrashInfo(*this, Var, SourceLocation(),
+ "instantiating variable definition");
// If we're performing recursive template instantiation, create our own
// queue of pending implicit instantiations that we will instantiate later,
@@ -3958,11 +4161,16 @@ void Sema::InstantiateVariableDefinition(SourceLocation PointOfInstantiation,
LocalInstantiationScope Local(*this);
VarDecl *OldVar = Var;
- if (!VarSpec)
+ if (Def->isStaticDataMember() && !Def->isOutOfLine()) {
+ // We're instantiating an inline static data member whose definition was
+ // provided inside the class.
+ // FIXME: Update record?
+ InstantiateVariableInitializer(Var, Def, TemplateArgs);
+ } else if (!VarSpec) {
Var = cast_or_null<VarDecl>(SubstDecl(Def, Var->getDeclContext(),
TemplateArgs));
- else if (Var->isStaticDataMember() &&
- Var->getLexicalDeclContext()->isRecord()) {
+ } else if (Var->isStaticDataMember() &&
+ Var->getLexicalDeclContext()->isRecord()) {
// We need to instantiate the definition of a static data member template,
// and all we have is the in-class declaration of it. Instantiate a separate
// declaration of the definition.
@@ -4664,12 +4872,10 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Instantiate function definitions
if (FunctionDecl *Function = dyn_cast<FunctionDecl>(Inst.first)) {
- PrettyDeclStackTraceEntry CrashInfo(*this, Function, SourceLocation(),
- "instantiating function definition");
bool DefinitionRequired = Function->getTemplateSpecializationKind() ==
TSK_ExplicitInstantiationDefinition;
InstantiateFunctionDefinition(/*FIXME:*/Inst.second, Function, true,
- DefinitionRequired);
+ DefinitionRequired, true);
continue;
}
@@ -4710,7 +4916,7 @@ void Sema::PerformPendingInstantiations(bool LocalOnly) {
// Instantiate static data member definitions or variable template
// specializations.
InstantiateVariableDefinition(/*FIXME:*/ Inst.second, Var, true,
- DefinitionRequired);
+ DefinitionRequired, true);
}
}
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
index cb67d71f9e59..06afe87f515e 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -604,7 +604,7 @@ bool Sema::CheckParameterPacksForExpansion(
// Template argument deduction can extend the sequence of template
// arguments corresponding to a template parameter pack, even when the
// sequence contains explicitly specified template arguments.
- if (!IsFunctionParameterPack) {
+ if (!IsFunctionParameterPack && CurrentInstantiationScope) {
if (NamedDecl *PartialPack
= CurrentInstantiationScope->getPartiallySubstitutedPack()){
unsigned PartialDepth, PartialIndex;
@@ -727,6 +727,7 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_half:
case TST_float:
case TST_double:
+ case TST_float128:
case TST_bool:
case TST_decimal32:
case TST_decimal64:
@@ -739,6 +740,8 @@ bool Sema::containsUnexpandedParameterPacks(Declarator &D) {
case TST_auto:
case TST_auto_type:
case TST_decltype_auto:
+#define GENERIC_IMAGE_TYPE(ImgType, Id) case TST_##ImgType##_t:
+#include "clang/Basic/OpenCLImageTypes.def"
case TST_unknown_anytype:
case TST_error:
break;
@@ -996,10 +999,6 @@ ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
BinaryOperatorKind Operator) {
// [temp.variadic]p9:
// If N is zero for a unary fold-expression, the value of the expression is
- // * -> 1
- // + -> int()
- // & -> -1
- // | -> int()
// && -> true
// || -> false
// , -> void()
@@ -1009,17 +1008,6 @@ ExprResult Sema::BuildEmptyCXXFoldExpr(SourceLocation EllipsisLoc,
// prevent the result from being a null pointer constant.
QualType ScalarType;
switch (Operator) {
- case BO_Add:
- ScalarType = Context.IntTy;
- break;
- case BO_Mul:
- return ActOnIntegerConstant(EllipsisLoc, 1);
- case BO_Or:
- ScalarType = Context.IntTy;
- break;
- case BO_And:
- return CreateBuiltinUnaryOp(EllipsisLoc, UO_Minus,
- ActOnIntegerConstant(EllipsisLoc, 1).get());
case BO_LOr:
return ActOnCXXBoolLiteral(EllipsisLoc, tok::kw_false);
case BO_LAnd:
diff --git a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
index f6ad132cde83..f3747eaa5cb5 100644
--- a/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/SemaType.cpp
@@ -11,7 +11,6 @@
//
//===----------------------------------------------------------------------===//
-#include "clang/Sema/SemaInternal.h"
#include "TypeLocBuilder.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/AST/ASTContext.h"
@@ -22,7 +21,6 @@
#include "clang/AST/Expr.h"
#include "clang/AST/TypeLoc.h"
#include "clang/AST/TypeLocVisitor.h"
-#include "clang/Lex/Preprocessor.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/Lex/Preprocessor.h"
@@ -30,9 +28,11 @@
#include "clang/Sema/DelayedDiagnostic.h"
#include "clang/Sema/Lookup.h"
#include "clang/Sema/ScopeInfo.h"
+#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/Template.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
using namespace clang;
@@ -100,20 +100,27 @@ static void diagnoseBadTypeAttribute(Sema &S, const AttributeList &attr,
case AttributeList::AT_ObjCGC: \
case AttributeList::AT_ObjCOwnership
-// Function type attributes.
-#define FUNCTION_TYPE_ATTRS_CASELIST \
- case AttributeList::AT_NoReturn: \
+// Calling convention attributes.
+#define CALLING_CONV_ATTRS_CASELIST \
case AttributeList::AT_CDecl: \
case AttributeList::AT_FastCall: \
case AttributeList::AT_StdCall: \
case AttributeList::AT_ThisCall: \
case AttributeList::AT_Pascal: \
+ case AttributeList::AT_SwiftCall: \
case AttributeList::AT_VectorCall: \
case AttributeList::AT_MSABI: \
case AttributeList::AT_SysVABI: \
- case AttributeList::AT_Regparm: \
case AttributeList::AT_Pcs: \
- case AttributeList::AT_IntelOclBicc
+ case AttributeList::AT_IntelOclBicc: \
+ case AttributeList::AT_PreserveMost: \
+ case AttributeList::AT_PreserveAll
+
+// Function type attributes.
+#define FUNCTION_TYPE_ATTRS_CASELIST \
+ case AttributeList::AT_NoReturn: \
+ case AttributeList::AT_Regparm: \
+ CALLING_CONV_ATTRS_CASELIST
// Microsoft-specific type qualifiers.
#define MS_TYPE_ATTRS_CASELIST \
@@ -239,7 +246,7 @@ namespace {
savedAttrs.back()->setNext(nullptr);
}
};
-}
+} // end anonymous namespace
static void spliceAttrIntoList(AttributeList &attr, AttributeList *&head) {
attr.setNext(head);
@@ -727,6 +734,7 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS,
// it; they probably didn't mean to specify a redundant qualifier.
typedef std::pair<DeclSpec::TQ, SourceLocation> QualLoc;
for (QualLoc Qual : {QualLoc(DeclSpec::TQ_const, DS.getConstSpecLoc()),
+ QualLoc(DeclSpec::TQ_restrict, DS.getRestrictSpecLoc()),
QualLoc(DeclSpec::TQ_volatile, DS.getVolatileSpecLoc()),
QualLoc(DeclSpec::TQ_atomic, DS.getAtomicSpecLoc())}) {
if (!(RemoveTQs & Qual.first))
@@ -743,6 +751,47 @@ static void diagnoseAndRemoveTypeQualifiers(Sema &S, const DeclSpec &DS,
}
}
+/// Return true if this is omitted block return type. Also check type
+/// attributes and type qualifiers when returning true.
+static bool checkOmittedBlockReturnType(Sema &S, Declarator &declarator,
+ QualType Result) {
+ if (!isOmittedBlockReturnType(declarator))
+ return false;
+
+ // Warn if we see type attributes for omitted return type on a block literal.
+ AttributeList *&attrs =
+ declarator.getMutableDeclSpec().getAttributes().getListRef();
+ AttributeList *prev = nullptr;
+ for (AttributeList *cur = attrs; cur; cur = cur->getNext()) {
+ AttributeList &attr = *cur;
+ // Skip attributes that were marked to be invalid or non-type
+ // attributes.
+ if (attr.isInvalid() || !attr.isTypeAttr()) {
+ prev = cur;
+ continue;
+ }
+ S.Diag(attr.getLoc(),
+ diag::warn_block_literal_attributes_on_omitted_return_type)
+ << attr.getName();
+ // Remove cur from the list.
+ if (prev) {
+ prev->setNext(cur->getNext());
+ prev = cur;
+ } else {
+ attrs = cur->getNext();
+ }
+ }
+
+ // Warn if we see type qualifiers for omitted return type on a block literal.
+ const DeclSpec &DS = declarator.getDeclSpec();
+ unsigned TypeQuals = DS.getTypeQualifiers();
+ diagnoseAndRemoveTypeQualifiers(S, DS, TypeQuals, Result, (unsigned)-1,
+ diag::warn_block_literal_qualifiers_on_omitted_return_type);
+ declarator.getMutableDeclSpec().ClearTypeQualifiers();
+
+ return true;
+}
+
/// Apply Objective-C type arguments to the given type.
static QualType applyObjCTypeArgs(Sema &S, SourceLocation loc, QualType type,
ArrayRef<TypeSourceInfo *> typeArgs,
@@ -1171,6 +1220,21 @@ TypeResult Sema::actOnObjCTypeArgsAndProtocolQualifiers(
return CreateParsedType(Result, ResultTInfo);
}
+static StringRef getImageAccessAttrStr(AttributeList *attrs) {
+ if (attrs) {
+
+ AttributeList *Next;
+ do {
+ AttributeList &Attr = *attrs;
+ Next = Attr.getNext();
+ if (Attr.getKind() == AttributeList::AT_OpenCLAccess) {
+ return Attr.getName()->getName();
+ }
+ } while (Next);
+ }
+ return "";
+}
+
/// \brief Convert the specified declspec to the appropriate type
/// object.
/// \param state Specifies the declarator containing the declaration specifier
@@ -1244,7 +1308,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
Result = Context.getAutoDeductType();
break;
} else if (declarator.getContext() == Declarator::LambdaExprContext ||
- isOmittedBlockReturnType(declarator)) {
+ checkOmittedBlockReturnType(S, declarator,
+ Context.DependentTy)) {
Result = Context.DependentTy;
break;
}
@@ -1332,7 +1397,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
case DeclSpec::TST_int128:
if (!S.Context.getTargetInfo().hasInt128Type())
- S.Diag(DS.getTypeSpecTypeLoc(), diag::err_int128_unsupported);
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
+ << "__int128";
if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned)
Result = Context.UnsignedInt128Ty;
else
@@ -1354,7 +1420,14 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
declarator.setInvalidType(true);
}
break;
+ case DeclSpec::TST_float128:
+ if (!S.Context.getTargetInfo().hasFloat128Type())
+ S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported)
+ << "__float128";
+ Result = Context.Float128Ty;
+ break;
case DeclSpec::TST_bool: Result = Context.BoolTy; break; // _Bool or bool
+ break;
case DeclSpec::TST_decimal32: // _Decimal32
case DeclSpec::TST_decimal64: // _Decimal64
case DeclSpec::TST_decimal128: // _Decimal128
@@ -1423,9 +1496,18 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
declarator.setInvalidType(true);
}
} else if (!S.getOpenCLOptions().cl_khr_gl_msaa_sharing &&
- (Result->isImage2dMSAAT() || Result->isImage2dArrayMSAAT() ||
- Result->isImage2dArrayMSAATDepth() ||
- Result->isImage2dMSAATDepth())) {
+ (Result->isOCLImage2dArrayMSAADepthROType() ||
+ Result->isOCLImage2dArrayMSAADepthWOType() ||
+ Result->isOCLImage2dArrayMSAADepthRWType() ||
+ Result->isOCLImage2dArrayMSAAROType() ||
+ Result->isOCLImage2dArrayMSAARWType() ||
+ Result->isOCLImage2dArrayMSAAWOType() ||
+ Result->isOCLImage2dMSAADepthROType() ||
+ Result->isOCLImage2dMSAADepthRWType() ||
+ Result->isOCLImage2dMSAADepthWOType() ||
+ Result->isOCLImage2dMSAAROType() ||
+ Result->isOCLImage2dMSAARWType() ||
+ Result->isOCLImage2dMSAAWOType())) {
S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_requires_extension)
<< Result << "cl_khr_gl_msaa_sharing";
declarator.setInvalidType(true);
@@ -1539,6 +1621,16 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) {
}
break;
+#define GENERIC_IMAGE_TYPE(ImgType, Id) \
+ case DeclSpec::TST_##ImgType##_t: \
+ Result = llvm::StringSwitch<QualType>( \
+ getImageAccessAttrStr(DS.getAttributes().getList())) \
+ .Cases("write_only", "__write_only", Context.Id##WOTy) \
+ .Cases("read_write", "__read_write", Context.Id##RWTy) \
+ .Default(Context.Id##ROTy); \
+ break;
+#include "clang/Basic/OpenCLImageTypes.def"
+
case DeclSpec::TST_error:
Result = Context.IntTy;
declarator.setInvalidType(true);
@@ -1693,12 +1785,13 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
}
QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
- unsigned CVRA, const DeclSpec *DS) {
+ unsigned CVRAU, const DeclSpec *DS) {
if (T.isNull())
return QualType();
- // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic.
- unsigned CVR = CVRA & ~DeclSpec::TQ_atomic;
+ // Convert from DeclSpec::TQ to Qualifiers::TQ by just dropping TQ_atomic and
+ // TQ_unaligned;
+ unsigned CVR = CVRAU & ~(DeclSpec::TQ_atomic | DeclSpec::TQ_unaligned);
// C11 6.7.3/5:
// If the same qualifier appears more than once in the same
@@ -1708,7 +1801,7 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
// It's not specified what happens when the _Atomic qualifier is applied to
// a type specified with the _Atomic specifier, but we assume that this
// should be treated as if the _Atomic qualifier appeared multiple times.
- if (CVRA & DeclSpec::TQ_atomic && !T->isAtomicType()) {
+ if (CVRAU & DeclSpec::TQ_atomic && !T->isAtomicType()) {
// C11 6.7.3/5:
// If other qualifiers appear along with the _Atomic qualifier in a
// specifier-qualifier-list, the resulting type is the so-qualified
@@ -1725,7 +1818,9 @@ QualType Sema::BuildQualifiedType(QualType T, SourceLocation Loc,
return BuildQualifiedType(T, Loc, Split.Quals);
}
- return BuildQualifiedType(T, Loc, Qualifiers::fromCVRMask(CVR), DS);
+ Qualifiers Q = Qualifiers::fromCVRMask(CVR);
+ Q.setUnaligned(CVRAU & DeclSpec::TQ_unaligned);
+ return BuildQualifiedType(T, Loc, Q, DS);
}
/// \brief Build a paren type including \p T.
@@ -1821,7 +1916,7 @@ namespace {
///
/// The values of this enum are used in diagnostics.
enum QualifiedFunctionKind { QFK_BlockPointer, QFK_Pointer, QFK_Reference };
-}
+} // end anonymous namespace
/// Check whether the type T is a qualified function type, and if it is,
/// diagnose that it cannot be contained within the given kind of declarator.
@@ -1968,10 +2063,10 @@ static bool isArraySizeVLA(Sema &S, Expr *ArraySize, llvm::APSInt &SizeVal) {
} Diagnoser;
return S.VerifyIntegerConstantExpression(ArraySize, &SizeVal, Diagnoser,
- S.LangOpts.GNUMode).isInvalid();
+ S.LangOpts.GNUMode ||
+ S.LangOpts.OpenCL).isInvalid();
}
-
/// \brief Build an array type.
///
/// \param T The type of each element in the array.
@@ -2150,15 +2245,8 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
// If this is not C99, extwarn about VLA's and C99 array size modifiers.
if (!getLangOpts().C99) {
if (T->isVariableArrayType()) {
- // Prohibit the use of non-POD types in VLAs.
- QualType BaseT = Context.getBaseElementType(T);
- if (!T->isDependentType() && isCompleteType(Loc, BaseT) &&
- !BaseT.isPODType(Context) && !BaseT->isObjCLifetimeType()) {
- Diag(Loc, diag::err_vla_non_pod) << BaseT;
- return QualType();
- }
// Prohibit the use of VLAs during template argument deduction.
- else if (isSFINAEContext()) {
+ if (isSFINAEContext()) {
Diag(Loc, diag::err_vla_in_sfinae);
return QualType();
}
@@ -2176,6 +2264,18 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
Diag(Loc, diag::warn_vla_used);
}
+ // OpenCL v2.0 s6.12.5 - Arrays of blocks are not supported.
+ // OpenCL v2.0 s6.16.13.1 - Arrays of pipe type are not supported.
+ // OpenCL v2.0 s6.9.b - Arrays of image/sampler type are not supported.
+ if (getLangOpts().OpenCL) {
+ const QualType ArrType = Context.getBaseElementType(T);
+ if (ArrType->isBlockPointerType() || ArrType->isPipeType() ||
+ ArrType->isSamplerT() || ArrType->isImageType()) {
+ Diag(Loc, diag::err_opencl_invalid_type_array) << ArrType;
+ return QualType();
+ }
+ }
+
return T;
}
@@ -2184,10 +2284,16 @@ QualType Sema::BuildArrayType(QualType T, ArrayType::ArraySizeModifier ASM,
/// Run the required checks for the extended vector type.
QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
SourceLocation AttrLoc) {
- // unlike gcc's vector_size attribute, we do not allow vectors to be defined
+ // Unlike gcc's vector_size attribute, we do not allow vectors to be defined
// in conjunction with complex types (pointers, arrays, functions, etc.).
- if (!T->isDependentType() &&
- !T->isIntegerType() && !T->isRealFloatingType()) {
+ //
+ // Additionally, OpenCL prohibits vectors of booleans (they're considered a
+ // reserved data type under OpenCL v2.0 s6.1.4), we don't support selects
+ // on bitvectors, and we have no well-defined ABI for bitvectors, so vectors
+ // of bool aren't allowed.
+ if ((!T->isDependentType() && !T->isIntegerType() &&
+ !T->isRealFloatingType()) ||
+ T->isBooleanType()) {
Diag(AttrLoc, diag::err_attribute_invalid_vector_type) << T;
return QualType();
}
@@ -2201,7 +2307,7 @@ QualType Sema::BuildExtVectorType(QualType T, Expr *ArraySize,
return QualType();
}
- // unlike gcc's vector_size attribute, the size is specified as the
+ // Unlike gcc's vector_size attribute, the size is specified as the
// number of elements, not the number of bytes.
unsigned vectorSize = static_cast<unsigned>(vecSize.getZExtValue());
@@ -2247,6 +2353,74 @@ bool Sema::CheckFunctionReturnType(QualType T, SourceLocation Loc) {
return false;
}
+/// Check the extended parameter information. Most of the necessary
+/// checking should occur when applying the parameter attribute; the
+/// only other checks required are positional restrictions.
+static void checkExtParameterInfos(Sema &S, ArrayRef<QualType> paramTypes,
+ const FunctionProtoType::ExtProtoInfo &EPI,
+ llvm::function_ref<SourceLocation(unsigned)> getParamLoc) {
+ assert(EPI.ExtParameterInfos && "shouldn't get here without param infos");
+
+ bool hasCheckedSwiftCall = false;
+ auto checkForSwiftCC = [&](unsigned paramIndex) {
+ // Only do this once.
+ if (hasCheckedSwiftCall) return;
+ hasCheckedSwiftCall = true;
+ if (EPI.ExtInfo.getCC() == CC_Swift) return;
+ S.Diag(getParamLoc(paramIndex), diag::err_swift_param_attr_not_swiftcall)
+ << getParameterABISpelling(EPI.ExtParameterInfos[paramIndex].getABI());
+ };
+
+ for (size_t paramIndex = 0, numParams = paramTypes.size();
+ paramIndex != numParams; ++paramIndex) {
+ switch (EPI.ExtParameterInfos[paramIndex].getABI()) {
+ // Nothing interesting to check for orindary-ABI parameters.
+ case ParameterABI::Ordinary:
+ continue;
+
+ // swift_indirect_result parameters must be a prefix of the function
+ // arguments.
+ case ParameterABI::SwiftIndirectResult:
+ checkForSwiftCC(paramIndex);
+ if (paramIndex != 0 &&
+ EPI.ExtParameterInfos[paramIndex - 1].getABI()
+ != ParameterABI::SwiftIndirectResult) {
+ S.Diag(getParamLoc(paramIndex),
+ diag::err_swift_indirect_result_not_first);
+ }
+ continue;
+
+ // swift_context parameters must be the last parameter except for
+ // a possible swift_error parameter.
+ case ParameterABI::SwiftContext:
+ checkForSwiftCC(paramIndex);
+ if (!(paramIndex == numParams - 1 ||
+ (paramIndex == numParams - 2 &&
+ EPI.ExtParameterInfos[numParams - 1].getABI()
+ == ParameterABI::SwiftErrorResult))) {
+ S.Diag(getParamLoc(paramIndex),
+ diag::err_swift_context_not_before_swift_error_result);
+ }
+ continue;
+
+ // swift_error parameters must be the last parameter.
+ case ParameterABI::SwiftErrorResult:
+ checkForSwiftCC(paramIndex);
+ if (paramIndex != numParams - 1) {
+ S.Diag(getParamLoc(paramIndex),
+ diag::err_swift_error_result_not_last);
+ } else if (paramIndex == 0 ||
+ EPI.ExtParameterInfos[paramIndex - 1].getABI()
+ != ParameterABI::SwiftContext) {
+ S.Diag(getParamLoc(paramIndex),
+ diag::err_swift_error_result_not_after_swift_context);
+ }
+ continue;
+ }
+ llvm_unreachable("bad ABI kind");
+ }
+}
+
QualType Sema::BuildFunctionType(QualType T,
MutableArrayRef<QualType> ParamTypes,
SourceLocation Loc, DeclarationName Entity,
@@ -2271,6 +2445,11 @@ QualType Sema::BuildFunctionType(QualType T,
ParamTypes[Idx] = ParamType;
}
+ if (EPI.ExtParameterInfos) {
+ checkExtParameterInfos(*this, ParamTypes, EPI,
+ [=](unsigned i) { return Loc; });
+ }
+
if (Invalid)
return QualType();
@@ -2477,7 +2656,8 @@ void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals,
SourceLocation ConstQualLoc,
SourceLocation VolatileQualLoc,
SourceLocation RestrictQualLoc,
- SourceLocation AtomicQualLoc) {
+ SourceLocation AtomicQualLoc,
+ SourceLocation UnalignedQualLoc) {
if (!Quals)
return;
@@ -2485,26 +2665,27 @@ void Sema::diagnoseIgnoredQualifiers(unsigned DiagID, unsigned Quals,
const char *Name;
unsigned Mask;
SourceLocation Loc;
- } const QualKinds[4] = {
+ } const QualKinds[5] = {
{ "const", DeclSpec::TQ_const, ConstQualLoc },
{ "volatile", DeclSpec::TQ_volatile, VolatileQualLoc },
{ "restrict", DeclSpec::TQ_restrict, RestrictQualLoc },
+ { "__unaligned", DeclSpec::TQ_unaligned, UnalignedQualLoc },
{ "_Atomic", DeclSpec::TQ_atomic, AtomicQualLoc }
};
SmallString<32> QualStr;
unsigned NumQuals = 0;
SourceLocation Loc;
- FixItHint FixIts[4];
+ FixItHint FixIts[5];
// Build a string naming the redundant qualifiers.
- for (unsigned I = 0; I != 4; ++I) {
- if (Quals & QualKinds[I].Mask) {
+ for (auto &E : QualKinds) {
+ if (Quals & E.Mask) {
if (!QualStr.empty()) QualStr += ' ';
- QualStr += QualKinds[I].Name;
+ QualStr += E.Name;
// If we have a location for the qualifier, offer a fixit.
- SourceLocation QualLoc = QualKinds[I].Loc;
+ SourceLocation QualLoc = E.Loc;
if (QualLoc.isValid()) {
FixIts[NumQuals] = FixItHint::CreateRemoval(QualLoc);
if (Loc.isInvalid() ||
@@ -2550,7 +2731,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
SourceLocation::getFromRawEncoding(PTI.ConstQualLoc),
SourceLocation::getFromRawEncoding(PTI.VolatileQualLoc),
SourceLocation::getFromRawEncoding(PTI.RestrictQualLoc),
- SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc));
+ SourceLocation::getFromRawEncoding(PTI.AtomicQualLoc),
+ SourceLocation::getFromRawEncoding(PTI.UnalignedQualLoc));
return;
}
@@ -2586,7 +2768,8 @@ static void diagnoseRedundantReturnTypeQualifiers(Sema &S, QualType RetTy,
D.getDeclSpec().getConstSpecLoc(),
D.getDeclSpec().getVolatileSpecLoc(),
D.getDeclSpec().getRestrictSpecLoc(),
- D.getDeclSpec().getAtomicSpecLoc());
+ D.getDeclSpec().getAtomicSpecLoc(),
+ D.getDeclSpec().getUnalignedSpecLoc());
}
static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
@@ -2700,6 +2883,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::FileContext:
case Declarator::BlockContext:
case Declarator::ForContext:
+ case Declarator::InitStmtContext:
case Declarator::ConditionContext:
break;
case Declarator::CXXNewContext:
@@ -2785,6 +2969,7 @@ static QualType GetDeclSpecTypeForDeclarator(TypeProcessingState &state,
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
+ case Declarator::InitStmtContext:
case Declarator::BlockLiteralContext:
case Declarator::LambdaExprContext:
// C++11 [dcl.type]p3:
@@ -2940,6 +3125,26 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
unsigned ChunkIndex) {
assert(D.getTypeObject(ChunkIndex).Kind == DeclaratorChunk::Function);
+ // Check for an explicit CC attribute.
+ for (auto Attr = FTI.AttrList; Attr; Attr = Attr->getNext()) {
+ switch (Attr->getKind()) {
+ CALLING_CONV_ATTRS_CASELIST: {
+ // Ignore attributes that don't validate or can't apply to the
+ // function type. We'll diagnose the failure to apply them in
+ // handleFunctionTypeAttr.
+ CallingConv CC;
+ if (!S.CheckCallingConvAttr(*Attr, CC) &&
+ (!FTI.isVariadic || supportsVariadicCall(CC))) {
+ return CC;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+
bool IsCXXInstanceMethod = false;
if (S.getLangOpts().CPlusPlus) {
@@ -2979,15 +3184,19 @@ getCCForDeclaratorChunk(Sema &S, Declarator &D,
CallingConv CC = S.Context.getDefaultCallingConvention(FTI.isVariadic,
IsCXXInstanceMethod);
- // Attribute AT_OpenCLKernel affects the calling convention only on
- // the SPIR target, hence it cannot be treated as a calling
+ // Attribute AT_OpenCLKernel affects the calling convention for SPIR
+ // and AMDGPU targets, hence it cannot be treated as a calling
// convention attribute. This is the simplest place to infer
- // "spir_kernel" for OpenCL kernels on SPIR.
- if (CC == CC_SpirFunction) {
+ // calling convention for OpenCL kernels.
+ if (S.getLangOpts().OpenCL) {
for (const AttributeList *Attr = D.getDeclSpec().getAttributes().getList();
Attr; Attr = Attr->getNext()) {
if (Attr->getKind() == AttributeList::AT_OpenCLKernel) {
- CC = CC_SpirKernel;
+ llvm::Triple::ArchType arch = S.Context.getTargetInfo().getTriple().getArch();
+ if (arch == llvm::Triple::spir || arch == llvm::Triple::spir64 ||
+ arch == llvm::Triple::amdgcn) {
+ CC = CC_OpenCLKernel;
+ }
break;
}
}
@@ -3004,7 +3213,7 @@ namespace {
BlockPointer,
MemberPointer,
};
-}
+} // end anonymous namespace
IdentifierInfo *Sema::getNullabilityKeyword(NullabilityKind nullability) {
switch (nullability) {
@@ -3064,7 +3273,7 @@ namespace {
// NSError**
NSErrorPointerPointer,
};
-}
+} // end anonymous namespace
/// Classify the given declarator, whose type-specified is \c type, based on
/// what kind of pointer it refers to.
@@ -3192,7 +3401,6 @@ static PointerDeclaratorKind classifyPointerDeclarator(Sema &S,
break;
} while (true);
-
switch (numNormalPointers) {
case 0:
return PointerDeclaratorKind::NonPointer;
@@ -3509,6 +3717,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::CXXCatchContext:
case Declarator::CXXNewContext:
case Declarator::ForContext:
+ case Declarator::InitStmtContext:
case Declarator::LambdaExprContext:
case Declarator::LambdaExprParameterContext:
case Declarator::ObjCCatchContext:
@@ -3609,15 +3818,20 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case DeclaratorChunk::BlockPointer:
// If blocks are disabled, emit an error.
if (!LangOpts.Blocks)
- S.Diag(DeclType.Loc, diag::err_blocks_disable);
+ S.Diag(DeclType.Loc, diag::err_blocks_disable) << LangOpts.OpenCL;
// Handle pointer nullability.
inferPointerNullability(SimplePointerKind::BlockPointer,
DeclType.Loc, DeclType.getAttrListRef());
T = S.BuildBlockPointerType(T, D.getIdentifierLoc(), Name);
- if (DeclType.Cls.TypeQuals)
+ if (DeclType.Cls.TypeQuals || LangOpts.OpenCL) {
+ // OpenCL v2.0, s6.12.5 - Block variable declarations are implicitly
+ // qualified with const.
+ if (LangOpts.OpenCL)
+ DeclType.Cls.TypeQuals |= DeclSpec::TQ_const;
T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Cls.TypeQuals);
+ }
break;
case DeclaratorChunk::Pointer:
// Verify that we're not building a pointer to pointer to function with
@@ -3638,10 +3852,21 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
break;
}
+
+ // OpenCL v2.0 s6.9b - Pointer to image/sampler cannot be used.
+ // OpenCL v2.0 s6.13.16.1 - Pointer to pipe cannot be used.
+ // OpenCL v2.0 s6.12.5 - Pointers to Blocks are not allowed.
+ if (LangOpts.OpenCL) {
+ if (T->isImageType() || T->isSamplerT() || T->isPipeType() ||
+ T->isBlockPointerType()) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_pointer_to_type) << T;
+ D.setInvalidType(true);
+ }
+ }
+
T = S.BuildPointerType(T, DeclType.Loc, Name);
if (DeclType.Ptr.TypeQuals)
T = S.BuildQualifiedType(T, DeclType.Loc, DeclType.Ptr.TypeQuals);
-
break;
case DeclaratorChunk::Reference: {
// Verify that we're not building a reference to pointer to function with
@@ -3808,7 +4033,8 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
if (T->isHalfType()) {
if (S.getLangOpts().OpenCL) {
if (!S.getOpenCLOptions().cl_khr_fp16) {
- S.Diag(D.getIdentifierLoc(), diag::err_opencl_half_return) << T;
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+ << T << 0 /*pointer hint*/;
D.setInvalidType(true);
}
} else if (!S.getLangOpts().HalfArgsAndReturns) {
@@ -3818,6 +4044,15 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
+ // OpenCL v2.0 s6.12.5 - A block cannot be the return value of a
+ // function.
+ if (LangOpts.OpenCL && (T->isBlockPointerType() || T->isImageType() ||
+ T->isSamplerT() || T->isPipeType())) {
+ S.Diag(D.getIdentifierLoc(), diag::err_opencl_invalid_return)
+ << T << 1 /*hint off*/;
+ D.setInvalidType(true);
+ }
+
// Methods cannot return interface types. All ObjC objects are
// passed by reference.
if (T->isObjCObjectType()) {
@@ -3967,9 +4202,9 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
SmallVector<QualType, 16> ParamTys;
ParamTys.reserve(FTI.NumParams);
- SmallVector<bool, 16> ConsumedParameters;
- ConsumedParameters.reserve(FTI.NumParams);
- bool HasAnyConsumedParameters = false;
+ SmallVector<FunctionProtoType::ExtParameterInfo, 16>
+ ExtParameterInfos(FTI.NumParams);
+ bool HasAnyInterestingExtParameterInfos = false;
for (unsigned i = 0, e = FTI.NumParams; i != e; ++i) {
ParmVarDecl *Param = cast<ParmVarDecl>(FTI.Params[i].Param);
@@ -4027,17 +4262,25 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
}
}
- if (LangOpts.ObjCAutoRefCount) {
- bool Consumed = Param->hasAttr<NSConsumedAttr>();
- ConsumedParameters.push_back(Consumed);
- HasAnyConsumedParameters |= Consumed;
+ if (LangOpts.ObjCAutoRefCount && Param->hasAttr<NSConsumedAttr>()) {
+ ExtParameterInfos[i] = ExtParameterInfos[i].withIsConsumed(true);
+ HasAnyInterestingExtParameterInfos = true;
+ }
+
+ if (auto attr = Param->getAttr<ParameterABIAttr>()) {
+ ExtParameterInfos[i] =
+ ExtParameterInfos[i].withABI(attr->getABI());
+ HasAnyInterestingExtParameterInfos = true;
}
ParamTys.push_back(ParamTy);
}
- if (HasAnyConsumedParameters)
- EPI.ConsumedParameters = ConsumedParameters.data();
+ if (HasAnyInterestingExtParameterInfos) {
+ EPI.ExtParameterInfos = ExtParameterInfos.data();
+ checkExtParameterInfos(S, ParamTys, EPI,
+ [&](unsigned i) { return FTI.Params[i].Param->getLocation(); });
+ }
SmallVector<QualType, 4> Exceptions;
SmallVector<ParsedType, 2> DynamicExceptions;
@@ -4068,7 +4311,6 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
T = Context.getFunctionType(T, ParamTys, EPI);
}
-
break;
}
case DeclaratorChunk::MemberPointer: {
@@ -4306,6 +4548,7 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
case Declarator::MemberContext:
case Declarator::BlockContext:
case Declarator::ForContext:
+ case Declarator::InitStmtContext:
case Declarator::ConditionContext:
case Declarator::CXXCatchContext:
case Declarator::ObjCCatchContext:
@@ -4497,6 +4740,8 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_ThisCall;
case AttributedType::attr_pascal:
return AttributeList::AT_Pascal;
+ case AttributedType::attr_swiftcall:
+ return AttributeList::AT_SwiftCall;
case AttributedType::attr_vectorcall:
return AttributeList::AT_VectorCall;
case AttributedType::attr_pcs:
@@ -4508,6 +4753,10 @@ static AttributeList::Kind getAttrListKind(AttributedType::Kind kind) {
return AttributeList::AT_MSABI;
case AttributedType::attr_sysv_abi:
return AttributeList::AT_SysVABI;
+ case AttributedType::attr_preserve_most:
+ return AttributeList::AT_PreserveMost;
+ case AttributedType::attr_preserve_all:
+ return AttributeList::AT_PreserveAll;
case AttributedType::attr_ptr32:
return AttributeList::AT_Ptr32;
case AttributedType::attr_ptr64:
@@ -4725,7 +4974,7 @@ namespace {
void VisitPipeTypeLoc(PipeTypeLoc TL) {
TL.setKWLoc(DS.getTypeSpecTypeLoc());
- TypeSourceInfo *TInfo = 0;
+ TypeSourceInfo *TInfo = nullptr;
Sema::GetTypeFromParser(DS.getRepAsType(), &TInfo);
TL.getValueLoc().initializeFullCopy(TInfo->getTypeLoc());
}
@@ -4859,7 +5108,7 @@ namespace {
llvm_unreachable("unsupported TypeLoc kind in declarator!");
}
};
-}
+} // end anonymous namespace
static void fillAtomicQualLoc(AtomicTypeLoc ATL, const DeclaratorChunk &Chunk) {
SourceLocation Loc;
@@ -4995,7 +5244,6 @@ ParsedType Sema::ActOnObjCInstanceType(SourceLocation Loc) {
return CreateParsedType(T, TInfo);
}
-
//===----------------------------------------------------------------------===//
// Type Attribute Processing
//===----------------------------------------------------------------------===//
@@ -5194,11 +5442,13 @@ static bool handleObjCOwnershipTypeAttr(TypeProcessingState &state,
}
// Otherwise, if the qualifiers actually conflict, pull sugar off
- // until we reach a type that is directly qualified.
+ // and remove the ObjCLifetime qualifiers.
if (previousLifetime != lifetime) {
- // This should always terminate: the canonical type is
- // qualified, so some bit of sugar must be hiding it.
- while (!underlyingType.Quals.hasObjCLifetime()) {
+ // It's possible to have multiple local ObjCLifetime qualifiers. We
+ // can't stop after we reach a type that is directly qualified.
+ const Type *prevTy = nullptr;
+ while (!prevTy || prevTy != underlyingType.Ty) {
+ prevTy = underlyingType.Ty;
underlyingType = underlyingType.getSingleStepDesugaredType();
}
underlyingType.Quals.removeObjCLifetime();
@@ -5369,6 +5619,7 @@ namespace {
struct FunctionTypeUnwrapper {
enum WrapKind {
Desugar,
+ Attributed,
Parens,
Pointer,
BlockPointer,
@@ -5401,6 +5652,9 @@ namespace {
} else if (isa<ReferenceType>(Ty)) {
T = cast<ReferenceType>(Ty)->getPointeeType();
Stack.push_back(Reference);
+ } else if (isa<AttributedType>(Ty)) {
+ T = cast<AttributedType>(Ty)->getEquivalentType();
+ Stack.push_back(Attributed);
} else {
const Type *DTy = Ty->getUnqualifiedDesugaredType();
if (Ty == DTy) {
@@ -5449,6 +5703,9 @@ namespace {
// information.
return wrap(C, Old->getUnqualifiedDesugaredType(), I);
+ case Attributed:
+ return wrap(C, cast<AttributedType>(Old)->getEquivalentType(), I);
+
case Parens: {
QualType New = wrap(C, cast<ParenType>(Old)->getInnerType(), I);
return C.getParenType(New);
@@ -5483,7 +5740,7 @@ namespace {
llvm_unreachable("unknown wrapping kind");
}
};
-}
+} // end anonymous namespace
static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
AttributeList &Attr,
@@ -5672,10 +5929,11 @@ bool Sema::checkObjCKindOfType(QualType &type, SourceLocation loc) {
// Rebuild the "equivalent" type, which pushes __kindof down into
// the object type.
- QualType equivType = Context.getObjCObjectType(objType->getBaseType(),
- objType->getTypeArgsAsWritten(),
- objType->getProtocols(),
- /*isKindOf=*/true);
+ // There is no need to apply kindof on an unqualified id type.
+ QualType equivType = Context.getObjCObjectType(
+ objType->getBaseType(), objType->getTypeArgsAsWritten(),
+ objType->getProtocols(),
+ /*isKindOf=*/objType->isObjCUnqualifiedId() ? false : true);
// If we started with an object pointer type, rebuild it.
if (ptrType) {
@@ -5814,6 +6072,8 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
return AttributedType::attr_thiscall;
case AttributeList::AT_Pascal:
return AttributedType::attr_pascal;
+ case AttributeList::AT_SwiftCall:
+ return AttributedType::attr_swiftcall;
case AttributeList::AT_VectorCall:
return AttributedType::attr_vectorcall;
case AttributeList::AT_Pcs: {
@@ -5835,6 +6095,10 @@ static AttributedType::Kind getCCTypeAttrKind(AttributeList &Attr) {
return AttributedType::attr_ms_abi;
case AttributeList::AT_SysVABI:
return AttributedType::attr_sysv_abi;
+ case AttributeList::AT_PreserveMost:
+ return AttributedType::attr_preserve_most;
+ case AttributeList::AT_PreserveAll:
+ return AttributedType::attr_preserve_all;
}
llvm_unreachable("unexpected attribute kind!");
}
@@ -5930,18 +6194,28 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
}
}
- // Diagnose use of callee-cleanup calling convention on variadic functions.
+ // Diagnose use of variadic functions with calling conventions that
+ // don't support them (e.g. because they're callee-cleanup).
+ // We delay warning about this on unprototyped function declarations
+ // until after redeclaration checking, just in case we pick up a
+ // prototype that way. And apparently we also "delay" warning about
+ // unprototyped function types in general, despite not necessarily having
+ // much ability to diagnose it later.
if (!supportsVariadicCall(CC)) {
const FunctionProtoType *FnP = dyn_cast<FunctionProtoType>(fn);
if (FnP && FnP->isVariadic()) {
unsigned DiagID = diag::err_cconv_varargs;
+
// stdcall and fastcall are ignored with a warning for GCC and MS
// compatibility.
- if (CC == CC_X86StdCall || CC == CC_X86FastCall)
+ bool IsInvalid = true;
+ if (CC == CC_X86StdCall || CC == CC_X86FastCall) {
DiagID = diag::warn_cconv_varargs;
+ IsInvalid = false;
+ }
S.Diag(attr.getLoc(), DiagID) << FunctionType::getNameForCallConv(CC);
- attr.setInvalid();
+ if (IsInvalid) attr.setInvalid();
return true;
}
}
@@ -5957,9 +6231,14 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state,
// Modify the CC from the wrapped function type, wrap it all back, and then
// wrap the whole thing in an AttributedType as written. The modified type
// might have a different CC if we ignored the attribute.
- FunctionType::ExtInfo EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
- QualType Equivalent =
+ QualType Equivalent;
+ if (CCOld == CC) {
+ Equivalent = type;
+ } else {
+ auto EI = unwrapped.get()->getExtInfo().withCallingConv(CC);
+ Equivalent =
unwrapped.wrap(S, S.Context.adjustFunctionType(unwrapped.get(), EI));
+ }
type = S.Context.getAttributedType(CCAttrKind, type, Equivalent);
return true;
}
@@ -6217,6 +6496,36 @@ static void HandleNeonVectorTypeAttr(QualType& CurType,
CurType = S.Context.getVectorType(CurType, numElts, VecKind);
}
+/// Handle OpenCL Access Qualifier Attribute.
+static void HandleOpenCLAccessAttr(QualType &CurType, const AttributeList &Attr,
+ Sema &S) {
+ // OpenCL v2.0 s6.6 - Access qualifier can be used only for image and pipe type.
+ if (!(CurType->isImageType() || CurType->isPipeType())) {
+ S.Diag(Attr.getLoc(), diag::err_opencl_invalid_access_qualifier);
+ Attr.setInvalid();
+ return;
+ }
+
+ if (const TypedefType* TypedefTy = CurType->getAs<TypedefType>()) {
+ QualType PointeeTy = TypedefTy->desugar();
+ S.Diag(Attr.getLoc(), diag::err_opencl_multiple_access_qualifiers);
+
+ std::string PrevAccessQual;
+ switch (cast<BuiltinType>(PointeeTy.getTypePtr())->getKind()) {
+ #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id: \
+ PrevAccessQual = #Access; \
+ break;
+ #include "clang/Basic/OpenCLImageTypes.def"
+ default:
+ assert(0 && "Unable to find corresponding image type.");
+ }
+
+ S.Diag(TypedefTy->getDecl()->getLocStart(),
+ diag::note_opencl_typedef_access_qualifier) << PrevAccessQual;
+ }
+}
+
static void processTypeAttrs(TypeProcessingState &state, QualType &type,
TypeAttrLocation TAL, AttributeList *attrs) {
// Scan through and apply attributes to this type where it makes sense. Some
@@ -6312,9 +6621,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
VectorType::NeonPolyVector);
attr.setUsedAsTypeAttr();
break;
- case AttributeList::AT_OpenCLImageAccess:
- // FIXME: there should be some type checking happening here, I would
- // imagine, but the original handler's checking was entirely superfluous.
+ case AttributeList::AT_OpenCLAccess:
+ HandleOpenCLAccessAttr(type, attr, state.getSema());
attr.setUsedAsTypeAttr();
break;
@@ -6554,8 +6862,8 @@ bool Sema::hasVisibleDefinition(NamedDecl *D, NamedDecl **Suggested,
RD = Pattern;
D = RD->getDefinition();
} else if (auto *ED = dyn_cast<EnumDecl>(D)) {
- while (auto *NewED = ED->getInstantiatedFromMemberEnum())
- ED = NewED;
+ if (auto *Pattern = ED->getTemplateInstantiationPattern())
+ ED = Pattern;
if (OnlyNeedComplete && ED->isFixed()) {
// If the enum has a fixed underlying type, and we're only looking for a
// complete type (not a definition), any visible declaration of it will
@@ -6616,6 +6924,7 @@ static void assignInheritanceModel(Sema &S, CXXRecordDecl *RD) {
S.ImplicitMSInheritanceAttrLoc.isValid()
? S.ImplicitMSInheritanceAttrLoc
: RD->getSourceRange()));
+ S.Consumer.AssignInheritanceModel(RD);
}
}
@@ -6641,9 +6950,16 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
}
}
- // If we have a complete type, we're done.
NamedDecl *Def = nullptr;
- if (!T->isIncompleteType(&Def)) {
+ bool Incomplete = T->isIncompleteType(&Def);
+
+ // Check that any necessary explicit specializations are visible. For an
+ // enum, we just need the declaration, so don't check this.
+ if (Def && !isa<EnumDecl>(Def))
+ checkSpecializationVisibility(Loc, Def);
+
+ // If we have a complete type, we're done.
+ if (!Incomplete) {
// If we know about the definition but it is not visible, complain.
NamedDecl *SuggestedDef = nullptr;
if (Def &&
@@ -6652,7 +6968,7 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
// definition visible.
bool TreatAsComplete = Diagnoser && !isSFINAEContext();
if (Diagnoser)
- diagnoseMissingImport(Loc, SuggestedDef, /*NeedDefinition*/true,
+ diagnoseMissingImport(Loc, SuggestedDef, MissingImportKind::Definition,
/*Recover*/TreatAsComplete);
return !TreatAsComplete;
}
@@ -6745,15 +7061,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
}
}
- if (!Diagnoser)
- return true;
+ // FIXME: If we didn't instantiate a definition because of an explicit
+ // specialization declaration, check that it's visible.
- // We have an incomplete type. Produce a diagnostic.
- if (Ident___float128 &&
- T == Context.getTypeDeclType(Context.getFloat128StubType())) {
- Diag(Loc, diag::err_typecheck_decl_incomplete_type___float128);
+ if (!Diagnoser)
return true;
- }
Diagnoser->diagnose(*this, Loc, T);
diff --git a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
index 935304fe4076..36859f61d387 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
+++ b/contrib/llvm/tools/clang/lib/Sema/TreeTransform.h
@@ -410,6 +410,14 @@ public:
return D;
}
+ /// \brief Transform the specified condition.
+ ///
+ /// By default, this transforms the variable and expression and rebuilds
+ /// the condition.
+ Sema::ConditionResult TransformCondition(SourceLocation Loc, VarDecl *Var,
+ Expr *Expr,
+ Sema::ConditionKind Kind);
+
/// \brief Transform the attributes associated with the given declaration and
/// place them on the new declaration.
///
@@ -604,11 +612,12 @@ public:
/// variables vector are acceptable.
///
/// Return true on error.
- bool TransformFunctionTypeParams(SourceLocation Loc,
- ParmVarDecl **Params, unsigned NumParams,
- const QualType *ParamTypes,
- SmallVectorImpl<QualType> &PTypes,
- SmallVectorImpl<ParmVarDecl*> *PVars);
+ bool TransformFunctionTypeParams(
+ SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
+ const QualType *ParamTypes,
+ const FunctionProtoType::ExtParameterInfo *ParamInfos,
+ SmallVectorImpl<QualType> &PTypes, SmallVectorImpl<ParmVarDecl *> *PVars,
+ Sema::ExtParameterInfoBuilder &PInfos);
/// \brief Transforms a single function-type parameter. Return null
/// on error.
@@ -1164,20 +1173,20 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildIfStmt(SourceLocation IfLoc, Sema::FullExprArg Cond,
- VarDecl *CondVar, Stmt *Then,
+ StmtResult RebuildIfStmt(SourceLocation IfLoc, bool IsConstexpr,
+ Sema::ConditionResult Cond, Stmt *Init, Stmt *Then,
SourceLocation ElseLoc, Stmt *Else) {
- return getSema().ActOnIfStmt(IfLoc, Cond, CondVar, Then, ElseLoc, Else);
+ return getSema().ActOnIfStmt(IfLoc, IsConstexpr, Init, Cond, Then,
+ ElseLoc, Else);
}
/// \brief Start building a new switch statement.
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc,
- Expr *Cond, VarDecl *CondVar) {
- return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Cond,
- CondVar);
+ StmtResult RebuildSwitchStmtStart(SourceLocation SwitchLoc, Stmt *Init,
+ Sema::ConditionResult Cond) {
+ return getSema().ActOnStartOfSwitchStmt(SwitchLoc, Init, Cond);
}
/// \brief Attach the body to the switch statement.
@@ -1193,9 +1202,9 @@ public:
///
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
- StmtResult RebuildWhileStmt(SourceLocation WhileLoc, Sema::FullExprArg Cond,
- VarDecl *CondVar, Stmt *Body) {
- return getSema().ActOnWhileStmt(WhileLoc, Cond, CondVar, Body);
+ StmtResult RebuildWhileStmt(SourceLocation WhileLoc,
+ Sema::ConditionResult Cond, Stmt *Body) {
+ return getSema().ActOnWhileStmt(WhileLoc, Cond, Body);
}
/// \brief Build a new do-while statement.
@@ -1214,11 +1223,11 @@ public:
/// By default, performs semantic analysis to build the new statement.
/// Subclasses may override this routine to provide different behavior.
StmtResult RebuildForStmt(SourceLocation ForLoc, SourceLocation LParenLoc,
- Stmt *Init, Sema::FullExprArg Cond,
- VarDecl *CondVar, Sema::FullExprArg Inc,
- SourceLocation RParenLoc, Stmt *Body) {
+ Stmt *Init, Sema::ConditionResult Cond,
+ Sema::FullExprArg Inc, SourceLocation RParenLoc,
+ Stmt *Body) {
return getSema().ActOnForStmt(ForLoc, LParenLoc, Init, Cond,
- CondVar, Inc, RParenLoc, Body);
+ Inc, RParenLoc, Body);
}
/// \brief Build a new goto statement.
@@ -1559,10 +1568,11 @@ public:
SourceLocation ColonLoc,
SourceLocation EndLoc,
CXXScopeSpec &ReductionIdScopeSpec,
- const DeclarationNameInfo &ReductionId) {
+ const DeclarationNameInfo &ReductionId,
+ ArrayRef<Expr *> UnresolvedReductions) {
return getSema().ActOnOpenMPReductionClause(
VarList, StartLoc, LParenLoc, ColonLoc, EndLoc, ReductionIdScopeSpec,
- ReductionId);
+ ReductionId, UnresolvedReductions);
}
/// \brief Build a new OpenMP 'linear' clause.
@@ -1658,14 +1668,15 @@ public:
///
/// By default, performs semantic analysis to build the new OpenMP clause.
/// Subclasses may override this routine to provide different behavior.
- OMPClause *RebuildOMPMapClause(
- OpenMPMapClauseKind MapTypeModifier, OpenMPMapClauseKind MapType,
- SourceLocation MapLoc, SourceLocation ColonLoc, ArrayRef<Expr *> VarList,
- SourceLocation StartLoc, SourceLocation LParenLoc,
- SourceLocation EndLoc) {
- return getSema().ActOnOpenMPMapClause(MapTypeModifier, MapType, MapLoc,
- ColonLoc, VarList,StartLoc,
- LParenLoc, EndLoc);
+ OMPClause *
+ RebuildOMPMapClause(OpenMPMapClauseKind MapTypeModifier,
+ OpenMPMapClauseKind MapType, bool IsMapTypeImplicit,
+ SourceLocation MapLoc, SourceLocation ColonLoc,
+ ArrayRef<Expr *> VarList, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPMapClause(MapTypeModifier, MapType,
+ IsMapTypeImplicit, MapLoc, ColonLoc,
+ VarList, StartLoc, LParenLoc, EndLoc);
}
/// \brief Build a new OpenMP 'num_teams' clause.
@@ -1734,6 +1745,66 @@ public:
return getSema().ActOnOpenMPHintClause(Hint, StartLoc, LParenLoc, EndLoc);
}
+ /// \brief Build a new OpenMP 'dist_schedule' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *
+ RebuildOMPDistScheduleClause(OpenMPDistScheduleClauseKind Kind,
+ Expr *ChunkSize, SourceLocation StartLoc,
+ SourceLocation LParenLoc, SourceLocation KindLoc,
+ SourceLocation CommaLoc, SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPDistScheduleClause(
+ Kind, ChunkSize, StartLoc, LParenLoc, KindLoc, CommaLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'to' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPToClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPToClause(VarList, StartLoc, LParenLoc, EndLoc);
+ }
+
+ /// \brief Build a new OpenMP 'from' clause.
+ ///
+ /// By default, performs semantic analysis to build the new statement.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPFromClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPFromClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'use_device_ptr' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPUseDevicePtrClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPUseDevicePtrClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
+ /// Build a new OpenMP 'is_device_ptr' clause.
+ ///
+ /// By default, performs semantic analysis to build the new OpenMP clause.
+ /// Subclasses may override this routine to provide different behavior.
+ OMPClause *RebuildOMPIsDevicePtrClause(ArrayRef<Expr *> VarList,
+ SourceLocation StartLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ return getSema().ActOnOpenMPIsDevicePtrClause(VarList, StartLoc, LParenLoc,
+ EndLoc);
+ }
+
/// \brief Rebuild the operand to an Objective-C \@synchronized statement.
///
/// By default, performs semantic analysis to build the new statement.
@@ -1823,7 +1894,7 @@ public:
StmtResult RebuildCXXForRangeStmt(SourceLocation ForLoc,
SourceLocation CoawaitLoc,
SourceLocation ColonLoc,
- Stmt *Range, Stmt *BeginEnd,
+ Stmt *Range, Stmt *Begin, Stmt *End,
Expr *Cond, Expr *Inc,
Stmt *LoopVar,
SourceLocation RParenLoc) {
@@ -1845,7 +1916,7 @@ public:
}
return getSema().BuildCXXForRangeStmt(ForLoc, CoawaitLoc, ColonLoc,
- Range, BeginEnd,
+ Range, Begin, End,
Cond, Inc, LoopVar, RParenLoc,
Sema::BFRK_Rebuild);
}
@@ -2634,7 +2705,8 @@ public:
ConvertedArgs))
return ExprError();
- return getSema().BuildCXXConstructExpr(Loc, T, Constructor, IsElidable,
+ return getSema().BuildCXXConstructExpr(Loc, T, Constructor,
+ IsElidable,
ConvertedArgs,
HadMultipleCandidates,
ListInitialization,
@@ -2643,6 +2715,16 @@ public:
ParenRange);
}
+ /// \brief Build a new implicit construction via inherited constructor
+ /// expression.
+ ExprResult RebuildCXXInheritedCtorInitExpr(QualType T, SourceLocation Loc,
+ CXXConstructorDecl *Constructor,
+ bool ConstructsVBase,
+ bool InheritedFromVBase) {
+ return new (getSema().Context) CXXInheritedCtorInitExpr(
+ Loc, T, Constructor, ConstructsVBase, InheritedFromVBase);
+ }
+
/// \brief Build a new object-construction expression.
///
/// By default, performs semantic analysis to build the new expression.
@@ -3269,8 +3351,6 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
if (Out.isInvalid())
return true;
- // FIXME: Can this happen? We should not try to expand the pack
- // in this case.
if (Out.get()->containsUnexpandedParameterPack()) {
Out = getDerived().RebuildPackExpansion(
Out.get(), Expansion->getEllipsisLoc(), OrigNumExpansions);
@@ -3316,6 +3396,31 @@ bool TreeTransform<Derived>::TransformExprs(Expr *const *Inputs,
return false;
}
+template <typename Derived>
+Sema::ConditionResult TreeTransform<Derived>::TransformCondition(
+ SourceLocation Loc, VarDecl *Var, Expr *Expr, Sema::ConditionKind Kind) {
+ if (Var) {
+ VarDecl *ConditionVar = cast_or_null<VarDecl>(
+ getDerived().TransformDefinition(Var->getLocation(), Var));
+
+ if (!ConditionVar)
+ return Sema::ConditionError();
+
+ return getSema().ActOnConditionVariable(ConditionVar, Loc, Kind);
+ }
+
+ if (Expr) {
+ ExprResult CondExpr = getDerived().TransformExpr(Expr);
+
+ if (CondExpr.isInvalid())
+ return Sema::ConditionError();
+
+ return getSema().ActOnCondition(nullptr, Loc, CondExpr.get(), Kind);
+ }
+
+ return Sema::ConditionResult();
+}
+
template<typename Derived>
NestedNameSpecifierLoc
TreeTransform<Derived>::TransformNestedNameSpecifierLoc(
@@ -4590,15 +4695,17 @@ ParmVarDecl *TreeTransform<Derived>::TransformFunctionTypeParam(
return newParm;
}
-template<typename Derived>
-bool TreeTransform<Derived>::
- TransformFunctionTypeParams(SourceLocation Loc,
- ParmVarDecl **Params, unsigned NumParams,
- const QualType *ParamTypes,
- SmallVectorImpl<QualType> &OutParamTypes,
- SmallVectorImpl<ParmVarDecl*> *PVars) {
+template <typename Derived>
+bool TreeTransform<Derived>::TransformFunctionTypeParams(
+ SourceLocation Loc, ArrayRef<ParmVarDecl *> Params,
+ const QualType *ParamTypes,
+ const FunctionProtoType::ExtParameterInfo *ParamInfos,
+ SmallVectorImpl<QualType> &OutParamTypes,
+ SmallVectorImpl<ParmVarDecl *> *PVars,
+ Sema::ExtParameterInfoBuilder &PInfos) {
int indexAdjustment = 0;
+ unsigned NumParams = Params.size();
for (unsigned i = 0; i != NumParams; ++i) {
if (ParmVarDecl *OldParm = Params[i]) {
assert(OldParm->getFunctionScopeIndex() == i);
@@ -4645,6 +4752,8 @@ bool TreeTransform<Derived>::
if (!NewParm)
return true;
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4662,6 +4771,8 @@ bool TreeTransform<Derived>::
if (!NewParm)
return true;
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4692,6 +4803,8 @@ bool TreeTransform<Derived>::
if (!NewParm)
return true;
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewParm->getType());
if (PVars)
PVars->push_back(NewParm);
@@ -4731,6 +4844,16 @@ bool TreeTransform<Derived>::
if (NewType.isNull())
return true;
+ if (NewType->containsUnexpandedParameterPack()) {
+ NewType =
+ getSema().getASTContext().getPackExpansionType(NewType, None);
+
+ if (NewType.isNull())
+ return true;
+ }
+
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewType);
if (PVars)
PVars->push_back(nullptr);
@@ -4748,6 +4871,8 @@ bool TreeTransform<Derived>::
if (NewType.isNull())
return true;
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewType);
if (PVars)
PVars->push_back(nullptr);
@@ -4770,6 +4895,8 @@ bool TreeTransform<Derived>::
NewType = getSema().Context.getPackExpansionType(NewType,
NumExpansions);
+ if (ParamInfos)
+ PInfos.set(OutParamTypes.size(), ParamInfos[i]);
OutParamTypes.push_back(NewType);
if (PVars)
PVars->push_back(nullptr);
@@ -4804,6 +4931,7 @@ template<typename Derived> template<typename Fn>
QualType TreeTransform<Derived>::TransformFunctionProtoType(
TypeLocBuilder &TLB, FunctionProtoTypeLoc TL, CXXRecordDecl *ThisContext,
unsigned ThisTypeQuals, Fn TransformExceptionSpec) {
+
// Transform the parameters and return type.
//
// We are required to instantiate the params and return type in source order.
@@ -4813,14 +4941,17 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
//
SmallVector<QualType, 4> ParamTypes;
SmallVector<ParmVarDecl*, 4> ParamDecls;
+ Sema::ExtParameterInfoBuilder ExtParamInfos;
const FunctionProtoType *T = TL.getTypePtr();
QualType ResultType;
if (T->hasTrailingReturn()) {
if (getDerived().TransformFunctionTypeParams(
- TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(),
- TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls))
+ TL.getBeginLoc(), TL.getParams(),
+ TL.getTypePtr()->param_type_begin(),
+ T->getExtParameterInfosOrNull(),
+ ParamTypes, &ParamDecls, ExtParamInfos))
return QualType();
{
@@ -4843,8 +4974,10 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
return QualType();
if (getDerived().TransformFunctionTypeParams(
- TL.getBeginLoc(), TL.getParmArray(), TL.getNumParams(),
- TL.getTypePtr()->param_type_begin(), ParamTypes, &ParamDecls))
+ TL.getBeginLoc(), TL.getParams(),
+ TL.getTypePtr()->param_type_begin(),
+ T->getExtParameterInfosOrNull(),
+ ParamTypes, &ParamDecls, ExtParamInfos))
return QualType();
}
@@ -4854,8 +4987,19 @@ QualType TreeTransform<Derived>::TransformFunctionProtoType(
if (TransformExceptionSpec(EPI.ExceptionSpec, EPIChanged))
return QualType();
- // FIXME: Need to transform ConsumedParameters for variadic template
- // expansion.
+ // Handle extended parameter information.
+ if (auto NewExtParamInfos =
+ ExtParamInfos.getPointerOrNull(ParamTypes.size())) {
+ if (!EPI.ExtParameterInfos ||
+ llvm::makeArrayRef(EPI.ExtParameterInfos, TL.getNumParams())
+ != llvm::makeArrayRef(NewExtParamInfos, ParamTypes.size())) {
+ EPIChanged = true;
+ }
+ EPI.ExtParameterInfos = NewExtParamInfos;
+ } else if (EPI.ExtParameterInfos) {
+ EPIChanged = true;
+ EPI.ExtParameterInfos = nullptr;
+ }
QualType Result = TL.getType();
if (getDerived().AlwaysRebuild() || ResultType != T->getReturnType() ||
@@ -4890,8 +5034,8 @@ bool TreeTransform<Derived>::TransformExceptionSpec(
if (NoexceptExpr.isInvalid())
return true;
- NoexceptExpr = getSema().CheckBooleanCondition(
- NoexceptExpr.get(), NoexceptExpr.get()->getLocStart());
+ // FIXME: This is bogus, a noexcept expression is not a condition.
+ NoexceptExpr = getSema().CheckBooleanCondition(Loc, NoexceptExpr.get());
if (NoexceptExpr.isInvalid())
return true;
@@ -5918,7 +6062,6 @@ TreeTransform<Derived>::TransformObjCObjectType(TypeLocBuilder &TLB,
}
ObjCObjectTypeLoc NewT = TLB.push<ObjCObjectTypeLoc>(Result);
- assert(TL.hasBaseTypeAsWritten() && "Can't be dependent");
NewT.setHasBaseTypeAsWritten(true);
NewT.setTypeArgsLAngleLoc(TL.getTypeArgsLAngleLoc());
for (unsigned i = 0, n = TL.getNumTypeArgs(); i != n; ++i)
@@ -6123,85 +6266,73 @@ StmtResult TreeTransform<Derived>::TransformAttributedStmt(AttributedStmt *S) {
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformIfStmt(IfStmt *S) {
- // Transform the condition
- ExprResult Cond;
- VarDecl *ConditionVar = nullptr;
- if (S->getConditionVariable()) {
- ConditionVar
- = cast_or_null<VarDecl>(
- getDerived().TransformDefinition(
- S->getConditionVariable()->getLocation(),
- S->getConditionVariable()));
- if (!ConditionVar)
- return StmtError();
- } else {
- Cond = getDerived().TransformExpr(S->getCond());
-
- if (Cond.isInvalid())
- return StmtError();
-
- // Convert the condition to a boolean value.
- if (S->getCond()) {
- ExprResult CondE = getSema().ActOnBooleanCondition(nullptr, S->getIfLoc(),
- Cond.get());
- if (CondE.isInvalid())
- return StmtError();
-
- Cond = CondE.get();
- }
- }
+ // Transform the initialization statement
+ StmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return StmtError();
- Sema::FullExprArg FullCond(getSema().MakeFullExpr(Cond.get(), S->getIfLoc()));
- if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
+ // Transform the condition
+ Sema::ConditionResult Cond = getDerived().TransformCondition(
+ S->getIfLoc(), S->getConditionVariable(), S->getCond(),
+ S->isConstexpr() ? Sema::ConditionKind::ConstexprIf
+ : Sema::ConditionKind::Boolean);
+ if (Cond.isInvalid())
return StmtError();
+ // If this is a constexpr if, determine which arm we should instantiate.
+ llvm::Optional<bool> ConstexprConditionValue;
+ if (S->isConstexpr())
+ ConstexprConditionValue = Cond.getKnownValue();
+
// Transform the "then" branch.
- StmtResult Then = getDerived().TransformStmt(S->getThen());
- if (Then.isInvalid())
- return StmtError();
+ StmtResult Then;
+ if (!ConstexprConditionValue || *ConstexprConditionValue) {
+ Then = getDerived().TransformStmt(S->getThen());
+ if (Then.isInvalid())
+ return StmtError();
+ } else {
+ Then = new (getSema().Context) NullStmt(S->getThen()->getLocStart());
+ }
// Transform the "else" branch.
- StmtResult Else = getDerived().TransformStmt(S->getElse());
- if (Else.isInvalid())
- return StmtError();
+ StmtResult Else;
+ if (!ConstexprConditionValue || !*ConstexprConditionValue) {
+ Else = getDerived().TransformStmt(S->getElse());
+ if (Else.isInvalid())
+ return StmtError();
+ }
if (!getDerived().AlwaysRebuild() &&
- FullCond.get() == S->getCond() &&
- ConditionVar == S->getConditionVariable() &&
+ Init.get() == S->getInit() &&
+ Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
Then.get() == S->getThen() &&
Else.get() == S->getElse())
return S;
- return getDerived().RebuildIfStmt(S->getIfLoc(), FullCond, ConditionVar,
- Then.get(),
- S->getElseLoc(), Else.get());
+ return getDerived().RebuildIfStmt(S->getIfLoc(), S->isConstexpr(), Cond,
+ Init.get(), Then.get(), S->getElseLoc(),
+ Else.get());
}
template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformSwitchStmt(SwitchStmt *S) {
- // Transform the condition.
- ExprResult Cond;
- VarDecl *ConditionVar = nullptr;
- if (S->getConditionVariable()) {
- ConditionVar
- = cast_or_null<VarDecl>(
- getDerived().TransformDefinition(
- S->getConditionVariable()->getLocation(),
- S->getConditionVariable()));
- if (!ConditionVar)
- return StmtError();
- } else {
- Cond = getDerived().TransformExpr(S->getCond());
+ // Transform the initialization statement
+ StmtResult Init = getDerived().TransformStmt(S->getInit());
+ if (Init.isInvalid())
+ return StmtError();
- if (Cond.isInvalid())
- return StmtError();
- }
+ // Transform the condition.
+ Sema::ConditionResult Cond = getDerived().TransformCondition(
+ S->getSwitchLoc(), S->getConditionVariable(), S->getCond(),
+ Sema::ConditionKind::Switch);
+ if (Cond.isInvalid())
+ return StmtError();
// Rebuild the switch statement.
StmtResult Switch
- = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(), Cond.get(),
- ConditionVar);
+ = getDerived().RebuildSwitchStmtStart(S->getSwitchLoc(),
+ S->getInit(), Cond);
if (Switch.isInvalid())
return StmtError();
@@ -6219,36 +6350,10 @@ template<typename Derived>
StmtResult
TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
// Transform the condition
- ExprResult Cond;
- VarDecl *ConditionVar = nullptr;
- if (S->getConditionVariable()) {
- ConditionVar
- = cast_or_null<VarDecl>(
- getDerived().TransformDefinition(
- S->getConditionVariable()->getLocation(),
- S->getConditionVariable()));
- if (!ConditionVar)
- return StmtError();
- } else {
- Cond = getDerived().TransformExpr(S->getCond());
-
- if (Cond.isInvalid())
- return StmtError();
-
- if (S->getCond()) {
- // Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(nullptr,
- S->getWhileLoc(),
- Cond.get());
- if (CondE.isInvalid())
- return StmtError();
- Cond = CondE;
- }
- }
-
- Sema::FullExprArg FullCond(
- getSema().MakeFullExpr(Cond.get(), S->getWhileLoc()));
- if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
+ Sema::ConditionResult Cond = getDerived().TransformCondition(
+ S->getWhileLoc(), S->getConditionVariable(), S->getCond(),
+ Sema::ConditionKind::Boolean);
+ if (Cond.isInvalid())
return StmtError();
// Transform the body
@@ -6257,13 +6362,11 @@ TreeTransform<Derived>::TransformWhileStmt(WhileStmt *S) {
return StmtError();
if (!getDerived().AlwaysRebuild() &&
- FullCond.get() == S->getCond() &&
- ConditionVar == S->getConditionVariable() &&
+ Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
Body.get() == S->getBody())
return Owned(S);
- return getDerived().RebuildWhileStmt(S->getWhileLoc(), FullCond,
- ConditionVar, Body.get());
+ return getDerived().RebuildWhileStmt(S->getWhileLoc(), Cond, Body.get());
}
template<typename Derived>
@@ -6303,37 +6406,10 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
getSema().ActOnOpenMPLoopInitialization(S->getForLoc(), Init.get());
// Transform the condition
- ExprResult Cond;
- VarDecl *ConditionVar = nullptr;
- if (S->getConditionVariable()) {
- ConditionVar
- = cast_or_null<VarDecl>(
- getDerived().TransformDefinition(
- S->getConditionVariable()->getLocation(),
- S->getConditionVariable()));
- if (!ConditionVar)
- return StmtError();
- } else {
- Cond = getDerived().TransformExpr(S->getCond());
-
- if (Cond.isInvalid())
- return StmtError();
-
- if (S->getCond()) {
- // Convert the condition to a boolean value.
- ExprResult CondE = getSema().ActOnBooleanCondition(nullptr,
- S->getForLoc(),
- Cond.get());
- if (CondE.isInvalid())
- return StmtError();
-
- Cond = CondE.get();
- }
- }
-
- Sema::FullExprArg FullCond(
- getSema().MakeFullExpr(Cond.get(), S->getForLoc()));
- if (!S->getConditionVariable() && S->getCond() && !FullCond.get())
+ Sema::ConditionResult Cond = getDerived().TransformCondition(
+ S->getForLoc(), S->getConditionVariable(), S->getCond(),
+ Sema::ConditionKind::Boolean);
+ if (Cond.isInvalid())
return StmtError();
// Transform the increment
@@ -6352,14 +6428,14 @@ TreeTransform<Derived>::TransformForStmt(ForStmt *S) {
if (!getDerived().AlwaysRebuild() &&
Init.get() == S->getInit() &&
- FullCond.get() == S->getCond() &&
+ Cond.get() == std::make_pair(S->getConditionVariable(), S->getCond()) &&
Inc.get() == S->getInc() &&
Body.get() == S->getBody())
return S;
return getDerived().RebuildForStmt(S->getForLoc(), S->getLParenLoc(),
- Init.get(), FullCond, ConditionVar,
- FullInc, S->getRParenLoc(), Body.get());
+ Init.get(), Cond, FullInc,
+ S->getRParenLoc(), Body.get());
}
template<typename Derived>
@@ -6842,15 +6918,18 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
if (Range.isInvalid())
return StmtError();
- StmtResult BeginEnd = getDerived().TransformStmt(S->getBeginEndStmt());
- if (BeginEnd.isInvalid())
+ StmtResult Begin = getDerived().TransformStmt(S->getBeginStmt());
+ if (Begin.isInvalid())
+ return StmtError();
+ StmtResult End = getDerived().TransformStmt(S->getEndStmt());
+ if (End.isInvalid())
return StmtError();
ExprResult Cond = getDerived().TransformExpr(S->getCond());
if (Cond.isInvalid())
return StmtError();
if (Cond.get())
- Cond = SemaRef.CheckBooleanCondition(Cond.get(), S->getColonLoc());
+ Cond = SemaRef.CheckBooleanCondition(S->getColonLoc(), Cond.get());
if (Cond.isInvalid())
return StmtError();
if (Cond.get())
@@ -6869,14 +6948,16 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
StmtResult NewStmt = S;
if (getDerived().AlwaysRebuild() ||
Range.get() != S->getRangeStmt() ||
- BeginEnd.get() != S->getBeginEndStmt() ||
+ Begin.get() != S->getBeginStmt() ||
+ End.get() != S->getEndStmt() ||
Cond.get() != S->getCond() ||
Inc.get() != S->getInc() ||
LoopVar.get() != S->getLoopVarStmt()) {
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
- BeginEnd.get(), Cond.get(),
+ Begin.get(), End.get(),
+ Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
if (NewStmt.isInvalid())
@@ -6893,7 +6974,8 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
NewStmt = getDerived().RebuildCXXForRangeStmt(S->getForLoc(),
S->getCoawaitLoc(),
S->getColonLoc(), Range.get(),
- BeginEnd.get(), Cond.get(),
+ Begin.get(), End.get(),
+ Cond.get(),
Inc.get(), LoopVar.get(),
S->getRParenLoc());
if (NewStmt.isInvalid())
@@ -7378,6 +7460,61 @@ StmtResult TreeTransform<Derived>::TransformOMPTargetDataDirective(
}
template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetEnterDataDirective(
+ OMPTargetEnterDataDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_enter_data, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetExitDataDirective(
+ OMPTargetExitDataDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_exit_data, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetParallelDirective(
+ OMPTargetParallelDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetParallelForDirective(
+ OMPTargetParallelForDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_for, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetUpdateDirective(
+ OMPTargetUpdateDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_update, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
StmtResult
TreeTransform<Derived>::TransformOMPTeamsDirective(OMPTeamsDirective *D) {
DeclarationNameInfo DirName;
@@ -7443,6 +7580,52 @@ StmtResult TreeTransform<Derived>::TransformOMPDistributeDirective(
return Res;
}
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPDistributeParallelForDirective(
+ OMPDistributeParallelForDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_distribute_parallel_for, DirName, nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult
+TreeTransform<Derived>::TransformOMPDistributeParallelForSimdDirective(
+ OMPDistributeParallelForSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(
+ OMPD_distribute_parallel_for_simd, DirName, nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPDistributeSimdDirective(
+ OMPDistributeSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_distribute_simd, DirName,
+ nullptr, D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
+template <typename Derived>
+StmtResult TreeTransform<Derived>::TransformOMPTargetParallelForSimdDirective(
+ OMPTargetParallelForSimdDirective *D) {
+ DeclarationNameInfo DirName;
+ getDerived().getSema().StartOpenMPDSABlock(OMPD_target_parallel_for_simd,
+ DirName, nullptr,
+ D->getLocStart());
+ StmtResult Res = getDerived().TransformOMPExecutableDirective(D);
+ getDerived().getSema().EndOpenMPDSABlock(Res.get());
+ return Res;
+}
+
//===----------------------------------------------------------------------===//
// OpenMP clause transformation
//===----------------------------------------------------------------------===//
@@ -7701,9 +7884,31 @@ TreeTransform<Derived>::TransformOMPReductionClause(OMPReductionClause *C) {
if (!NameInfo.getName())
return nullptr;
}
+ // Build a list of all UDR decls with the same names ranged by the Scopes.
+ // The Scope boundary is a duplication of the previous decl.
+ llvm::SmallVector<Expr *, 16> UnresolvedReductions;
+ for (auto *E : C->reduction_ops()) {
+ // Transform all the decls.
+ if (E) {
+ auto *ULE = cast<UnresolvedLookupExpr>(E);
+ UnresolvedSet<8> Decls;
+ for (auto *D : ULE->decls()) {
+ NamedDecl *InstD =
+ cast<NamedDecl>(getDerived().TransformDecl(E->getExprLoc(), D));
+ Decls.addDecl(InstD, InstD->getAccess());
+ }
+ UnresolvedReductions.push_back(
+ UnresolvedLookupExpr::Create(
+ SemaRef.Context, /*NamingClass=*/nullptr,
+ ReductionIdScopeSpec.getWithLocInContext(SemaRef.Context),
+ NameInfo, /*ADL=*/true, ULE->isOverloaded(),
+ Decls.begin(), Decls.end()));
+ } else
+ UnresolvedReductions.push_back(nullptr);
+ }
return getDerived().RebuildOMPReductionClause(
Vars, C->getLocStart(), C->getLParenLoc(), C->getColonLoc(),
- C->getLocEnd(), ReductionIdScopeSpec, NameInfo);
+ C->getLocEnd(), ReductionIdScopeSpec, NameInfo, UnresolvedReductions);
}
template <typename Derived>
@@ -7825,9 +8030,9 @@ OMPClause *TreeTransform<Derived>::TransformOMPMapClause(OMPMapClause *C) {
Vars.push_back(EVar.get());
}
return getDerived().RebuildOMPMapClause(
- C->getMapTypeModifier(), C->getMapType(), C->getMapLoc(),
- C->getColonLoc(), Vars, C->getLocStart(), C->getLParenLoc(),
- C->getLocEnd());
+ C->getMapTypeModifier(), C->getMapType(), C->isImplicitMapType(),
+ C->getMapLoc(), C->getColonLoc(), Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
}
template <typename Derived>
@@ -7889,6 +8094,81 @@ OMPClause *TreeTransform<Derived>::TransformOMPHintClause(OMPHintClause *C) {
C->getLParenLoc(), C->getLocEnd());
}
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPDistScheduleClause(
+ OMPDistScheduleClause *C) {
+ ExprResult E = getDerived().TransformExpr(C->getChunkSize());
+ if (E.isInvalid())
+ return nullptr;
+ return getDerived().RebuildOMPDistScheduleClause(
+ C->getDistScheduleKind(), E.get(), C->getLocStart(), C->getLParenLoc(),
+ C->getDistScheduleKindLoc(), C->getCommaLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPDefaultmapClause(OMPDefaultmapClause *C) {
+ return C;
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPToClause(OMPToClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPToClause(Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPFromClause(OMPFromClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return 0;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPFromClause(Vars, C->getLocStart(),
+ C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *TreeTransform<Derived>::TransformOMPUseDevicePtrClause(
+ OMPUseDevicePtrClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPUseDevicePtrClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
+template <typename Derived>
+OMPClause *
+TreeTransform<Derived>::TransformOMPIsDevicePtrClause(OMPIsDevicePtrClause *C) {
+ llvm::SmallVector<Expr *, 16> Vars;
+ Vars.reserve(C->varlist_size());
+ for (auto *VE : C->varlists()) {
+ ExprResult EVar = getDerived().TransformExpr(cast<Expr>(VE));
+ if (EVar.isInvalid())
+ return nullptr;
+ Vars.push_back(EVar.get());
+ }
+ return getDerived().RebuildOMPIsDevicePtrClause(
+ Vars, C->getLocStart(), C->getLParenLoc(), C->getLocEnd());
+}
+
//===----------------------------------------------------------------------===//
// Expression transformation
//===----------------------------------------------------------------------===//
@@ -8581,46 +8861,44 @@ TreeTransform<Derived>::TransformDesignatedInitExpr(DesignatedInitExpr *E) {
// transform the designators.
SmallVector<Expr*, 4> ArrayExprs;
bool ExprChanged = false;
- for (DesignatedInitExpr::designators_iterator D = E->designators_begin(),
- DEnd = E->designators_end();
- D != DEnd; ++D) {
- if (D->isFieldDesignator()) {
- Desig.AddDesignator(Designator::getField(D->getFieldName(),
- D->getDotLoc(),
- D->getFieldLoc()));
+ for (const DesignatedInitExpr::Designator &D : E->designators()) {
+ if (D.isFieldDesignator()) {
+ Desig.AddDesignator(Designator::getField(D.getFieldName(),
+ D.getDotLoc(),
+ D.getFieldLoc()));
continue;
}
- if (D->isArrayDesignator()) {
- ExprResult Index = getDerived().TransformExpr(E->getArrayIndex(*D));
+ if (D.isArrayDesignator()) {
+ ExprResult Index = getDerived().TransformExpr(E->getArrayIndex(D));
if (Index.isInvalid())
return ExprError();
- Desig.AddDesignator(Designator::getArray(Index.get(),
- D->getLBracketLoc()));
+ Desig.AddDesignator(
+ Designator::getArray(Index.get(), D.getLBracketLoc()));
- ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(*D);
+ ExprChanged = ExprChanged || Init.get() != E->getArrayIndex(D);
ArrayExprs.push_back(Index.get());
continue;
}
- assert(D->isArrayRangeDesignator() && "New kind of designator?");
+ assert(D.isArrayRangeDesignator() && "New kind of designator?");
ExprResult Start
- = getDerived().TransformExpr(E->getArrayRangeStart(*D));
+ = getDerived().TransformExpr(E->getArrayRangeStart(D));
if (Start.isInvalid())
return ExprError();
- ExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(*D));
+ ExprResult End = getDerived().TransformExpr(E->getArrayRangeEnd(D));
if (End.isInvalid())
return ExprError();
Desig.AddDesignator(Designator::getArrayRange(Start.get(),
End.get(),
- D->getLBracketLoc(),
- D->getEllipsisLoc()));
+ D.getLBracketLoc(),
+ D.getEllipsisLoc()));
- ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(*D) ||
- End.get() != E->getArrayRangeEnd(*D);
+ ExprChanged = ExprChanged || Start.get() != E->getArrayRangeStart(D) ||
+ End.get() != E->getArrayRangeEnd(D);
ArrayExprs.push_back(Start.get());
ArrayExprs.push_back(End.get());
@@ -9768,8 +10046,8 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
}
return getDerived().RebuildCXXConstructExpr(T, /*FIXME:*/E->getLocStart(),
- Constructor, E->isElidable(),
- Args,
+ Constructor,
+ E->isElidable(), Args,
E->hadMultipleCandidates(),
E->isListInitialization(),
E->isStdInitListInitialization(),
@@ -9778,6 +10056,32 @@ TreeTransform<Derived>::TransformCXXConstructExpr(CXXConstructExpr *E) {
E->getParenOrBraceRange());
}
+template<typename Derived>
+ExprResult TreeTransform<Derived>::TransformCXXInheritedCtorInitExpr(
+ CXXInheritedCtorInitExpr *E) {
+ QualType T = getDerived().TransformType(E->getType());
+ if (T.isNull())
+ return ExprError();
+
+ CXXConstructorDecl *Constructor = cast_or_null<CXXConstructorDecl>(
+ getDerived().TransformDecl(E->getLocStart(), E->getConstructor()));
+ if (!Constructor)
+ return ExprError();
+
+ if (!getDerived().AlwaysRebuild() &&
+ T == E->getType() &&
+ Constructor == E->getConstructor()) {
+ // Mark the constructor as referenced.
+ // FIXME: Instantiation-specific
+ SemaRef.MarkFunctionReferenced(E->getLocStart(), Constructor);
+ return E;
+ }
+
+ return getDerived().RebuildCXXInheritedCtorInitExpr(
+ T, E->getLocation(), Constructor,
+ E->constructsVBase(), E->inheritedFromVBase());
+}
+
/// \brief Transform a C++ temporary-binding expression.
///
/// Since CXXBindTemporaryExpr nodes are implicitly generated, we just
@@ -9918,7 +10222,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
CXXMethodDecl *NewCallOperator = getSema().startLambdaDefinition(
Class, E->getIntroducerRange(), NewCallOpTSI,
E->getCallOperator()->getLocEnd(),
- NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams());
+ NewCallOpTSI->getTypeLoc().castAs<FunctionProtoTypeLoc>().getParams(),
+ E->getCallOperator()->isConstexpr());
+
LSI->CallOperator = NewCallOperator;
getDerived().transformAttrs(E->getCallOperator(), NewCallOperator);
@@ -9953,7 +10259,9 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
// Capturing 'this' is trivial.
if (C->capturesThis()) {
- getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit());
+ getSema().CheckCXXThisCapture(C->getLocation(), C->isExplicit(),
+ /*BuildAndDiagnose*/ true, nullptr,
+ C->getCaptureKind() == LCK_StarThis);
continue;
}
// Captured expression will be recaptured during captured variables
@@ -10804,6 +11112,12 @@ TransformObjCBridgedCastExpr(ObjCBridgedCastExpr *E) {
Result.get());
}
+template <typename Derived>
+ExprResult TreeTransform<Derived>::TransformObjCAvailabilityCheckExpr(
+ ObjCAvailabilityCheckExpr *E) {
+ return E;
+}
+
template<typename Derived>
ExprResult
TreeTransform<Derived>::TransformObjCMessageExpr(ObjCMessageExpr *E) {
@@ -11039,22 +11353,26 @@ TreeTransform<Derived>::TransformBlockExpr(BlockExpr *E) {
SmallVector<ParmVarDecl*, 4> params;
SmallVector<QualType, 4> paramTypes;
+ const FunctionProtoType *exprFunctionType = E->getFunctionType();
+
// Parameter substitution.
- if (getDerived().TransformFunctionTypeParams(E->getCaretLocation(),
- oldBlock->param_begin(),
- oldBlock->param_size(),
- nullptr, paramTypes, &params)) {
+ Sema::ExtParameterInfoBuilder extParamInfos;
+ if (getDerived().TransformFunctionTypeParams(
+ E->getCaretLocation(), oldBlock->parameters(), nullptr,
+ exprFunctionType->getExtParameterInfosOrNull(), paramTypes, &params,
+ extParamInfos)) {
getSema().ActOnBlockError(E->getCaretLocation(), /*Scope=*/nullptr);
return ExprError();
}
- const FunctionProtoType *exprFunctionType = E->getFunctionType();
QualType exprResultType =
getDerived().TransformType(exprFunctionType->getReturnType());
+ auto epi = exprFunctionType->getExtProtoInfo();
+ epi.ExtParameterInfos = extParamInfos.getPointerOrNull(paramTypes.size());
+
QualType functionType =
- getDerived().RebuildFunctionProtoType(exprResultType, paramTypes,
- exprFunctionType->getExtProtoInfo());
+ getDerived().RebuildFunctionProtoType(exprResultType, paramTypes, epi);
blockScope->FunctionType = functionType;
// Set the parameters on the block decl.
diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp
index be995400df6d..340b7fae78aa 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp
+++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.cpp
@@ -115,11 +115,39 @@ TypeLoc TypeLocBuilder::pushImpl(QualType T, size_t LocalSize, unsigned LocalAli
NumBytesAtAlign4 += LocalSize;
}
} else if (LocalAlignment == 8) {
- if (!NumBytesAtAlign8 && NumBytesAtAlign4 % 8 != 0) {
- // No existing padding and misaligned members; add in 4 bytes padding
- memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
- Index -= 4;
+ if (NumBytesAtAlign8 == 0) {
+ // We have not seen any 8-byte aligned element yet. We insert a padding
+ // only if the new Index is not 8-byte-aligned.
+ if ((Index - LocalSize) % 8 != 0) {
+ memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
+ Index -= 4;
+ }
+ } else {
+ unsigned Padding = NumBytesAtAlign4 % 8;
+ if (Padding == 0) {
+ if (LocalSize % 8 == 0) {
+ // Everything is set: there's no padding and we don't need to add
+ // any.
+ } else {
+ assert(LocalSize % 8 == 4);
+ // No existing padding; add in 4 bytes padding
+ memmove(&Buffer[Index - 4], &Buffer[Index], NumBytesAtAlign4);
+ Index -= 4;
+ }
+ } else {
+ assert(Padding == 4);
+ if (LocalSize % 8 == 0) {
+ // Everything is set: there's 4 bytes padding and we don't need
+ // to add any.
+ } else {
+ assert(LocalSize % 8 == 4);
+ // There are 4 bytes padding, but we don't need any; remove it.
+ memmove(&Buffer[Index + 4], &Buffer[Index], NumBytesAtAlign4);
+ Index += 4;
+ }
+ }
}
+
// Forget about any padding.
NumBytesAtAlign4 = 0;
NumBytesAtAlign8 += LocalSize;
diff --git a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h
index 82844b391467..382821859768 100644
--- a/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h
+++ b/contrib/llvm/tools/clang/lib/Sema/TypeLocBuilder.h
@@ -7,7 +7,7 @@
//
//===----------------------------------------------------------------------===//
//
-// This files defines TypeLocBuilder, a class for building TypeLocs
+// This file defines TypeLocBuilder, a class for building TypeLocs
// bottom-up.
//
//===----------------------------------------------------------------------===//